链接器如何解析汇编代码中的符号

8
我想知道连接器如何解析以下汇编代码中的printf符号。
#include<stdio.h>
void main()
{
     printf("Hello ");
}




    .file   "test.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .section .rdata,"dr"
LC0:
    .ascii "Hello \0"
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    call    __alloca
    call    ___main
    movl    $LC0, (%esp)
    **call  _printf**
    leave
    ret
    .def    **_printf**;    .scl    3;  .type   32; .endef

希望能够提供一些关于低级别解释的内容。

提前感谢。


1
一个很好的问题,但并没有被问得足够多,这也导致了诸如“未解决符号”之类的问题在SO上频繁出现! - xtofl
4个回答

17
假设使用 ELF 文件格式,汇编器将在目标文件中生成一个未定义符号的引用。它会像这样显示:
符号表'.symtab'包含11个条目:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS test.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 SECTION LOCAL  DEFAULT    3
     4: 00000000     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000000     0 SECTION LOCAL  DEFAULT    6
     7: 00000000     0 SECTION LOCAL  DEFAULT    7
     8: 00000000    52 FUNC    GLOBAL DEFAULT    1 main
     9: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
    10: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND exit
它还会创建一个重定位项来指向代码映像中需要由链接器使用正确地址更新的部分。它看起来像这样:
$ readelf -r test.o
重定位段'.rel.text'位于偏移量0x358处,包含3个条目: Offset Info Type Sym.Value Sym. Name 0000001f 00000501 R_386_32 00000000 .rodata 00000024 00000902 R_386_PC32 00000000 printf 00000030 00000a02 R_386_PC32 00000000 exit
然后链接器的工作就是遍历重定位表,并使用最终符号地址修复代码映像。

有一本绝佳的书,但我现在找不到详细信息(而且已经绝版)。不过,这个链接看起来可能会很有用:http://www.linuxjournal.com/article/6463


Dave的回答非常出色,阐述得非常清晰。非常感谢你。如果你能提醒自己并让我也看看那本书,那就太感激了 :) - Mahesh

1

如果你想了解链接过程,可以看一下John Levine的《Linkers & Loaders》这本书。你可以在这里获取手稿章节的HTML格式。


1
一篇可能对你有帮助的论文是 Ulrich Drepper 的 How To Write Shared Libraries。Ulrich 是 Linux glibc 的维护者,也是 ELF 方面的权威。
尽管这篇论文是关于如何编写共享库以及如何导出或不导出符号,但它解释了这些符号在具有 ELF 格式的可执行文件内部如何动态解析。
我想这可能会回答你的问题。

1

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