C/C++——代码的编译和运行
每种高级语言都有对应的编译器,而且针对不同指令集架构的CPU会提供不同的编译器。本文以C语言为例,CPU指令集架构不做前提约束,实际上同一种语言也只有在狭义的编译阶段有所区别,其他阶段的处理,如二进制文件处理等待均类似。
1. 概述
函数调用时资源分配和进程调度
- 发生函数调用时,在执行该函数前,先将这次调用中需要用到的参数保存,方便取用
- 将控制权移交给这次调用的功能函数
- 根据情况为函数申请一定的本地存储空间,满足函数存储过程中的存储需求
- 执行该函数的功能调用
- 执行完成后,将结果数据保存好,便于主进程获取,同时还原函数执行过程中使用过的寄存器值,恢复先前分配的存储空间。
- 将控制权转移给主进程
- 变量的要素
- 名字
- 值
- 类型
- 地址
- 作用域
- 生存期
- 堆栈
假设一个过程,编译器需要使用多于4个参数寄存器和两个返回值寄存器。由于任务完成后必须消除踪迹,因此调用者使用的任何寄存器都必须恢复到过程调用前所存储的值。这种情况可以看成是需要将寄存器换出到存储器的一个例子。
换出寄存器的最理想的数据结构是栈——一种后进先出的队列,栈需要一个指针指向栈中最新分配的地址,以指示下一个过程放置换出寄存器的位置,或是寄存器旧值的存放位置。在每次寄存器进行保存或恢复时,栈指针以字为单位进行调整,由此将数据放入栈中称为压栈,从栈中移除数据称为出栈。
栈:被组织成后进先出队列形式并用于寄存器换出的数据结构
栈指针:指示栈中最近分配的地址的值,它指示寄存器被换出的位置,或寄存器旧值的存放位置
压栈:向栈中增加元素
出栈:向栈中移除元素
C语言标准和编译工具版本关系
C++标准和G++的关系
【C++】各版本标准与gcc、vs编译器对应关系_insightface 0.7.3 对应 gcc-CSDN博客
2. GCC编译
1 选项
参考:
- 编译选项
- 链接选项
- -nostdlib
链接时,请勿使用标准的系统启动文件或库。没有启动文件,只有指定的库才传递给链接器,选项指定系统库的链接,例如 -static-libgcc 或-shared-libgcc,否则也将被忽略。 - -lm
链接数学函数库
- 一些特殊写法
- 缺省的写法,例如某字符串前加weak
指如果定义了该字符串(可能是函数或者变量),则使用新的字符串,如果没有,则用weak后面的字符串
2 error
- undefined reference to 'xxxx'
缺少某个库,用 -l参数将库加入。Linux的库命名是一致的,一般为libxxx.so,或libxxx.a,libxxx.la,那么如要链接某个库就用-lxxx,去掉头lib及"."后面的so,la,a等即可。 因为数学函数位于libm.so库文件中(通常在/lib目录下),-lm选项告诉编译器,我们程序中用到的数学函数要到这个库文件里找. - error: confilicting types for ""
这种情况往往出现在函数实现文件中,未在头部声明或声明的位置位于函数使用的位置之后;
解决办法:将函数声明放到文件靠前位置;
3. 编译过程
每种高级语言都有对应的编译器,而且针对不同指令集架构的CPU会提供不同的编译器。本文以C语言为例,CPU指令集架构不做前提约束,实际上同一种语言也只有在狭义的编译阶段有所区别,其他阶段的处理,如二进制文件处理等待均类似。
C语言的编译有两种方式,一种是本地编译(在一个平台上编译该平台运行的程序),另一种是交叉编译(在一个平台上编译供另一个平台运行的程序)
- 编译的功能
- 将高级语言转换为处理器能够执行的二进制代码。
- 对编程语言进行语法检查核逻辑检查
- 分配寄存器和内存地址(存储器)
- 代码优化
- 编译过程
C语言的翻译可以分为四个阶段:预编译阶段编译阶段,汇编阶段,链接阶段
- 预编译阶段
主要处理文件中宏定义,注释,以及将头文件插入到主代码中,生成扩展名为“.i”的文件,替换原来的.c文件(原文件保留)。 - 编译阶段
将代码转化成汇编语言或某种中间代码。编译器首先会检查代码的规范性,是否有语法错误等,以确定代码实际要做的工作;检查完毕后转换为底层机器可处理的汇编语言,即生成.s文件替换.i文件。
该阶段会进行优化处理,除了对中间代码的结构进行优化外,还会充分利用硬件寄存器中存储的变量值,减少内存访问次数;根据指令执行特点(RSIC,CSIC,流水线等)对指令进行调整 - 汇编阶段
将汇编语言直接映射为二进制码,以二进制码格式的指令将会被打包封存成可重定位的目标程序的格式,生成.o文件替代原来的.s文件。.o文件由段组成,且至少有两个段:代码段和数据段。代码段主要包含程序的指令,数据段主要是各种全局变量或静态数据。
UNIX环境下会生成三个目标文件:
1) 可重定位文件:其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。
2) 共享的目标文件:这种文件存放了适合于在上下文里链接的代码和数据。
3) 可执行文件:包含了一个可以被操作系统创建一个进程来执行之的文件。
- 链接阶段
将多个.o文件合并整合成一个可执行文件。上图表现的是一个动态链接过程。
该阶段的三个步骤:
1)将代码和数据模块象征性地放入内存
2)决定数据和指令标签的地址
3)修补内部和外部引用
编译后生成的elf后续处理参考:C/C++——elf文件分析_KGback的博客-CSDN博客
- 2. 运行库和标准库
参考:glibc是什么_runtime是什么_喜欢数学一辈子的博客-CSDN博客
查询动态链接库参考链接:nm命令详解 - 二狗啸地 - 博客园
4. 代码编译错误
undefined reference to `__umoddi3'
undefined reference to '_modsi3'和`__udivdi3'问题的分析与解决办法_umodsi3-CSDN博客
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)