自定义 ELF 文件中未定义的引用,但符号在文件符号表中定义

Undefined reference in a custom ELF file, but the symbol is defined in the files symbol table

提问人:user1652403 提问时间:6/21/2020 最后编辑:user1652403 更新时间:6/22/2020 访问量:1683

问:

我一直在尝试了解 x86-64 机器代码和 ELF 文件。为此,我编写了一些代码来生成一个包含一些机器代码的 ELF 文件。我使用一些我组装的机器代码(它只是打印一条消息并调用系统调用,接下来是自己学习组装机器代码)并编写了一个 C 程序来手动将正确的 ELF 标头/Section 标头/符号表等写入文件。nasmexit

现在我正在尝试将我的文件(其中包含单个函数)链接到另一个 elf 文件,我通过 C 代码生成该文件():gcctest.c

// does not work with or without "extern"
extern void hello();

void _start()
{
  hello();

  // exit system call
  asm(
    "movl $60,%eax;"
    "xorl %ebx,%ebx;"
    "syscall");
}

我的ELF文件的输出是():readelf -ahello.o

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          64 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         9
  Section header string table index: 8

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000280
       0000000000000044  0000000000000000  AX       0     0     16
  [ 2] .rela.text        RELA             0000000000000000  000002c8
       0000000000000030  0000000000000018   I       6     1     8
  [ 3] .data             PROGBITS         0000000000000000  00000300
       0000000000000005  0000000000000000  WA       0     0     16
  [ 4] .bss              NOBITS           0000000000000000  00000310
       0000000000000080  0000000000000000   A       0     0     16
  [ 5] .rodata           PROGBITS         0000000000000000  00000310
       000000000000000d  0000000000000000   A       0     0     16
  [ 6] .symtab           SYMTAB           0000000000000000  00000320
       0000000000000150  0000000000000018           7    14     8
  [ 7] .strtab           STRTAB           0000000000000000  00000470
       0000000000000028  0000000000000000           0     0     1
  [ 8] .shstrtab         STRTAB           0000000000000000  00000498
       000000000000003f  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

There is no dynamic section in this file.

Relocation section '.rela.text' at offset 0x2c8 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
00000000001a  000500000001 R_X86_64_64       0000000000000000 .rodata + 0
000000000024  00050000000a R_X86_64_32       0000000000000000 .rodata + d

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.symtab' contains 14 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     9: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    10: 0000000000000000    68 FUNC    GLOBAL DEFAULT    1 hello
    11: 0000000000000060    13 OBJECT  LOCAL  DEFAULT    5 msg
    12: 000000000000000d     8 NOTYPE  LOCAL  DEFAULT  ABS len
    13: 0000000000000050     5 OBJECT  GLOBAL DEFAULT    3 _test

No version information found in this file.

我已经编译了test.c

gcc -c -nostdlib -fno-asynchronous-unwind-tables test.c -o test.o

然后与 链接,不幸的是,这会产生ld test.o hello.o

ld: test.o: in function `_start':
test.c:(.text+0xa): undefined reference to `hello'

即使函数在 (请注意符号表中命名的条目,该条目位于第 1 节,该部分中,并且似乎具有正确的大小/类型/值/绑定)。hellohello.ohello.text

如果我以与编译相同的方式编译一个文件,这两个目标文件显然可以链接。此外,如果我将自己的 ELF 文件生成为可执行文件,则将函数重命名为它可以很好地执行。我已经用头撞墙一段时间了,我想知道两件事:显然我想知道我的ELF文件问题。但我也想知道将来如何调试此类问题。我尝试使用调试符号从源代码构建(克隆 GNU binutils 存储库),但我没有走得很远调试本身。void hello(){}test.chello.ohello_startldld

编辑:我已在此处上传了我的精灵文件: https://drive.google.com/file/d/1cRNr0VPAjkEbueuWFYwLYbpijVnLySqq/view?usp=sharing

c linker ld elf undefined-reference

评论

0赞 user1652403 6/21/2020
我不出所料地做到了,而且它跑了。
0赞 user1652403 6/21/2020
编译和链接 C 代码没有问题,只有当我链接到我上传的特定文件时(链接消失了,我重新上传了它)。我已经澄清了我如何生成 ELF 文件的细节,因为我可能有点含糊不清。这肯定是该文件的问题,但我无法自己弄清楚,即使经过数小时的搜索文档和 System V ABI 规范。据我所知,是一个有效的可链接 ELF 文件,其中定义了一个符号:函数(并确认)。但不知何故不喜欢它。hello.ohello.ohelloreadelfld
0赞 Marco Bonelli 6/21/2020
哦,所以你想知道你自己构建的文件具体出了什么问题,对不起,我没有得到那部分。很难说,如果不知道你到底做了什么来生成文件,你应该添加生成它所需的步骤。hello.o
0赞 user1652403 6/21/2020
好吧,我几乎只是使用结构来构造 ELF 标题/部分标题/符号表等并将它们写入文件。我事先做了一些计算,以计算所有正确的偏移量,其中的东西在文件中,仅此而已。代码又乱又长,所以我没有上传。奇怪的是,两者都可以很好地读取和反汇编文件<elf.h>readelfobjdump

答:

3赞 Employed Russian 6/22/2020 #1

这很难调试。

以下是您上传到 Google 云端硬盘的文件的输出(它与您的问题中的信息不匹配):readelf -WSs hello.o

There are 9 section headers, starting at offset 0x40:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000000000 000280 000044 00  AX  0   0 16
  [ 2] .rela.text        RELA            0000000000000000 0002c8 000030 18   I  6   1  8
  [ 3] .data             PROGBITS        0000000000000000 000300 000005 00  WA  0   0 16
  [ 4] .bss              NOBITS          0000000000000000 000310 000080 00   A  0   0 16
  [ 5] .rodata           PROGBITS        0000000000000000 000310 00000d 00   A  0   0 16
  [ 6] .symtab           SYMTAB          0000000000000000 000320 000150 18      7  14  8
  [ 7] .strtab           STRTAB          0000000000000000 000470 000028 00      0   0  1
  [ 8] .shstrtab         STRTAB          0000000000000000 000498 00003f 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

Symbol table '.symtab' contains 14 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    8
     9: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    10: 0000000000000000    68 FUNC    GLOBAL DEFAULT    1 hello
    11: 0000000000000060    13 OBJECT  LOCAL  DEFAULT    5 msg
    12: 000000000000000d     8 NOTYPE  LOCAL  DEFAULT  ABS len
    13: 0000000000000050     5 OBJECT  GLOBAL DEFAULT    3 _test

问题出在该部分的值 (14) 上。.sh_info.symtab

根据文档,for 部分应该包含“比最后一个本地符号(绑定STB_LOCAL)的符号表索引大一个”。.sh_infoSYMTAB

因此,值 14 告诉链接器此文件中的所有符号都是本地符号,因此不可能用于解析对它们的任何外部引用。

您需要将所有符号移动到 1 之前(此处,并且需要在 之前移动),以便符号表如下所示:LOCALGLOBALmsglenhello

...
     9: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    10: 0000000000000060    13 OBJECT  LOCAL  DEFAULT    5 msg
    11: 000000000000000d     8 NOTYPE  LOCAL  DEFAULT  ABS len
    12: 0000000000000000    68 FUNC    GLOBAL DEFAULT    1 hello
    13: 0000000000000050     5 OBJECT  GLOBAL DEFAULT    3 _test

然后将该部分设置为 12。.sh_info.symtab

但我也想知道将来如何调试此类问题。

正如你所发现的,调试 binutils 非常困难,部分原因是它使用了 ,它充满了宏,而且本身很难调试。ldlibbfd

我通过从源代码构建 Gold 来调试它,幸运的是,这产生了完全相同的失败。

评论

0赞 user1652403 6/22/2020
好的,做到了!非常感谢,阅读解决方案让我觉得自己很愚蠢,但我预料到了这样的事情。我从来没有真正找到任何关于这些部分的 and 字段的好文档,所以链接真的很有帮助。我还更新了输出的内容以匹配我上传的文件,以备将来参考,如果该文件以某种方式无法再访问。.sh_info.sh_linkreadelf