, 2 min read
Is Binary Compiled with Frame Pointer Support?
How can you detect whether a Linux binary was compiled with
gcc -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
objdump -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
objdump -d $binary | grep -c "mov.*%rsp,.*%rbp"
Double check with
objdump -d $binary | grep -C1 "mov.*%rsp,.*%rbp"
This heuristic is not fool proof, as individual C routines can be augmented with
__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:
$ objdump -d /bin/zsh | grep -c "mov.*%rsp,.*%rbp"
10
The PHP binary fails the heuristic:
$ objdump -d /bin/php | grep -c "mov.*%rsp,.*%rbp"
173
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.