【C语言】程序编译链接详解

目录

一、程序的翻译环境和执行环境

二、编译链接过程

2.1、程序编译过程

2.2、程序编译链接的阶段

2.2.1、预处理

2.2.2、编译

2.2.3、汇编

2.2.4、链接

2.2.5、整体过程

三、运行环境


一、程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境

第一种是翻译环境(由编译器完成),在这个环境中源代码转换为可执行的机器指令。

第二种是执行环境,它用于执行代码

二、编译链接过程

2.1、程序编译过程

一个源文件要经过编译,链接才能形成可执行程序。因此每个源文件经过编译器处理生成目标文件,多个生成的目标文件和链接库经过连接器处理生成可执行程序。

在vs2019下编译器是cl.exe,链接器是link.exe

连接器同时也会引入标准C函数库中任何被该程序所用到的函数

2.2、程序编译链接的阶段

2.2.1、预处理

1、进行头文件的包含,将头文件的相关内容包含进test.i文件中。(#include预处理指令)

在Linux环境下,头文件放在/usr/include目录下。

2、define定义符号的替换(#define预处理指令)

3、去注释

[hx@VM-24-7-centos 20240120-编译链接]$ vim test.c
                                                                                             
    1 #include<stdio.h>
    2 
    3 extern int Add(int,int);
    4 
    5 //定义MAX的值
    6 #define MAX 1000
    7 
    8 int main()
    9 {
   10     int x=MAX;                                                                                                     
   11     int a=10;
   12     int b=20;
   13     int c=Add(a,b);
   14     printf("%d\n",c);
   15 
   16     return 0;
   17 }
[hx@VM-24-7-centos 20240120-编译链接]$ gcc add.c -E -o add.i
[hx@VM-24-7-centos 20240120-编译链接]$ gcc test.c -E -o test.i
[hx@VM-24-7-centos 20240120-编译链接]$ ls
add.c  add.i  test.c  test.i

###  -E选项,让预编译后停下来
###  -o选项  编译结束后把结果放到test.i文件中

2.2.2、编译

把C语言代码翻译成汇编代码,进行词法分析,语法分析,语义分析,符号汇总

符号汇总一般是全局符号,全局变量,局部变量不会汇总进来(局部变量只能在函数内部使用)

本程序中,全局符号是Add,main

[hx@VM-24-7-centos 20240120-编译链接]$ gcc add.i -S
[hx@VM-24-7-centos 20240120-编译链接]$ gcc test.i -S
[hx@VM-24-7-centos 20240120-编译链接]$ ls
add.c  add.i  add.s  test.c  test.i  test.s
[hx@VM-24-7-centos 20240120-编译链接]$ vim test.s

### -S选项 编译结束后让程序停下来,结果保存在test.s中,不再往后走
    

2.2.3、汇编

符号汇总,形成符号表,并且将汇编指令转换成二进制指令最后生成test.o文件,汇编完成生成的目标文件经过连接器处理生成可执行程序。

[hx@VM-24-7-centos 20240120-编译链接]$ gcc add.i -c
[hx@VM-24-7-centos 20240120-编译链接]$ gcc test.i -c
[hx@VM-24-7-centos 20240120-编译链接]$ ls
add.c  add.i  add.o  add.s  test.c  test.i  test.o  test.s


### -c选项 汇编完成之后就停下来,结果保存在test.o中
2.2.4、链接

合并段表,合并符号表以及符号表的重定位(解决找到外部符号问题)

         符号表的合并和重定位,当最终生成可执行程序时,符号表也需要合并,main函数有确定的地址,Add出现了两个符号,要合并时需要重定位,但是知道test.o文件中Add的地址不是有效地址,是状态值,没有用处,但是add.o文件中符号表里的Add是有效地址,符号名一样就合并符号

        两个符号表合并就可以通过地址找到函数,解决的是如何跨文件找外部符号问题,可以链接其它文件的函数,当然外部符号没有定义的时候,就会出现链接报错。

在Linux环境下 test.o的可执行程序的格式是.elf,通过readelf工具可以看懂elf文件

通过加选项-s来查看test.o,add.o形成的符号表。

add.o test.o文件,按照elf文件格式组织的时候把文件分成各种各样的段,把相同段上的内容合并在一起,成为合并段表

[hx@VM-24-7-centos 20240120-编译链接]$ readelf test.o
Usage: readelf <option(s)> elf-file(s)
 Display information about the contents of ELF format files
 Options are:
  -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I
  -h --file-header       Display the ELF file header
  -l --program-headers   Display the program headers
     --segments          An alias for --program-headers
  -S --section-headers   Display the sections' header
     --sections          An alias for --section-headers
  -g --section-groups    Display the section groups
  -t --section-details   Display the section details
  -e --headers           Equivalent to: -h -l -S
  -s --syms              Display the symbol table
     --symbols           An alias for --syms
[hx@VM-24-7-centos 20240120-编译链接]$ readelf test.o -s

Symbol table '.symtab' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS test.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     9: 0000000000000000    74 FUNC    GLOBAL DEFAULT    1 main
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND Add
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND printf
[hx@VM-24-7-centos 20240120-编译链接]$ readelf add.o -s

Symbol table '.symtab' contains 9 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS add.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     8: 0000000000000000    20 FUNC    GLOBAL DEFAULT    1 Add

2.2.5、整体过程

        源文件要通过编译链接形成可执行程序,其中编译阶段就包括预处理,编译,汇编阶段生成目标源文件,链接是通过链接器将链接库和多个目标源文件链接在一起生成可执行程序,其中编译阶段的预处理过程是头文件包含,宏替换,去注释,编译阶段将C语言代码通过语法分析,词法分析,语义分析,符号汇总,最后生成汇编代码,汇编阶段就是将汇编代码翻译成二进制指令,生成符号表。链接阶段进行合并段表以及合并符号表和符号表的重定位。

        因此源文件经过编译链接,汇总符号,形成符号表,链接期间会把跨多个文件的符号进行链接,如果链接时有符号没有有效地址,就会有链接错误报错

三、运行环境

程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序 的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用 main 函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈( stack ),存储函数的局部变量和返回 地址。程序同时也可以使用静态(static )内存,存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。
4. 终止程序。正常终止 main 函数;也有可能是意外终止。
  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值