《程序员的自我修养》第四章学习笔记

 2015.12.26的笔记,放在了草稿箱。2023.8.24发布一下吧。

第四章 静态链接

 先上两个文件

// a.c

extern int shared;

int main()
{
     int a = 100;
    swap(&a, &shared);
} 
// b.c

int shared = 1;

void swap(int *a, int *b)
{
    *a ^= *b ^= *a ^= *b;
}

 再来只编译不链接
$ gcc -c a.c b.c

最后用ld链接器进行链接

$ ld a.o b.o -e main -o ab     // -e main 表示将main函数作为程序入口

这样 就一共有了三个目标文件  a.o   b.o   ab

 

4.1 空间与地址分配

 a.o b.o 链接生成 ab。 对于多个输入目标文件,链接器如何将它们的各个段合并到输出文件。

 

4.1.1 按序叠加:简单的将各个目标文件文件依次合并。 造成空间浪费(因为每个段都需要有一定的地址和空间对齐要求)。

 

4.1.2 相似段合并:将相同性质的段合并到一起。 a.o的.text 和 b.o的.text 合并成 ab的.text。其他的段也类似。

1,“链接器为目标文件分配地址和空间”:“地址和空间”有两层含义,一是在输出的可执行文件中的空间。二是在装载后的虚拟地址中的虚拟地址空间。

2,链接器空间分配的策略采用一种叫两步链接的方法(分成两步)

  (1)第一步 空间与地址分配:扫描所有输入目标文件,获取它们的各个段的长度、属性和位置,将输入目标文件中的符号表中所有的符号定义和符号引用搜集起来,同意放到一个全局符号表中。

    这一步中链接器将能够获得所有输入目标文件的段长度,并且将它们合并,计算输出文件各个段合并后的长度和位置,并建立映射关系。

  (2)第二步符号解析和重定位: 使用上面搜集到的信息,读取输入文件段中的数据、重定位信息,并且进行符号解析与重定位、调整代码中的地址。

3,$ ld a.o b.o –e main –o ab     -e main 表示将main函数作为程序入口。ld链接器默认的程序入口为 _start。

4,在Linux下,ELF可执行文件默认从地址0x08048000开始分配。

5,用objdump来查看链接前后地址的分配情况

 $ objdump -h a.o

 $ objdump -h b.o

 $ objdump -h ab

File off:文件偏移

Size:大小

VMA:Virtual Memory Address 虚拟地址(我们主要关心这个和Size)

LMA:Load Memory Address 加载地址

正常情况下 LMA VMA应该是一样的,但是在有些嵌入式系统中,这两个有可能是不一样的。

说明:

1)在链接之前,目标文件的VMA都是0,因为虚拟空间还没有被分配。链接之后,可执行文件ab中的各个段都被分配到了相应的虚拟地址。

2)在Linux下,ELF可执行文件默认从地址0x08048000开始分配。

 

4.1.3 符号地址的确定

 

posted @ 2023-08-24 10:02  xcywt  阅读(15)  评论(0编辑  收藏  举报
作者:xcywt
出处:https://www.cnblogs.com/xcywt//
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果文中有什么错误,欢迎指出。以免更多的人被误导。