在Linux中,可执行文件中的对象文件

9
有没有办法在Linux(特别是RHEL)中找到生成当前可执行文件的目标文件?我知道可以使用“nm”查找导出的符号,“ldd”查找相关共享对象。但我找不到命令来查找由哪些目标文件(.o)组成的可执行文件的名称。这是否可能?
7个回答

7

对象文件的原始名称没有存储在DWARF调试信息中。

每个对象文件都有一个.debug_info部分中的DW_TAG_compile_unit条目。该条目包含一个引用,指向“导出编译单元的主要源文件”,但不包括对象文件的名称。 DWARF标准 包含可为每个编译单元存储的属性列表(第3.1.1节,页码44,pdf页58)。

您可以使用以下命令查看存储的信息:

$ readelf --debug-dump=info --dwarf-depth=1 hw

输出:

Contents of the .debug_info section:
<some compilation units removed>       
  Compilation Unit @ offset 0x133:
   Length:        0x8b (32-bit)
   Version:       4
   Abbrev Offset: 0x64
   Pointer Size:  4
 <0><13e>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <13f>   DW_AT_producer    : (indirect string, offset: 0x131): GNU C11 5.3.0 -mtune=generic -march=pentiumpro -g
    <143>   DW_AT_language    : 12      (ANSI C99)
    <144>   DW_AT_name        : (indirect string, offset: 0x163): hw.c
    <148>   DW_AT_comp_dir    : (indirect string, offset: 0x168): /home/mikel/src/hw
    <14c>   DW_AT_low_pc      : 0x80483db
    <150>   DW_AT_high_pc     : 0x2e
    <154>   DW_AT_stmt_list   : 0xea
 <1><158>: ...
<some compilation units removed>

6
如果它已经编译了调试信息,那么可以使用gdb(man gdb)查找信息。如果没有编译调试信息,那么就没有办法了。

3

您也可以使用objdump(只要可执行文件和对象是使用调试信息编译的):

# gcc -g -c -o /tmp/some_object.o /tmp/some_object.c
# gcc -g -o /tmp/file /tmp/file.c /tmp/some_object.o
# objdump -g /tmp/file | awk 'BEGIN{out=0} /Directory Table/{out=1} /Line Number Statements/{out=0} {if(out){print $0}}'
 The Directory Table (offset 0x1b):
  1     /tmp

 The File Name Table (offset 0x21):
  Entry Dir     Time    Size    Name
  1     1       0       0       file.c

 The Directory Table (offset 0x5a):
  1     /tmp

 The File Name Table (offset 0x60):
  Entry Dir     Time    Size    Name
  1     1       0       0       some_object.c

awk 是用来提取相关信息的(如果不使用,将会在可执行文件和对象文件中获取完整的调试信息)。


1

我没有足够的声望来添加评论,但是为了扩展Mikel Rychliski的建议使用readelf,您可以使用awk提取源文件的路径:

readelf --debug-dump=info --dwarf-depth=1 hw exe_to_examine | awk '/DW_AT_name/ {file=$8} /DW_AT_comp_dir/ {print $8 "/" file}'

这将输出源文件的完整路径(在我的情况下是.cpp文件),这些文件很可能与目标文件非常相似(取决于您的构建系统)。

1
一个对象文件在链接之后变成可执行文件。如果链接是共享的,那么你可以通过共享库(ldd)获取它。然而,如果链接是静态的,那么唯一的方法就是通过调试信息。你可以在RHEL(或Fedora)安装debuginfo包。以下是说明。

然后按照这里描述的方法使用gdb info sources:

这将给您一个源文件列表。但要实际获取目标文件,您需要深入了解构建工具(rpmbuild)。要实际运行rpmbuild,您需要获取源RPM包,可以使用此处列出的说明进行获取:

现在你可以自己构建软件包,并分析哪个.o文件导致了可执行文件的生成。
希望这有所帮助。

1
除了nullptr之外,“共享对象”还指其他共享库(已链接),而不是原始对象(未链接)。

0

类似Mikels答案,但是使用另一种工具,可能会给你更干净的输出。

过去我曾经有幸参与开发一个名为DIVA的调试信息分析器工具。它是免费且开源的,你可以在这里找到它:

https://github.com/SNSystems/DIVA

虽然使用DIVA无法找到链接到生成可执行文件的对象文件,但可以使用它来查找编译单元。

我快速地组合了一个小例子如下:

a.cpp

int a() {
  return 1;
}

a.h

int a();

b.cpp

int b() {
  return 2;
}

b.h

int b();

c.cpp

#include "a.h"
#include "b.h"

int main() {
  return a + b;
}

使用以下选项使用clang编译它们

$ clang a.cpp b.cpp c.cpp -o test.elf -g -O0

运行DIVA在test.elf上,并使用以下选项:
$ diva --show-none test.elf

这应该产生以下输出

{InputFile} "test.elf"
   {CompileUnit} "a.cpp"
   {CompileUnit} "b.cpp"
   {CompileUnit} "c.cpp"

我应该补充说明,你测试的可执行文件需要使用DWARF格式编译调试信息,才能让DIVA成功显示编译单元。 - T.Weaver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接