I'm compiling the following code:
#include <stdio.h>
#include <stdint.h>
uint32_t fibonacci(uint32_t pos) {
long next = 1, current = 0, tmp;
for (long n = 1; n <= pos; n++) {
tmp = current;
current = next;
next += tmp;
}
return current;
}
int main() {
uint32_t target_pos, result;
scanf("%u", &target_pos);
result = fibonacci(target_pos);
printf("%u\n", result);
return 0;
}
Which results in the following assembly code:
0000000000001189 <fibonacci>:
1189: endbr64
118d: push %rbp
118e: mov %rsp,%rbp
1191: mov %edi,-0x24(%rbp)
1194: movq $0x1,-0x20(%rbp)
119c: movq $0x0,-0x18(%rbp)
11a4: movq $0x1,-0x10(%rbp)
11ac: jmp 11cb <fibonacci+0x42>
11ae: mov -0x18(%rbp),%rax
11b2: mov %rax,-0x8(%rbp)
11b6: mov -0x20(%rbp),%rax
11ba: mov %rax,-0x18(%rbp)
11be: mov -0x8(%rbp),%rax
11c2: add %rax,-0x20(%rbp)
11c6: addq $0x1,-0x10(%rbp)
11cb: mov -0x24(%rbp),%eax
11ce: cmp %rax,-0x10(%rbp)
11d2: jle 11ae <fibonacci+0x25>
11d4: mov -0x18(%rbp),%rax
11d8: pop %rbp
11d9: retq
Now, I did some research and this is what I have:
- The first instruction (endbr64) is security-related [ref], and in my case it will be a NOP
- The instructions 0x118d, 0x118e, 0x11d8 and 0x11d9 are related to the return [ref]
%rbp
is the base of the stack
With that information, we have this diagram:
I've tried to understand it, but some operations are completely nonsense:
%eax
(that for what I've found it's used for returning data) gets saved (not loaded) unchanged%edi
is loaded at the start, and it doesn't change/get queried from that pointThe asm performs a "variable++" on
-0x10(%rbp)
; so you expect that in-0x10(%rbp)
n
, that is the only variable that gets incremented by 1, is stored. But in one instruction%rax
gets compared "less than or equal" with-0x10(%rbp)
(looking at the original C code, I assume that the asm is doingpos <= n
, when it should be the other way)
And like that more and more...
Someone can explain me what the hell is happening? I've compiled the C code with an AMD 3950X without optimizations.