c - 未定义表达式的汇编程序调试

标签 c assembly undefined x86-64

我试图更好地理解编译器如何为 undefined 表达式生成代码,例如对于以下代码:

int main()
{
    int i = 5;
    i = i++;
    return 0;
}

这是 gcc 4.8.2 生成的汇编代码(优化关闭 -O0,我插入了自己的行号以供引用):

(gdb) disassemble main
Dump of assembler code for function main:
(1) 0x0000000000000000 <+0>:    push   %rbp
(2) 0x0000000000000001 <+1>:    mov    %rsp,%rbp
(3) 0x0000000000000004 <+4>:    movl   $0x5,-0x4(%rbp)
(4) 0x000000000000000b <+11>:   mov    -0x4(%rbp),%eax
(5) 0x000000000000000e <+14>:   lea    0x1(%rax),%edx
(6) 0x0000000000000011 <+17>:   mov    %edx,-0x4(%rbp)
(7) 0x0000000000000014 <+20>:   mov    %eax,-0x4(%rbp)
(8) 0x0000000000000017 <+23>:   mov    $0x0,%eax
(9) 0x000000000000001c <+28>:   pop    %rbp
(10) 0x000000000000001d <+29>:  retq   
End of assembler dump.

执行此代码会产生 i 的值剩余值为 5(使用 printf() 语句验证)即 i似乎永远不会增加。我知道不同的编译器会以不同的方式评估/编译未定义的表达式,这可能只是 gcc 的方式,即我可以用不同的编译器得到不同的结果。

关于汇编代码,据我了解:

忽略行 - 1-2 设置堆栈/基指针等。 第 3/4 行 - 5 的值是如何分配给 i 的.

谁能解释第 5-6 行发生了什么?看起来好像 i将最终重新分配 5 的值(第 7 行),但是增量操作(后增量操作所需 i++ )是否只是被编译器在这种情况下放弃/跳过?

最佳答案

这三行包含你的答案:

lea    0x1(%rax),%edx
mov    %edx,-0x4(%rbp)
mov    %eax,-0x4(%rbp)

不会跳过增量操作。 lea 是增量,从%rax 中获取值并将增量值存储在%edx 中。 %edx 被存储,但随后被使用 %eax 中的原始值的下一行覆盖。

理解此代码的关键是了解 lea 的工作原理。它代表load effective address ,所以虽然它看起来像一个指针取消引用,但它实际上只是进行数学运算以获取 [whatever] 的最终地址,然后保留该地址,而不是 该地址的值。这意味着它可以用于任何可以使用寻址模式有效表达的数学表达式,作为数学操作码的替代方法。出于这个原因,它经常被用作获得乘法和添加到单个指令中的方法。特别是,在这种情况下,它用于在一条指令中增加值并将结果移动到不同的寄存器,其中 inc 会就地覆盖它。

关于c - 未定义表达式的汇编程序调试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30545954/

相关文章:

c - 在 C 中使用 char 数组填充结构

c - int *ptr= 5 怎么做;与 int *ptr= 变量地址不同?

汇编语言 - 不止一种类型?

从 C 调用 Mips

php - 通知: Undefined index 'upload'

c - 当所有元素都相同时快速排序复杂度?

android - 是否有任何 Android 函数调用只进行一两个特定的系统调用?

c - 实模式 OS 中的 16 位 .com C 程序

python - 在 if-elif-else 语句中定义值时打印小计?名称错误问题[Python 2.7]

c++ - 从另一个文件调用 C++ 函数时出现 "Undefined Symbols"