编译和链接的那些故事

34 篇文章 1 订阅

 

 

编译连接过程

从预编译->编译->汇编->连接
(1)预编译 gcc -E main.c -o main.i
     内部处理:宏定义处理、头文件包含的指令、删除注释、特殊符号的处理
(2)编译  gcc -S main.i -o main.s
     编译环节是对源代码进行语法分析,并优化产生对应的汇编代码
     生成符号、产生汇编代码   
(3)汇编  gcc -c main.s -o main.o
     将汇编语言翻译成二进制代码  生成可重定位的二进制文件

(4) 连接 gcc -o mian main.o 
     连接分为静态连接和动态连接 
     内部处理:合并段表  调整偏移量 合并符号表 完成符号的重定位

代码如下:

 int data1 = 10;
 int data2 = 0;
 int data3;

 static int data4 = 20;
 static int data5 = 0;
 static int data6;

 int main()
 {
     int a = 30;
     int b = 0;
     int c;
 
     static data7 = 40;
     static data8 = 0;
     static data9;
     return 0;
 }

预编译生成的 .i 文件如下:

# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "main.c"
int data1 = 10; 
int data2 = 0;
int data3;

static int data4 = 20; 
static int data5 = 0;
static int data6;

int main()
{
    int a = 30; 
    int b = 0;
    int c;

    static data7 = 40; 
    static data8 = 0;
    static data9;
    return 0;
}

编译生成的  .s 文件如下:

    .file   "main.c"
.globl data1
    .data
    .align 4
    .type   data1, @object
    .size   data1, 4
data1:
    .long   10  
.globl data2
    .bss
    .align 4
    .type   data2, @object
    .size   data2, 4
data2:
    .zero   4   
    .comm   data3,4,4
    .data
    .align 4
    .type   data4, @object
    .size   data4, 4
data4:
    .long   20  
    .local  data5
    .comm   data5,4,4
    .local  data6
    .comm   data6,4,4
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $30, -12(%ebp)
    movl    $0, -8(%ebp)
    movl    $0, %eax
    leave
    ret 
    .size   main, .-main
    .local  data9.1246
    .comm   data9.1246,4,4
    .local  data8.1245
    .comm   data8.1245,4,4
    .data
    .align 4
    .type   data7.1244, @object
    .size   data7.1244, 4
data7.1244:
    .long   40  
    .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
    .section    .note.GNU-stack,"",@progbits

汇编生成的 .o 文件如下:

^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^A^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@Ð^@^@^@^@^@^@^@4^@^@^@^@^@(^@  ^@^F^@U<89>å<83>ì^PÇEô^^^@^@^@ÇEø^@^@^@^@¸^@^@^@^@ÉÃ^@
^@^@^@^T^@^@^@(^@^@^@^@GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)^@^@.symtab^@.strtab^@.shstrtab^@.text^@.data^@.bss^@.comment^@.note.GNU-stack^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^[^@^@^@^A^@^@^@^F^@^@^@^@^@^@^@4^@^@^@^[^@^@^@^@^@^@^@^@^@^@^@^D^@^@^@^@^@^@^@!^@^@^@^A^@^@^@^C^@^@^@^@^@^@^@P^@^@^@^L^@^@^@^@^@^@^@^@^@^@^@^D^@^@^@^@^@^@^@'^@^@^@^H^@^@^@^C^@^@^@^@^@^@^@\^@^@^@^T^@^@^@^@^@^@^@^@^@^@^@^D^@^@^@^@^@^@^@,^@^@^@^A^@^@^@0^@^@^@^@^@^@^@\^@^@^@-^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^A^@^@^@5^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@<89>^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^Q^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@<89>^@^@^@E^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@^@^@^@^@8^B^@^@^P^A^@^@^H^@^@^@^M^@^@^@^D^@^@^@^P^@^@^@  ^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@H^C^@^@R^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^D^@ñÿ^@^@^@^@^@^@^@^@^@^@^@^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^B^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^C^@^H^@^@^@^D^@^@^@^D^@^@^@^A^@^B^@^N^@^@^@^D^@^@^@^D^@^@^@^A^@^C^@^T^@^@^@^H^@^@^@^D^@^@^@^A^@^C^@^Z^@^@^@^L^@^@^@^D^@^@^@^A^@^C^@%^@^@^@^P^@^@^@^D^@^@^@^A^@^C^@0^@^@^@^H^@^@^@^D^@^@^@^A^@^B^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^D^@;^@^@^@^@^@^@^@^D^@^@^@^Q^@^B^@A^@^@^@^@^@^@^@^D^@^@^@^Q^@^C^@G^@^@^@^D^@^@^@^D^@^@^@^Q^@òÿM^@^@^@^@^@^@^@^[^@^@^@^R^@^A^@^@main.c^@data4^@data5^@data6^@data9.1246^@data8.1245^@data7.1244^@data1^@data2^@data3^@main^@
~                                                                   

ELF文件

ELF文件:在计算机科学中,是一种用二进制文件,可执行文件,目标代码,共享库和核心转储格式文件。它由四部分构成分别是ELF头(ELF header)、程序头表(Program header table)、节(section)和节头表(section header table)。

file命令:查看文件头部信息
ll命令:和ls -l一样

readelf命令:读取ELF文件中信息
readelf -h:读取ELF文件头信息

 

readelf -s main.o

从图中可以看出:data.size = 000c 那么c / 4 = 3;.data段存储了3个数据
               bss.size = 0014 那么 14 / 4 = 5; .bss段存储了5个数据
但是:代码中有6个未初始化或者初始化为0的的数据,为何只有五个?

那么来了解一下c语言中的强符号和弱符号
强符号:初始化了的非静态变量
弱符号:未初始化的非静态变量
所以说代码中的int data3是一个未初始化的非静态变量 它是一个弱符号,它在存储中不占有.bss内存,会被强符号替代
注意上图中.bss 和.comment 段起始地址重合,这是因为.bss 在文件中不占内存,这时候
数据如何存储呢?
注意上图中的[7].symtab,这是数据生成的符号表,.bss 不占据实际的磁盘空间,只在
段表中记录大小,从而节约了磁盘的空间。在符号表中记录符号。当文件加载运行时,才分
配空间以及初始化。
在 elf 文件结构中,有一个字符串表.strtab,里面存放的是 elf 文件中各个段的名字以及
变量名等字符串,字符串表中记录了这些字符串以及对应的下标,需要用到这些字符串时,
直接用偏移下标去取就行了。段表中存放的段的名字这一项,就是存的.strtab 中对应字符串
的偏移。

链接有以下几个部分要做
1、 合并段表:将多个二进制可重定位文件中的段信息整合放到一个文件中
2、 调整段偏移:段表经过合并之后大小发生了变化,所以地址需要适当的偏移
3、 合并符号表:将多个二进制可重定位文件中的符号整合到一个文件中
4、 完成符号的重定位:连接器把每个符号定义与一个虚拟地址联系起来,然后
修改所有对这些符号的引用,使得它们指向这个存储位置,从而重定位这些

按照属性划分不同的段放在同一页,运行时按照 LOAD 页信息将段按照页读入到虚拟地址空间

 

以上就是编译链接的大体内容,希望能对你们有所帮助!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值