Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assembly lea instruction of int *q = p++ and int c = a++

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

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

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

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

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.

like image 403
ProbHunter Avatar asked Jun 27 '17 06:06

ProbHunter


People also ask

What is Lea assembly instruction?

The lea instruction places the address specified by its first operand into the register specified by its second operand. Note, the contents of the memory location are not loaded, only the effective address is computed and placed into the register.

What is the purpose of LEA instruction in 8086?

LEA − Used to load the address of operand into the provided register. LES − Used to load ES register and other provided register from the memory.

What is the difference between the MOV and LEA instructions?

The lea instruction copies an “effective address” from one place to another. Unlike mov, which copies data at the address src to the destination, lea copies the value of src itself to the destination. The syntax for the destinations is the same as mov. The difference is how it handles the src.

What is Qword PTR?

qword ptr is a hint for the assembler to create a move op-code (machine code) using a 64bit constant address. The value that is provided is a 32bit value (8 hex-digits => 8 times a hex-digit/letter => 8 * 4bits => 32bit).


1 Answers

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

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

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

No, you are mistaken. rax is being set by 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).

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 |
                                         ; +----+----+----+----+  +----+----+----+----+
like image 66
ikegami Avatar answered Sep 28 '22 06:09

ikegami