装配lea指令的int *q = p++和int c = a++。

时间:2022-05-04 03:13:20

In order to deepen the impression about how the " (*p)++ " works, I wrote some test codes like:

为了加深对“(*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);
}

OUTPUT IS: a = 5, b = 3, c = 5, d = 4, p = 0xc6dc3490, q = 0xc6dc348c

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

But my question is about the assembly (codes are in orders and not off and on):

但我的问题是关于程序集(代码是在订单中,而不是断断续续的):

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)

Please pay attention to the "Flagx" lines which make me confused.
From above , we know that
when pointer: int *q = p++ :

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

lea     rdx, [rax+4]    ;Flag3

Here, 'lea' seems to read the addr value store in 'rax' and +4. then pass to 'rdx'.

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

在这里,“lea”似乎在“rax”和+4中读取addr值存储。然后通过“黑索今”。while: int c = a++或int d = c++:

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

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'.

But! the point is that 'rax' in these two statments are the same one. They're all from

在这里,“lea”似乎阅读了“rax”(这里是3)的addr值存储的内容,然后+1,到4,然后传递到“edx”。但是!关键是这两个状态中的“rax”是同一个。他们都从

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

As we can see, they ( Flag3 and Flag4/Flag5 ) look very similar, but they work very differently base on a same 'rax', how come ? Can the 'lea' instruction distinguish between 'rdx' and 'edx / ecx' and turn out different results ?
Thank you very much.

正如我们所看到的,它们(Flag3和Flag4/Flag5)看起来非常相似,但它们在同一个“rax”上的工作方式非常不同,为什么呢?“lea”指令能区分“rdx”和“edx / ecx”,结果会有不同吗?非常感谢。

3 个解决方案

#1


5  

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”似乎阅读了“rax”(这里是3)的addr值存储的内容,然后+1,到4,然后传递到“edx”。

No, you are mistaken. lea edx, [rax+1] doesn't change rax. rax is already 3 before the lea instruction is evaluated.

不,你是错误的。lea edx, [rax+1]不会改变rax。rax在lea指令被评估之前已经是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]

但是!关键是这两个状态中的“rax”是同一个。它们都来自mov rax, QWORD PTR [rbp-8]

No, you are mistaken. rax is being set by mov eax, DWORD PTR [rbp-36].

不,你是错误的。rax是由mov eax, DWORD PTR [rbp-36]设置的。

Different parts of the general purpose registers can be referenced using different names.

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

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

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

This means that when you write to eax, you are also writing to the bottom half of rax (and the top half gets zeroed).

这意味着,当你给eax写信的时候,你也在写到rax的下半部分(上半部分得到了0)。

So,

所以,

                                         ; 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 |
                                         ; +----+----+----+----+  +----+----+----+----+

#2


1  

p and q are pointers to int and the size of an int is 4 on your platform. So incrementing p actually increments its value by 4.

p和q是指向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

c is an int. So incrementing a actually just increments its value by 1.

c是一个整数,所以递增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.

这里是关于LEA指令的更多细节。

#3


-1  

In line int *q = p++ the address pointer is getting incremented. As you know the size of int is 4 bytes and size of int is size of pointer variable, so in assembly code you can see lea rdx, [rax+4].
But in line int c = a++ the value of variable a is getting incremented. So in assembly code you can see lea edx, [rax+1].

在line int *q = p++中,地址指针不断增加。您知道int的大小是4字节,int的大小是指针变量的大小,所以在汇编代码中您可以看到lea rdx, [rax+4]。但是,在直线int c = a++中,变量a的值不断增加。在汇编代码中,可以看到lea edx, [rax+1]。

Note: Size of int may vary from compiler to compiler. But as per GCC based compilers and in your case int is 4 byte long

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

#1


5  

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”似乎阅读了“rax”(这里是3)的addr值存储的内容,然后+1,到4,然后传递到“edx”。

No, you are mistaken. lea edx, [rax+1] doesn't change rax. rax is already 3 before the lea instruction is evaluated.

不,你是错误的。lea edx, [rax+1]不会改变rax。rax在lea指令被评估之前已经是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]

但是!关键是这两个状态中的“rax”是同一个。它们都来自mov rax, QWORD PTR [rbp-8]

No, you are mistaken. rax is being set by mov eax, DWORD PTR [rbp-36].

不,你是错误的。rax是由mov eax, DWORD PTR [rbp-36]设置的。

Different parts of the general purpose registers can be referenced using different names.

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

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

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

This means that when you write to eax, you are also writing to the bottom half of rax (and the top half gets zeroed).

这意味着,当你给eax写信的时候,你也在写到rax的下半部分(上半部分得到了0)。

So,

所以,

                                         ; 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 |
                                         ; +----+----+----+----+  +----+----+----+----+

#2


1  

p and q are pointers to int and the size of an int is 4 on your platform. So incrementing p actually increments its value by 4.

p和q是指向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

c is an int. So incrementing a actually just increments its value by 1.

c是一个整数,所以递增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.

这里是关于LEA指令的更多细节。

#3


-1  

In line int *q = p++ the address pointer is getting incremented. As you know the size of int is 4 bytes and size of int is size of pointer variable, so in assembly code you can see lea rdx, [rax+4].
But in line int c = a++ the value of variable a is getting incremented. So in assembly code you can see lea edx, [rax+1].

在line int *q = p++中,地址指针不断增加。您知道int的大小是4字节,int的大小是指针变量的大小,所以在汇编代码中您可以看到lea rdx, [rax+4]。但是,在直线int c = a++中,变量a的值不断增加。在汇编代码中,可以看到lea edx, [rax+1]。

Note: Size of int may vary from compiler to compiler. But as per GCC based compilers and in your case int is 4 byte long

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