一些命令:
预处理命令 gcc –E prog.c –o prog.i
,cpp prog.c > prog.i
编译命令 gcc –S prog.i –o prog.s
,gcc –S prog.c –o prog.s
汇编命令 gcc –c prog.s –o prog.o
,gcc –c prog.c –o prog.o
,
as hello.s -o hello.o
as是一个汇编程序
链接命令 gcc –static –o myproc main.o test.o
,ld –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头信息
魔数: 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的节头表信息
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的节头表信息
因为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中的符号
文件中定义了一个函数main,存储为FUNC类型的全局符号,执行节1,即ELF可重定位文件中的.text节,大小为31
符号array为全局变量,执行节3,即.data节,大小为8,符号类型为OBJECT
符号sum属于未定义引用,节索引值为UND,符号类型为NOTYPE
4.2 readelf -s sum.o
查看sum.o中的符号
文件中定义了一个函数sum,存储为FUNC类型的全局符号,执行节1,即ELF文件中的.text节,大小为69
5.readelf -l prog
查看可执行文件prog程序头表的信息
入口地址为0x400a30,程序头表中有6个头表项,起始位置在64字节处
第一个LOAD(可装入段) 偏移量为0x0
映射到虚拟地址从0x400000开始长度为0xb5716字节的区域;
Flags为R E表示可执行,不可写,具有只读/执行权限,是只读代码段;按0x200000=2^21=2MB对齐
gcc -E sum.c –o sum.i
命令时gcc: error: –o: 没有那个文件或目录
gcc: error: sum.i: 没有那个文件或目录
原因不知。
重新打开终端后未出现该问题。