Chápu to správně, že pokud se kód dá optimalizovat tak, že se "inljajnují" těla všech funkcí, tak se dá EBP použít pro jiný účel neż uchování stavu rámců? Jak se pak vrátím zpátky z funkce main(), která v programu v Céčku musí být, když jsem ztratil informaci o pointeru na poslední rámec? Nebo se to uloží jako proměnná na stack? A co volání funkcí ze (standardních) knihoven?
16. 12. 2023, 08:34 editováno autorem komentáře
Z main (pokud neni volana rekurentne - C to umoznuje) se "nevracis", na konci (pri pruchodu } nebo return) se vola syscall sys_exit. Pokud se funkce inlinuje, tak se de facto nevola, takze nevznikne novy ramec. Co se deje pri volani funkce je zavisle na architekture a ABI. Na x86 CALL ulozi navratovou adresu na zasobnik. Vsechny ostatni registry jejichz hodnotu chces uchovat si musis explicitne PUSHnout. Proto neni jedinou rezii -fnoomit-frame-pointer zabrani jednoho registru (jak by se zdalo ze zpravicky) ale jeste navic jeden PUSH pri volani a jeden POP pri navratu.
Pardon, ale to není tak úplně pravda. Ani sys_exit() to volat nemůže, ono se tam docela dobře může nacházet docela dost cleanupu. (atexit() např.)
int main() { return 1; }
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400620 <+0>: push rbp
0x0000000000400621 <+1>: mov rbp,rsp
0x0000000000400624 <+4>: mov eax,0x1
0x0000000000400629 <+9>: pop rbp
0x000000000040062a <+10>: ret
End of assembler dump.
resp -O3 -fomit-frame-pointer
(gdb) disass main
Dump of assembler code for function main:
0x00000000004004c0 <+0>: mov eax,0x1
0x00000000004004c5 <+5>: ret
End of assembler dump.