程序员的自我修养2.1 静态链接-两步链接

静态链接

  • 本文需要用到的代码
#include<stdio.h>
int global_init_val = 84; //.data
int global_uninit_val;
__attribute__((section("FOO"))) int global = 42;//FOO
int main(){
        int init_a = 20;
        int uninit_b;
        static int static_b = 40;//.data
        static int static_uninit_c;
        return 0;
}

  • 对于链接器来说,整个链接过程,就是将几个输入目标文件加工合并成一个输出文件,由目标文件.o到可执行文件.out,合并方式一般由两种
    1. 按序叠加,其实就是把a.o的所有段放好了,然后接下来放b.o的所有段,但是这种方法有缺点
      1. 首先就是每个文件的段都是分开的,导致最后的可执行文件的段可能有许多个,非常的浪费空间
      2. 内存的基本分配单位是页,所以每个段都会至少占据一个页,那么就会产生非常多的页内碎片
    2. 相似段合并 : 把几个输入目标文件的一样的段放一起,比如把a.o和b.o的.text放一起,然后放.data,现在一般都是这种方式

两步链接

  1. 空间和地址分配
    1. 分配虚拟空间
    2. 更新符号地址
  2. 符号解析和重定位

空间和地址分配

  1. 分配虚拟空间

在这里插入图片描述

  1. 将所有目标文件的符号表以及相关信息整合成一个全局符号表,通过给每个符号加上一个偏移量就可以得出符号的虚拟地址,比如main函数原本相对.text的偏移是X(这个y通过查看该目标文件的符号表就可以知道readelf -s hello2.o),而分配虚拟空间后,.text的虚拟空间是Y,所以main的最终的虚拟地址就是X+Y
  • 注意 : linux中,虚拟空间默认从0x08048000开始分配

符号解析和重定位

  • 在ELF文件格式中,存在一个重定位表,该表记录的信息是:该目标文件所有存在外部引用的地方,而重定位表往往由多个,比如.ref.text,.ref.rodata,使用objdump -r hello2.o可以查看文件的重定位表
    在这里插入图片描述

  • 符号解析就是根据重定位表,找到哪里需要重定位,重定位的符号是什么,然后再去全局符号表找到该符号的虚拟地址

  • 指令修正方式,<<程序员的自我修养>>这本书p109有详细的例子说明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值