程序集lea指令int*q = p ++和int c = a ++

Pro*_*ter 5 c x86 assembly

为了加深对"(*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);
}
Run Code Online (Sandbox Code Playgroud)

输出为: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)
Run Code Online (Sandbox Code Playgroud)

请注意"Flagx"线让我感到困惑.
从上面,我们知道
当指针: int*q = p ++:

lea     rdx, [rax+4]    ;Flag3
Run Code Online (Sandbox Code Playgroud)

在这里,'lea'似乎在'rax'和+4中读取了addr值存储.然后转到'rdx'.

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

lea     edx, [rax+1]    ;Flag4/Flag5
Run Code Online (Sandbox Code Playgroud)

在这里,'lea'似乎在'rax'(这里是3)中读取addr值存储的内容,而+1,来到4并传递给'edx'.

但!关键是这两个陈述中的' rax '是相同的.他们全都来自

mov     rax, QWORD PTR [rbp-8]   ;Flag2
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,它们(Flag3和Flag4/Flag5)看起来非常相似,但基于相同的'rax'它们的工作方式却截然不同,怎么样?'lea'指令可以区分'rdx'和'edx/ecx'并得出不同的结果吗?
非常感谢你.

ike*_*ami 5

在这里,'lea'似乎在'rax'(这里是3)中读取addr值存储的内容,而+1,来到4并传递给'edx'.

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

但!关键是这两个陈述中的'rax'是相同的.他们全都来自mov rax, QWORD PTR [rbp-8]

不,你错了.rax正在设定mov eax, DWORD PTR [rbp-36].

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

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

     |<------------------------------------->| rax
                         |<----------------->| eax
                                   |<------->|  ax
                                   |<-->|       ah
                                        |<-->|  al
Run Code Online (Sandbox Code Playgroud)

这意味着当你写信时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 |
                                         ; +----+----+----+----+  +----+----+----+----+
Run Code Online (Sandbox Code Playgroud)


cse*_*cse -2

int *q = p++地址指针依次递增。如您所知,int 的大小是 4 个字节,而 int 的大小是指针变量的大小,因此在汇编代码中您可以看到lea rdx, [rax+4]
int c = a++变量的值a会逐渐增加。所以在汇编代码中你可以看到lea edx, [rax+1].

注意:的大小int可能因编译器而异。但根据GCC基于编译器和你的情况int是 4 字节长