c - int *q = p++ 和 int c = a++ 的汇编 lea 指令

标签 c assembly x86

为了加深对“(*p)++”是如何工作的印象,我写了一些测试代码如下:

int main()
{
  int  a = 3;
  int *p = &a;
  int b = (*p)++;
  int *q = p++;
  int c = a++;
  int d = c++;
  printf("a = %d, b = %d, c = %d, d = %d, p = %#x, q = %#x\n",a, b, c, d, p, q);
}

输出是:a = 5, b = 3, c = 5, d = 4, p = 0xc6dc3490, q = 0xc6dc348c

但我的问题是关于程序集(代码是按顺序排列的,而不是断断续续的):

main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 48

;int a = 3 :
        mov     DWORD PTR [rbp-36], 3

;int *p = &a :
        lea     rax, [rbp-36]
        mov     QWORD PTR [rbp-8], rax

;int b = (*p)++ :
        mov     rax, QWORD PTR [rbp-8]
        mov     eax, DWORD PTR [rax]
        lea     ecx, [rax+1]               ;Flag1
        mov     rdx, QWORD PTR [rbp-8]
        mov     DWORD PTR [rdx], ecx
        mov     DWORD PTR [rbp-12], eax

;int *q = p++ :
        mov     rax, QWORD PTR [rbp-8]     ;Flag2
        lea     rdx, [rax+4]               ;Flag3
        mov     QWORD PTR [rbp-8], rdx
        mov     QWORD PTR [rbp-24], rax

;int c = a++;
        mov     eax, DWORD PTR [rbp-36]
        lea     edx, [rax+1]               ;Flag4
        mov     DWORD PTR [rbp-36], edx
        mov     DWORD PTR [rbp-28], eax

;int d = c++;
        mov     eax, DWORD PTR [rbp-28]
        lea     edx, [rax+1]               ;Flag5
        mov     DWORD PTR [rbp-28], edx
        mov     DWORD PTR [rbp-32], eax

... ... (ignore some)

请注意让我感到困惑的“Flagx”行。
从上面我们知道
当指针:int *q = p++ :

lea     rdx, [rax+4]    ;Flag3

在这里,“lea”似乎读取了“rax”和 +4 中存储的地址值。然后传递给“rdx”。

while: int c = a++int d = c++ :

lea     edx, [rax+1]    ;Flag4/Flag5

这里'lea'好像读取了'rax'中addr值存储的内容(这里是3),+1,得出4,传给'edx'。

但是!关键是这两个语句中的“rax”是同一个。他们都来自

mov     rax, QWORD PTR [rbp-8]   ;Flag2

正如我们所见,它们(Flag3 和 Flag4/Flag5)看起来非常相似,但基于相同的“rax”,它们的工作方式却截然不同,这是怎么回事? “lea”指令能否区分“rdx”和“edx/ecx”并得出不同的结果?
非常感谢。

最佳答案

Here, 'lea' seems to read the content of the addr value store in 'rax' (which is 3 here), and +1, come to 4 and pass to 'edx'.

不,你错了。 lea edx, [rax+1] 不会改变 rax。在评估 lea 指令之前,rax 已经是 3

But! the point is that 'rax' in these two statments are the same one. They're all from mov rax, QWORD PTR [rbp-8]

不,你错了。 raxmov eax, DWORD PTR [rbp-36] 设置。

通用寄存器的不同部分可以使用不同的名称来引用。

   64                  32        16    8    0
    |                   |         |    |    |
    v                   v         v    v    v
     +----+----+----+----+----+----+----+----+
     |    |    |    |    |    |    |    |    |
     +----+----+----+----+----+----+----+----+

     |<------------------------------------->| rax
                         |<----------------->| eax
                                   |<------->|  ax
                                   |<-->|       ah
                                        |<-->|  al

这意味着当您写入 eax 时,您也在写入 rax 的下半部分(并且上半部分归零)。

所以,

                                         ; rax       eax          rdx       edx
; q = p++                                ; +----+----+----+----+  +----+----+----+----+
A1      mov     rax, QWORD PTR [rbp-8]   ; |                 p |  |               ??? |
A2      lea     rdx, [rax+4]             ; |                 p |  |               p+4 |
A3      mov     QWORD PTR [rbp-8], rdx   ; |                 p |  |               p+4 |
A4      mov     QWORD PTR [rbp-24], rax  ; |                 p |  |               p+4 |
; c = a++                                ; |                 p |  |               p+4 |
B1      mov     eax, DWORD PTR [rbp-40]  ; |       0 |       a |  |               p+4 |
B2      lea     edx, [rax+1]             ; |       0 |       a |  |       0 |     a+1 |
B3      mov     DWORD PTR [rbp-40], edx  ; |       0 |       a |  |       0 |     a+1 |
B4      mov     DWORD PTR [rbp-28], eax  ; |       0 |       a |  |       0 |     a+1 |
                                         ; +----+----+----+----+  +----+----+----+----+

关于c - int *q = p++ 和 int c = a++ 的汇编 lea 指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44773658/

相关文章:

assembly - .设置标签,.对比。标签 : GNU AS

c - 阅读 x86 汇编代码

c - 什么是CPUID标准函数01H?

c++ - 方法调用后返回值是否总是进入 eax 寄存器?

c - VC++ 2010 中的内联汇编错误

c - 将返回的 cstring 分配给变量

assembly - 通过bios中断获取要打印的字符串

c++ - 插件系统如何工作?

c - 转换为 Apple 事件 AppleScript

您可以使用 Arduino Uno(c 代码)同时多次运行一个函数吗?