80x86汇编编程-2(程序链
看清 .o 文件如何被拼成可执行:符号解析、重定位、库链接全拆解
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
80x86汇编编程-2(程序链
看清 .o 文件如何被拼成可执行:符号解析、重定位、库链接全拆解
程序链接-1
前面我们看到编译器把单个 .c 编成 .obj——但实际程序往往有十几个源文件,每个都生成自己的 .obj。谁负责把它们拼成最后那个能跑的 .exe?
墙板来自不同车间,链接器像现场工长:对齐接口、接通管线、丢掉多余的零件
程序链接-2
上一页我们看到链接器把多个 .o 拼成一个可执行文件——但拼接远不是复制粘贴。两件棘手事必须解决:某个函数到底在哪个目标文件里?拼好后地址都挪了,原指令里的地址怎么办?
各作者交章节(.o),编辑统一页码(重定位),并把「参见第三章」改成新页码(符号解析)
程序链接-3
程序链接-3:定义、要点与典型应用
程序链接-4
上一节我们看到静态链接把所有库代码打包进可执行文件。十台机器跑同一程序,内存里就有十份相同的 printf。动态链接正是为解决这一痛点——库代码运行时才加载,多个进程共享一份。
书统一存放,要用时再借,多人共享同一本;共享库也一样——运行时按需加载、多进程共享代码
程序链接-5
上页我们讲到多个进程能共享同一份共享库——但代价是这份代码必须在任何加载地址都能跑。传统的绝对寻址会立刻失效。这就是位置无关代码(PIC)要解决的问题。
房卡写『前台左转第3门』而非『XX路123号』:'前台'对应当前位置,'左转第3门'对应相对偏移
程序链接-6
链接-5里库代码段共享给多个进程,但库每次加载地址都不同——跳转指令的目标怎么写死?答案是让代码本身「位置无关」,跳转时再查一张可写的表。
客人(调用方)问前台(PLT),前台查登记本(GOT)报房号;第一次真查,后续直接报
程序链接-7
上一页我们把多个 OBJ 合成一个 EXE,但 Windows 里大量代码躺在 DLL 里——它们怎么被装进你的进程?这页拆开看动态链接的几个关键。
不必每户自建,拎包来用;冲突时换地方但功能不变
程序链接-8
链接器默认按段类型顺序塞进内存——但嵌入式固件常常要把启动代码钉死在 0x08000000、把中断向量表占据最低 256 字节。这些精细布局就要靠链接器脚本指挥。
MEMORY 是地块划线(哪些地址可用),SECTIONS 把各段落到具体房间
程序链接-9
动态链接把共享库加载进内存后,程序怎么知道函数实际跑在哪里?靠 PIC 和 GOT/PLT 这套精巧设计:代码不挑地址,地址查表获取,首次调用才解析。
取餐码(PLT)是占位符,第一次去窗口查实际摊位(GOT解析),记下来下次直接喊
程序链接-10
链接器把多个 .o 文件拼成一个可执行文件。但「怎么拼」有两种思路——焊死还是留口?这就是本页要分清的事。
做饭把食材搬进厨房(焊死),外卖只下单菜现做(运行时拼)
程序链接-11
编译器把每个 .c 单独编译成 .o 时,不知道变量和函数最终落在内存哪里。它在引用地址处先挖坑、登记重定位表,链接器合并段后来填这些坑。
砌墙时孔位先留着,按实际面板型号最后补上
本节要点
- ✓链接 = 符号解析 + 重定位,两阶段缺一不可
- ✓未定义符号在目标文件中以占位形式存在
- ✓同名同类段被链接器拼接为单一映像
- ✓静态库只链入被引用到的目标文件
- ✓重定位条目决定地址补丁的写入方式
课后思考
先独立作答并写下理由,再逐条对照参考答案,检验自己能否说清链接中的关键步骤。
参考答案先确定外部符号的唯一归属,链接器才能把重定位项记录的偏移加到真实基址,并写回机器码。
参考答案依工具链规则处理强、弱符号:多个强定义通常报歧义,弱定义才可能按规则覆盖。工程上应统一命名、少暴露全局符号。
参考答案不能保证。链接器按脚本安排各段,再按符号绑定完成重定位;脚本、段顺序或符号归属一变,地址结果就可能改变。