Original post is here: eklausmeier.goip.de
How can you detect whether a Linux binary was compiled with
1gcc -fomit-frame-pointer
Unfortunately the ELF itself does not contain a flag, which tells you that. But looking at the assembler code can give you the answer.
First disassemble the code with
1objdump -d
Check the disassembly for below pairs directly after any C function:
push %rbp
mov %rsp,%rbp
These are the instructions to set up the frame pointer on 64 bit Linux x86 systems.
Example:
0000000000001380 <zif_md4c_toHtml>:
1380: 55 push %rbp
1381: 48 89 e5 mov %rsp,%rbp
A good heuristic is then
1objdump -d $binary | grep -c "mov.*%rsp,.*%rbp"
Double check with
1objdump -d $binary | grep -C1 "mov.*%rsp,.*%rbp"
This heuristic is not fool proof, as individual C routines can be augmented with
1__attribute__((optimize("omit-frame-pointer"))
In the intense debate about making -fno-omit-frame-pointer
the default in Fedora, see this comment from L. A. F. Pereira in Python 3.11 performance with frame pointers.
See How can I tell whether a binary is compiled with frame pointers or not on Linux?, which discusses the case for 32 bit x86 Linux systems.
Code with framepointers will always contain the both of the two instructions
push %ebp
andmov %esp, %ebp
. ... For those working with x86_64, the registers to look for are the 64-bit equivalents: %rbp and %rsp - the concept is the same though!
The post The Return of the Frame Pointers by Brendan Gregg triggered this task.
As of today, 18-Mar-2024, Arch Linux still does not ship binaries with frame pointer support. For example:
1$ objdump -d /bin/zsh | grep -c "mov.*%rsp,.*%rbp"
210
The PHP binary fails the heuristic:
1$ objdump -d /bin/php | grep -c "mov.*%rsp,.*%rbp"
2173
But looking at the actuall disassembly shows something like this:
000000000021aff2 <php_info_print_box_end@@Base>:
21aff2: f3 0f 1e fa endbr64
21aff6: 48 8d 05 43 9b 1e 01 lea 0x11e9b43(%rip),%rax # 1404b40 <sapi_module@@Base>
I.e., no frame pointer handling.