静态链接与加载
准备好两个文件:
c
// hello.c
#include <stdio.h>
void run();
int main()
{
printf("hello world.\n");
run();
return 0;
}
c
// code.c
#include <stdio.h>
void run()
{
printf("running...\n");
}
静态编译成可执行文件main。(static)
然后使用objdump指令,做好文件code.s hello.s main.s,以方便观察其中信息。
1、静态链接------函数地址重定向
目标文件.o为什么执行不了呢?
除了一些使用的方法没有定义,.o执行不了的另一个原因,就是.o文件涉及函数调用的位置,无法定位被调用函数的地址。即调用函数的地址没有被设置。


而编译器在链接成可执行文件的过程中,就设置好了要去到的地址。未来CPU根据这些地址,就能找到对应的方法。

静态链接做的工作,除了把要用到的方法全部拷贝到可执行文件中,还有一件事,就是对.o文件的函数地址进行重定向。所以.o文件又叫做"可重定位目标文件"。
2、再谈虚拟地址------逻辑地址与虚拟地址
上面说编译器在链接的过程中就已经设置好了地址。我们观察.s汇编文件也确实看到了地址。但这与我们之前的"操作系统设置地址"的观念不符。
事实上,代码、变量等数据的地址,在静态编译中就是由编译器在链接形成可执行文件过程中确定的。
如何理解我们在.s文件中看到的地址?
可执行程序的地址分为三类:逻辑地址、虚拟地址、物理地址
| 地址类别 | 内涵解释 |
|---|---|
| 逻辑地址 | 数据在磁盘中地址的叫法。相对编址,即起始地址 + 偏移量 |
| 虚拟地址 | 数据加载到内存中地址的叫法,其实和逻辑地址是几乎等价的。绝对编址,也是起始地址 + 偏移量,只不过起始地址是0x0 |
| 物理地址 | 加载时由操作系统分配 |
比如,我们在.s文件中看到的地址,就是逻辑地址 。

内存中CPU根据输入的虚拟地址 ,在页表中查找物理地址,然后找到并执行指令。
而相对编址的方法,可以和绝对编址合并,因为起始地址都可以从0x0开始。合并的结果就是"平坦模式编址",也就是虚拟地址的编址方式。
3、静态加载
静态链接形成的可执行文件,加载到内存中,需要经过如下的一系列过程。我们用一张图就能搞定。

