3 ms·
This is because of the calling convention / ABI If you write void free_with_extra_args(int *a, int *b) { free(a); } then *a is in already in
by jonathrg 3y ago
This is because of the calling convention / ABI
If you write
void free_with_extra_args(int *a, int *b) {
free(a);
}
then *a is in already in the correct slot (the RDI register) for the first argument when free_with_extra_args is being called. Whatever is put into *b is never touched. If you compile this with gcc -O2 you get
free_with_extra_args:
jmp free
If you make the function call free(b) instead, you'll have to move b into the right place before calling free:
free_with_extra_args:
mov rdi, rsi
jmp free
This is on x86-64 as summarized here https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI https://en.wikipedia.org/wiki/X86_calling_conventions#System...
Wikipedia also has a nice summary of calling conventions on other platforms like ARM. All modern calling conventions are similar: pass the first args in registers and then use the stack as needed https://en.wikipedia.org/wiki/Calling_convention https://en.wikipedia.org/wiki/Calling_convention
- flohofwoe 3y agoThat's only one half of it though, the other interesting part is the jmp (instead of call) to hand over control to a subroutine without pushing a new return address to the stack (since there's no code after the function call, and the calling function doesn't require its own stack frame).
- jonathrg 3y agoIndeed. Typically you have pairs of call and ret, where call creates a stack frame and ret tears it down caller caller | ^ (call) . . . . . . . . . . . . . (ret) | | V | outer_function outer_function | ^ (call) . . . .(ret) | | V | inner_function A jmp does not modify the stack, so when the inner function calls ret it jumps right back to caller caller caller | ^ (call) . . . . . . (ret) | | v | outer_function | | | (jmp) | | | V | inner_function This trick stops working as soon as outer_function needs local variables or does anything other than returning the exact return value of inner_function. In that case you need a stack frame