Pointers
Simple Pointers
int increment(int *x) {
(*x)++;
return 1;
}
int caller(int x) {
increment(&x);
return x;
}
We compile this with -O0
which generates the following assembly:
increment:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
lea edx, [rax+1]
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], edx
mov eax, 1
pop rbp
ret
.size increment, .-increment
.globl caller
.type caller, @function
caller:
push rbp
mov rbp, rsp
sub rsp, 8
mov DWORD PTR [rbp-4], edi
lea rax, [rbp-4]
mov rdi, rax
call increment
mov eax, DWORD PTR [rbp-4]
leave
ret
Following the function prologue, the room is made on the stack to place the x
variable with sub rsp, 8
. Because caller()
is not a leaf function, it can't make use of the red zone.
The value of x
is in the edi
register, and it's moved on to the stack with mov DWORD PTR [rbp-4], edi
. The lea rax, [rbp-4]
line 'loads the effective address', so the address rbp - 4
, which is the location of the x
variable, is in the rax
variable. This address is then copied to rdi
, which is register where the first argument to increment()
is stored. increment()
is then called.
In the increment()
function, the address of the variable to be incremented is placed on the stack with mov QWORD PTR [rbp-8], rdi
. This address is then moved into rax
. The mov eax, DWORD PTR [rax]
moves the value that rax
points to into the eax
register. Note here that eax
is the low 32 bits of the rax
register.
The lea edx, [rax+1]
takes the value in the rax
register, adds 1, and loads it into the edx
register. Refer to this StackOverflow discussion as to why lea
is used instead of an add
instruction.
The on the stack at rbp-8
, which is the memory location of x
, is loaded into rax
. Then with the mov DWORD PTR [rax], edx
line the incremented value in edx
is moved into the memory location that rax
contains.
Finally, the return value of 1 is loaded into eax
, the previous base pointer is popped off the stack, and the function returns.
Back in caller()
, the value of x
which is on the stack at rbp-4
is moved into eax
. The leave
instruction performs two tasks:
- A
mov rsp, rbp
to return the stack pointer to the current base pointer. It then per - A
pop rbp
to pop the previous base pointer off the stack and load it intorbp
.
The ret
instruction is called which jumps to the calling function.