3

我有一个 ARM 二进制文件,我需要准确地找到它的函数序言结束和结语开始的地址。换句话说,我需要功能体的边界。例如,如果我有一个函数,其程序集类似于:

0x00000320 <+0>:    push    {r7, lr}
0x00000322 <+2>:    sub sp, #16
0x00000324 <+4>:    add r7, sp, #0
0x00000326 <+6>:    str r0, [r7, #4]
0x00000328 <+8>: (Function body starts here)
...
0x0000034c <+44>:   (Function body ends here)
0x0000034e <+46>:   mov sp, r7
0x00000350 <+48>:   pop {r7, pc}

我需要一种方法来使用 readelf 或 objdump 之类的东西快速找到0x00000326and 0x0000034e(prologue end/epilogue start) 或0x00000328and (function body start/end)。0x0000034c简单地反汇编它并检查代码是行不通的(理想情况下,我会使用脚本来解析 readelf 的输出或我用来获取 DWARF 信息的任何程序)。

根据 DWARF 4 标准,.debug_line 部分应该有行号信息,其中包括“ prologue_end”和“ epilogue_begin”,这正是我所需要的。但是,输出arm-linux-readelf --debug-dump=rawline,decodedline并没有给我那个信息。

我正在使用gcc 4.8.2标志-ggdb3进行编译。

编辑:更多信息:objdump 和 readelf 都向我展示了这样的内容:

Line Number Statements:
[0x00000074]  Extended opcode 2: set Address to 0x100
[0x0000007b]  Advance Line by 302 to 303
[0x0000007e]  Copy
[0x0000007f]  Special opcode 34: advance Address by 4 to 0x104 and Line by 1 to 304
[0x00000080]  Special opcode 34: advance Address by 4 to 0x108 and Line by 1 to 305
[0x00000081]  Special opcode 37: advance Address by 4 to 0x10c and Line by 4 to 309
[0x00000082]  Special opcode 34: advance Address by 4 to 0x110 and Line by 1 to 310
[0x00000083]  Special opcode 20: advance Address by 2 to 0x112 and Line by 1 to 311
[0x00000084]  Special opcode 37: advance Address by 4 to 0x116 and Line by 4 to 315
[0x00000085]  Special opcode 34: advance Address by 4 to 0x11a and Line by 1 to 316
[0x00000086]  Advance Line by -13 to 303
[0x00000088]  Special opcode 19: advance Address by 2 to 0x11c and Line by 0 to 303
[0x00000089]  Special opcode 34: advance Address by 4 to 0x120 and Line by 1 to 304
[0x0000008a]  Advance PC by 4 to 0x124
[0x0000008c]  Extended opcode 1: End of Sequence

查看 binutils 的 dwarf.c 的来源,它似乎应该在行信息转储中打印类似“Set prologue_end to true”和“Set epilogue_begin to true”的内容。然而,所有的操作码似乎都是特殊的而不是标准的。

4

3 回答 3

2

这是一个非常迟到的响应,但是:如果您使用的是 LLVM,那么您可以从 DWARF 行程序状态机中获取此信息:LLV​​M 发出DW_LNS_set_prologue_endDW_LNS_set_epilogue_begin作为每个行程序条目的标志。

GCC 显然(还)不支持这些属性,因此它的周边工具(如readelfgdb)很可能也不支持。但是你应该能够用pyelftools.

于 2021-04-28T14:54:48.387 回答
1

如果您在 llvm 生成的可执行文件上运行 dwarfdump,您将看到如下内容:

.debug_line contents:

Address            Line   Column File   ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x000000010000d0d0     17      0     19   0             0  is_stmt
0x000000010000d0e0     17      1     19   0             0  is_stmt prologue_end

这意味着“第 17 行的文件 19 声明了一个方法,方法序言以 0x000000010000d0e0 结束”,我认为这应该意味着“如果你想为该方法的开头设置断点,那是最好的地方”[猜你有将 file:line:column 交叉链接回 Dwarf 其他部分以了解实际是哪种方法?]

于 2022-02-03T01:32:03.053 回答
0

尝试

readelf -wi

并为您正在查看的子例程查找 DW_AT_low_pc 和 DW_AT_high_pc。

DWARF 规范说:

一个子程序入口可能有一个 DW_AT_low_pc 和 DW_AT_high_pc 属性对或一个 DW_AT_ranges 属性,其值分别编码为子程序生成的机器指令的连续或非连续地址范围(参见第 2.17 节)。

如果我没记错的话,DW_AT_low_pc 是紧接在序言之后的地址,而 DW_AT_high_pc 是在结尾之前的最后一个地址。

不要担心操作码是“特殊的”,这意味着它们不接受参数来节省编码行号程序中的空间。

于 2014-09-28T18:45:21.397 回答