-fpatchable-function-entry=N[,M]
Generate N NOPs right at the beginning of each function, with the function entry point before the Mth NOP. If M is omitted, it defaults to 0 so the function entry points to the address just at the first NOP.
也就是说在每个函数的开始处生成N个NOP指令;
举一个简单的例子来描述这个问题:
1.Compile the source file toy_exam.c
$ gcc -o toy_exam.gcc toy_exam.c -g -gdwarf-4 -fpatchable-function-entry=2 -save-temps
2.Check the symbolic address of the function fun_a
$ readelf -s toy_exam.gcc |grep -w fun_a
95: 00000000000007f0 80 FUNC GLOBAL DEFAULT 13 fun_a
objdump -d toy_exam.gcc |grep -A 8 -w \
00000000000007f0
7f0: d503201f nop
7f4: d503201f nop
7f8: a9be7bfd stp x29, x30, [sp, #-32]!
7fc: 910003fd mov x29, sp
800: 52800040 mov w0, #0x2 // #2
804: b90017e0 str w0, [sp, #20]
808: 528000a0 mov w0, #0x5 // #5
80c: b9001be0 str w0, [sp, #24]
4.dump dwarf info
$ llvm-dwarfdump toy_exam.gcc |grep -C 10 -w fun_a
0x00000315: DW_TAG_subprogram
DW_AT_external (true)
DW_AT_name ("fun_a")
DW_AT_decl_file ("/home/jianlin/code/test/toy_exam.c")
DW_AT_decl_line (14)
DW_AT_decl_column (0x06)
DW_AT_low_pc (0x00000000000007f8)
DW_AT_high_pc (0x0000000000000840)
DW_AT_frame_base (DW_OP_call_frame_cfa)
DW_AT_GNU_all_tail_call_sites (true)
DW_AT_sibling (0x0000035d)
5. Assembler code
fun_a:
.section __patchable_function_entries
.8byte .LPFE2
.text
.LPFE2:
nop
nop
.LFB7:
.loc 1 15 1
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
mov x29, sp
.loc 1 16 13
DW_AT_low_pc 比函数入口地址大8个字节,也就是两个NOP指令的空间(arm64上)
若使用clang编译是不会出现这个问题的DW_AT_low_pc和函数entry地址是一致的。
$ clang -o toy_exam.clang toy_exam.c -g -gdwarf-4 -fpatchable-function-entry=2
我已经将这个问题提交到gcc Bugzilla。