程序的编译、链接过程详解

   
   
   
在linux环境下,我们运行一个程序,使用gcc编译时假设函数名为main.c,

gcc -o main main.c

./main

上述过程我们可以分成四个步骤  预编译->编译->汇编->链接

(基准为x86体系下,32位操作系统linux内核)

源代码运行的时候 

它的

进程在内存上的布局为程序的编译、链接过程详解

首先我们先写个源程序;

#include<stdio.h>

int a=10;  //存放在data

int b=0;//存放在bss

int c;//存放在bss

extern int d;//UND未知


int main()

{

    char *p="hello world";//存放在rodata段

    int e=a;//代码段

    int f=d;//代码段

    printf("%d",fun(a,b));//.text

    return 0;

}

sum.c

int fun(int a,int b)//.text

{

    return a+b;

}


text段存放的是代码段;

rodata段存放在代码段.text,常量不一定就放在rodata里,有的立即数直接编码在指令里;rodata在多个进程间是共享的,可以提高空间利用率;

data段存放的是全局初始化且不为0的常量;

而bss段存放的是全局未初始化或初始化为0的量;

堆区是动态开辟的空间。

而argc和argv是主函数的参数;

程序的编译、链接过程详解

第一步主要是下列四个步骤;

预编译:

展开所有的宏定义,处理含有#部分的代码,还有删除所有的注释//和/* */。添加行号和文件名标识。比如#2  “hello .c”还有保留所有的#progma编译器指令。

编译:

进行代码的优化还有符号的汇总(符号表)以及语义分析 语法分析  词义分析及优化后生成相应的汇编代码文件。

汇编:

将指令转成当地操作系统的机器码;

生成可重定向的目标文件:x86体系下的.obj  和unix下的.o文件

问题:为什么.o和.obj文件不能直接执行呢?

因为变量转成符号,符号表的符号地址没有分配出来,所以不能直接执行。

然后进行第二个步骤:

链接过程:

将第一个步骤所生成的.o文件里的段整合在一起,进行【符号解析】,符号解析指的是将每个符号引用刚好和一个符号定义联系起来。对符号表里的未定义的符号找到其定义的地方,代码段中,对所有指令未有其定义的符号都将其变为正确的地址例如extern行的代码以及main函数中的printf。解析正确后,再进行【符号重定位】,对其分配相应的虚拟地址。所有符号都拥有其正确的虚拟地址后,然后生成最终可执行的.exe文件,其运行的时候只需要代码段和数据段。