首页 > 代码库 > 链接 与 加载

链接 与 加载

一、GUN处理目标文件的工具

AR 创建静态库,插入、删除、列出和提取成员;
SRING 列出目标文件中的字符串;
SIRIP 从目标文件中删除符号表信息;
NM 列出目标文件符号表中定义的符号;
READELF 显示一个目标文件的完整结构 SIZE 列出目标文件中节的名字和大小; OBJDUMP 所有二进制工具之母,可显示一个目标文件中所有的信息。
LDD 列出一个可执行文件在运行时所需要的动态库

 

首先对一个c文件进行编译生成.o目标文件

然后可以通过nm 和readelf来查看目标文件的符号表

 

nm------->

00000000 t $d
00000014 t $d
00000000 t $d
00000010 t $d
         U heap_init
00000000 T init_all
00000000 T main
         U printf
00000000 t $t
00000000 t $t
         U uart_init

其中

         B --- 全局非初始化数据段(BBS段)的符号,其值表示该符号在bss段中的偏移,如g1

           b --- 全局static的符号,如g3

           r --- const型只读的变量(readonly)

           N --- debug用的符号

           T --- 位于代码区的符号,比如本文件里的函数main foo

           t  --- 位于代码区的符号,一般是static函数

           U --- 位于本文件外的调用函数或变量符号,比如系统的printf()函数

 

readelf -s xxx.o

Symbol table .symtab contains 31 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    2 
     4: 00000000     0 SECTION LOCAL  DEFAULT    3 
     5: 00000000     0 SECTION LOCAL  DEFAULT    4 
     6: 00000000     0 SECTION LOCAL  DEFAULT    5 
     7: 00000000     0 SECTION LOCAL  DEFAULT    7 
     8: 00000000     0 SECTION LOCAL  DEFAULT    9 
     9: 00000000     0 NOTYPE  LOCAL  DEFAULT    9 $d
    10: 00000000     0 NOTYPE  LOCAL  DEFAULT    9 $t
    11: 00000014     0 NOTYPE  LOCAL  DEFAULT    9 $d
    12: 00000000     0 SECTION LOCAL  DEFAULT   11 
    13: 00000000     0 NOTYPE  LOCAL  DEFAULT   11 $d
    14: 00000000     0 NOTYPE  LOCAL  DEFAULT   11 $t
    15: 00000010     0 NOTYPE  LOCAL  DEFAULT   11 $d
    16: 00000000     0 SECTION LOCAL  DEFAULT   13 
    17: 00000000     0 SECTION LOCAL  DEFAULT   14 
    18: 00000000     0 SECTION LOCAL  DEFAULT   16 
    19: 00000000     0 SECTION LOCAL  DEFAULT   18 
    20: 00000000     0 SECTION LOCAL  DEFAULT   20 
    21: 00000000     0 SECTION LOCAL  DEFAULT   22 
    22: 00000000     0 SECTION LOCAL  DEFAULT   24 
    23: 00000000     0 SECTION LOCAL  DEFAULT   28 
    24: 00000000     0 SECTION LOCAL  DEFAULT   25 
    25: 00000000     0 SECTION LOCAL  DEFAULT   26 
    26: 00000000    24 FUNC    GLOBAL DEFAULT    9 init_all
    27: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND heap_init
    28: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND uart_init
    29: 00000000    20 FUNC    GLOBAL DEFAULT   11 main
    30: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf

 

 

二、链接

通过ld进行链接

链接可以把包括 目标文件,静态库,动态库,编译链接生成完全链接的可执行目标文件

链接器主要完成以下操作

1)符号解析:将符号引用和符号定义联系起来

2)重定位:从0地址开始生成代码数据节

 

目标文件.o (可重定位目标文件): 

静态库.a (通过ar命令生成) :合并静态库和目标文件使未定义符号能引用到唯一一个定义生成可执行文件

动态库.so(gcc -shared -fPIC -o xxx.so x1.c x2.c): 在链接时加载时进行动态链接(-fpic生成位置无关代码)

  将动态库的文本数据重定位到某个存储器段

  在链接时会在elf的text段生成PLT过程链接表  在data段开始的地方生成GOT全局偏移表

 

三、项目的地址规划

1)elf目标文件包含的各个节段

①text段:代码段(codesegment/textsegment)

  通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定。

②rodata段:只读数据

存放C中的字符串和#define定义的常量

③data段:数据段(datasegment

通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

④bss段: BSS段(bsssegment)  

通常是指用来存放程序中未初始化的全局变量的一块内存区域。不占任何实际的磁盘空间。

⑤其他

symtab段:符号表

rel.text段

rel.data段

debug段

line段

strtab段

⑥stack栈:

是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

⑦heap堆:

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

 

写一个链接脚本

ENTRY( __reset);

MEMORY
{
    dram : ORIGIN = 0x00080000, LENGTH = 0x10000
}

SECTIONS
{
    .text : { 
        _start_text_ = .;
        /*start.o(.text*)*/
        *(.text*)
        *(.rodata*)
        . = ALIGN(4);
        _end_text = .;
    } > dram

    .data : { 
        _start_data = .;
        *(.data*)
        . = ALIGN(4);
        _end_data = .;
    } > dram

    .bss : { 
        _start_bss_ = .;
        *(.bss) *(COMMON)
        . = ALIGN(4);
        _end_bss_ = .;
    } > dram

}

规划了各个节段从0x00080000开始,大小0x10000

各个段顺序是text < rodata < data < bss,4字节对齐

通过     ld ldflags -T link.ld *.o *.a -o x.elf

 

.S文件为汇编代码,一般为系统刚跑起来的时候运行的代码

包括了stage1 stage2的代码

 

链接 与 加载