关于c的静态重定位

问题描述:

关于目标文件中文本段的每个机器码都有地址,它将从0到一个数字。关于c的静态重定位

当链接器链接所有目标文件时,关于指令的地址将会改变。

我无法看到链接器是否会逐个读取关于文本段的指令以更改每个指令地址。

Disassembly of section .text: 

00000000 <_start>: 

    0: bf 00 00 00 00   mov $0x0,%edi 
    5: 8b 04 bd 00 00 00 00 mov 0x0(,%edi,4),%eax 
    c: 89 c3     mov %eax,%ebx 

通过链接

08048074 <_start>: 

    8048074: bf 00 00 00 00   mov $0x0,%edi 
    8048079: 8b 04 bd a0 90 04 08 mov 0x80490a0(,%edi,4),%eax 
    8048080: 89 c3     mov %eax,%ebx 

就像0→8048074等。

+0

不确定这是否是您要查找的内容,但该过程在' - ['man gcc']中的fpic'相关部分(http://linux.die.net/man/1/gcc)。 – CristiFati

+8

真正的问题是什么? – Art

+0

直到链接器创建它时才存在机器代码,所以我不明白你的意思。 “从哪里阅读关于文本部分的指示”? – Lundin

好吧,我假设你正在使用一些基于unix的系统,因为这看起来像objdump命令的输出,但我知道这与ELF和PE文件都是相关的。我们首先在使用c时将一些模型编译到目标文件中,并最终将它们链接在一起,如前所述。例如:

  • m1.c - >m1.o
  • m2.c - >m2.o
  • main.c + m2.o + m1.o - >main.exe

我们有一个名为m1.c/m2.c一些C程序,定义了一些功能,由main.c调用,最终全部链接并编译到main.exe中ich完全可执行。

现在,让我们潜入并看看引擎盖下发生了什么。首先我想从一个非常重要的开始开始,在最后的可执行文件中,在我们的例子(main.exe)中,所有地址都是完全分辨的虚拟地址(这不一定是真的,因为某些概念称为PIE/PIC,但是现在让我们不要进去)

因此内你的可执行文件,函数内m1.ofoo会有些解决地址(例如0x400100),MAIN.EXE内当调用函数foo你拆卸一些诸如内看到as

call 0x400100 

现在这就是概念上发生的事情,现在让我们进入实际发生的事情。当获取指令时,例如jmpcall指令某些地址作为操作数给出,然后处理器的指令寄存器更改为作为操作数给出的地址,因此,如果链接器按指令执行指令,找到哪个指令需要改变并改变它?好,不,链接器根本就没有这样做,它比这更聪明。

首先,编译时,编译器生成的跳转和调用,以内部模块(例如jmp一些地址应该在我们的例子中m1.o已经属于)相对于当前指令执行。那是什么意思? 假设我们有一些if语句,它将被编译为跳转到某些地址,编译器足够聪明,可以使用相对跳转操作数并在命令之间放置偏移量,因此链接器连接时甚至不必更改它们,因为调用与当前指令相关,并且某个目标文件的命令之间的偏移量通过链接阶段保持静态,所以与加载代码的哪个地址无关。

现在这里的事情变得稍微复杂一点,我们已经介绍了链接器如何避免内m1.o改变地址,现在,如果在m1.o定义m2.o调用函数都是可执行文件,有没有办法在地球上编译器可以假设他们之间的偏移,因为他们都不知道他们会链接多少其他模型,这是如何解决的?引入符号和重定位表。

  • 符号表 - 包含在模型中的所有符号表 - 一个 符号的东西,其他型号可能需要通过名称来识别,如函数和全局变量, 。
  • 重新定位表 - 一个表,其中包含某些模型中 符号的所有“出现”。

你以前可能听说过这些,但现在我会向你解释这些。 在进入之前,我需要警告我对ELF格式文件更加熟悉,但据我所知,概念上PE文件的工作方式是一样的。

让我们看看这个例子的代码

#include <stdio.h> 
/** file: m1.c **/ 

extern void goo(); 

void foo() 
{ 
    printf("I am foo()!\n"); 
    goo(); 
} 

#include <stdio.h> 
/** file: m2.c **/ 

void goo() 
{ 
    printf("I am goo()!\n"); 
} 

编译对象文件内m1.o时,会有一些表说,这样的事情

符号:foo - >在文件中的偏移X处,goo - >未定义 RELOCATION:goo - >在文件中的偏移Y处,

现在这意味着编译器会生成一个表,收集模型使用的所有函数并确定它们是否被定义 - 它给出函数在其内定义的偏移量如果它没有定义它会说明它,

它也会声明,在这个模型中,goo被称为偏移量X,它需要被重新定位(我们会得到我的观点,这是答案你的问题!)

当链接到一个可执行文件时,链接程序将获取所有目标文件的所有符号,解析其中的某个地址,然后遍历每个目标文件的每个符号表,查找并确定哪些符号尚未定义,然后它通过重定位表并查看哪些调用是针对未定义的符号进行的,将该位置放在文件中,然后简单地将调用的地址重新写入解析的地址,所以如果在我们之前有这样的东西m1.o

call 0x000000 ;undefined goo address 

符号解析后,链接器将可能对重定位表一些入门说你需要的线X搬迁咕地址,我们将会导致

call 0x400100 ;actual goo address 

仅供参考,有一个未定义的引用链接错误时,它意味着你有你的符号表中的一些不确定的符号和连接器不能解析匹配功能的定义,它也...如果我没有说清楚,这对于全局变量和静态变量的作用完全相同,它们也被认为是符号

+0

这是完美的,你应该得到一枚奖章!谢谢。 – Pyjong