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

时间:2017-06-27 06:34:25

标签: 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'中读取了addr值存储。和+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'并得出不同的结果?
非常感谢你。

3 个答案:

答案 0 :(得分:5)

  

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

不,你错了。 lea edx, [rax+1]不会更改rax。 <{1}}在评估rax指令之前已3

  

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

不,你错了。 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 时,您也会写入eax的下半部分(上半部分归零)。

所以,

rax

答案 1 :(得分:1)

pq是您int的指针,平台上int的大小 4 。因此,递增p实际上会将其值增加 4

int *q = p++;

   mov     rax, QWORD PTR [rbp-8]     ; rax = p
   lea     rdx, [rax+4]               ; same as rdx = rax + 4
   mov     QWORD PTR [rbp-8], rdx     ; p = rdx
   mov     QWORD PTR [rbp-24], rax    ; q = rax

cint。因此,递增a实际上只是将其值增加 1

c = a++;

   mov     eax, DWORD PTR [rbp-40]    ; rax = a (yes modifying eax actually modifies rax)
   lea     edx, [rax+1]               ; same as edx = rax + 1
   mov     DWORD PTR [rbp-40], edx    ; a = edx
   mov     DWORD PTR [rbp-28], eax    ; c = eax (eax still contains the inital value of a)

More details about the LEA instructions here

答案 2 :(得分:-1)

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

注意: int的大小可能因编译器而异。但是根据基于GCC的编译器,在您的情况下,int长度为4个字节