计算机系统基础-第七章 链接

笔记

计算机系统基础-第七章 链接_第1张图片
该图片来源于MOOC计算机系统基础(一)袁春风的课件

一些命令:

预处理命令 gcc –E prog.c –o prog.icpp prog.c > prog.i

编译命令 gcc –S prog.i –o prog.sgcc –S prog.c –o prog.s

汇编命令 gcc –c prog.s –o prog.ogcc –c prog.c –o prog.o,
as hello.s -o hello.o as是一个汇编程序

链接命令 gcc –static –o myproc main.o test.old –static –o myproc main.o test.o
–static 表示静态链接,如果不指定-o选项,则可执行文件名为“a.out”

链接过程将多个可重定位目标文件合并以生成可执行目标文件

链接符号的类型
每个可重定位目标模块m都有一个符号表,它包含了在m中定义和引用的符号。有三种链接器符号:
1.全局符号(Global symbols):由模块m定义并能被其他模块引用的符号。对应于非静态的C函数和全局变量。
2.外部符号(External symbols):由其他模块定义并被模块m引用的符号。对应于在其它模块定义的非静态C函数和全局变量。
3.局部符号(Local symbols):仅由模块m定义和引用的本地符号。对应于在模块m中定义的带static的C函数和全局变量。

操作

main.c

int sum(int *a, int n);		
int array[2] = {1, 2};
int main() 
{
    int val = sum(array, 2);
    return val;
}

sum.c

int sum(int *a, int n)
{
    int i, s = 0;  
    for (i = 0; i < n; i++) { 
        s += a[i];
    }
    return s;
} 

1.gcc -o prog main.c sum.c
调用GCC驱动程序将main.c和sum.c两个源程序翻译成可执行目标文件prog

2.readelf -h prog 显示可执行目标文件prog的ELF头信息
计算机系统基础-第七章 链接_第2张图片

魔数: 7f 45 4c 46 该文件的版本是64位
数据用补码表示,且用的小端法
操作系统为Linux,版本号为1,文件类型为可执行文件
机器为64位 入口地址为0x400a30,即prog第一条指令执行的地方 程序头表(段头表)的起始位置在64字节处,ELF头占64字节
节头表的起始位置在842616字节处
程序头表中有6个头表项,每个表项56字节,因此程序头表总长度为6×56B=336B
节头表中有33个表项,每个表项64字节,因此节头表总长度为33×64B=2112B

3.用-S命令查看节头表信息
3.1 readelf -S main.o 查看main.o的节头表信息
计算机系统基础-第七章 链接_第3张图片

main.o包含12个节,起始位置0x114 .text:
类型为PROGBITS,起始地址0x34,节大小0x1f,存储可执行代码,在运行时被加载器加载到内存 .rel.text:
类型为REL,起始地址0x3bc,节大小0x10 .data:
类型为PROGBITS,起始地址0x54,节大小0x8,可读可访问,存储被初始化的数据
.bss:类型为NOBITS,起始地址0x54,存储的是未经过初始化的数据,不需要空间,节大小为0,,可读可访问,存储未被初始化的静态变量,以及初始化为0的全局或静态变量
.comment: 类型为PROGBITS,起始地址0x5c,节大小0x25,存储未初始化的全局变量 .note.GNU-stack:
类型为PROGBITS,起始地址0x81 .eh_frame: 类型为PROGBITS,起始地址0x84,节大小0x38,运行时被加载到内存
.rel.eh_frame: 类型为REL,起始地址0x3cc,节大小0x8 .shstrtab:
类型为STRTAB,起始地址0xbc,节大小0x57 .symtab: 类型为SYMTAB,起始地址0x2f4,节大小0xb0
.strtab: 类型为STRTAB,起始地址0x3a4,节大小0x17

3.2 readelf -S sum.o 查看sum.o的节头表信息
计算机系统基础-第七章 链接_第4张图片
因为sum.o仅仅是参与link editor链接的可重定位文件,而不参与最后进程映像的构建,所以Addr(sh_addr)为0。Off(sh_offset)表示了该section离开文件头部位置的距离。Size(sh_size)表示section的字节大小。ES(sh_entsize)只对某些形式的sections有意义。比方符号表 .symtab section,其内部包含了一个表格,表格的每一个条目都是特定长度的,那这里的这个字段就表示条目的长度10。Al(sh_addralign)是地址对齐要求。另外剩下的两列Lk和Inf,对应着条目结构中的字段sh_link和字段sh_info。它们中记录的是section head table 中的条目索引,这就意味着,从这两个字段出发,可以找到对应的另外两个 section,其具体的含义解释依据不同种类的section 而不同。
以上内容来自链接 https://www.cnblogs.com/xmphoenix/archive/2011/10/23/2221879.html

3.3 readelf -S prog 查看prog的节头表信息

4.用-s命令查看文件中所有的符号信息
4.1 readelf -s main.o 查看main.o中的符号
计算机系统基础-第七章 链接_第5张图片

文件中定义了一个函数main,存储为FUNC类型的全局符号,执行节1,即ELF可重定位文件中的.text节,大小为31
符号array为全局变量,执行节3,即.data节,大小为8,符号类型为OBJECT
符号sum属于未定义引用,节索引值为UND,符号类型为NOTYPE

4.2 readelf -s sum.o 查看sum.o中的符号
计算机系统基础-第七章 链接_第6张图片

文件中定义了一个函数sum,存储为FUNC类型的全局符号,执行节1,即ELF文件中的.text节,大小为69

符号:
计算机系统基础-第七章 链接_第7张图片
符号在ELF可重定位文件中对应的节:
计算机系统基础-第七章 链接_第8张图片

5.readelf -l prog 查看可执行文件prog程序头表的信息
计算机系统基础-第七章 链接_第9张图片

入口地址为0x400a30,程序头表中有6个头表项,起始位置在64字节处
第一个LOAD(可装入段) 偏移量为0x0
映射到虚拟地址从0x400000开始长度为0xb5716字节的区域;
Flags为R E表示可执行,不可写,具有只读/执行权限,是只读代码段;按0x200000=2^21=2MB对齐

问题

  1. 执行 gcc -E sum.c –o sum.i 命令时

gcc: error: –o: 没有那个文件或目录
gcc: error: sum.i: 没有那个文件或目录

原因不知。
重新打开终端后未出现该问题。

你可能感兴趣的:(计算机系统基础)