C/C++源程序到可执行程序的过程
源程序.cpp 预处理得到
预处理文件.i 编译得到
汇编文件.S 汇编得到
目标文件.o 链接得到
可执行文件
例子:main.cpp fun.cpp fun.h
#include <iostream>
#include "fun.h"
using namespace std; #define PI 3.14 int main()
{
print();
cout<<PI<<endl;
return ;
}
#ifndef _FUN_H_
#define _FUN_H_
void print();
#endif
#include <iostream>
#include "fun.h"
void print()
{
std::cout<<"hello,world"<<std::endl;
}
1. 预处理
g++ -E main.cpp -o main.i
main.i、fun.i:
对源程序其中的伪指令(以#开头的指令)和特殊符号进行处理
(1)宏定义指令
如 main.cpp中有 #define PI 3.14,预处理之后进行了替换
(2)条件编译指令
#ifdef、#ifndef、#else、#elif、#endif等,根据宏定义决定对哪些代码进行处理,避免重复的引用
(3)头文件包含指令
#include <xx.h> #include "xx.h"等
这些头文件中有大量的宏定义
(4)特殊符号
printf("Date:%s,Time:%s,File:%s,Line:%d,Func:%s\n",__DATE__,__TIME__,__FILE__,__LINE__,__FUNCTION__);
经过预处理,得到的.i文件没有宏定义、没有条件编译指令、没有特殊符号
2. 编译
g++ -S main.i -o main.S
预处理之后的文件只有一些数字、字符串及关键字的定义,经过g++编译程序:词法分析、语法分析、优化,生成汇编文件
3. 汇编
汇编代码汇编成机器指令
4. 链接
多个.o文件以及库文件链接成可执行文件
ld 一堆库文件 fun.o main.o -o a.out
必要的库可通过 g++ -v main.o 查看
g++ 最终通过调用 collect2来链接文件,collect2是对ld的封装
(1)静态链接
以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件。
将链接库的代码复制到可执行程序中
静态链接做的事:
①符号解析:将目标文件符号引用和定义联系起来(因为某些符号是引用其他模块的符号)
②重定位:编译器、汇编器生成从地址0开始的代码和数据,链接器把每个符号定义和一个存储器位置联系起来,然后修改所有对这些符号的引用,使得从另一个位置开始执行。
(2)动态链接
函数的定义在动态链接库或共享对象的目标文件中,在链接阶段,动态链接库只提供符号表等少量信息保证所有符号引用都有定义(不像静态链接直接复制过去),保证编译顺利通过。在可执行文件执行时,动态连接库将函数等内容映射到运行时相应进程的虚地址空间。
(3)目标文件
①可重定位目标文件:含二进制代码、数据,因引用了其他模块的符号而不能执行
②共享目标文件/动态库: .so文件
③可执行文件
(4)目标文件的格式 ELF文件
ELF头:描述文件系统字长、字节序、ELF头大小、目标文件类型、目标机类型等
.text:代码段,可执行二进制机器指令
.rodata:只读数据段,存常量如字符串等
.data:数据段,以明确初始化的全局数据(全局变量、静态变量),是静态内存分配
.bss:块存储段,未被明确初始化的全局数据,这些全局数据会初始化为0,是静态内存分配
上面的四个段会加载到内存中
.symtab:符号表,定义和引用的函数和全局变量
.rel.text:代码段需要重定位的信息,存储需要靠重定位修改位置的符号的汇总
.rel.data:数据段需要重定位的信息
.debug:gcc -g选项会生成此段
.line:源程序的行号映射 用于调试
.strtab:字符串表存储symtab、debug符号表中符号的名字
查看ELF文件内容、各段大小的命令:
readelf -a main
2 size main
gcc命令基本选项:
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
库的生成与使用:
(1)静态库
ar rcs fun.a fun1.o fun2.o
选项:r:把列表中的目标文件加入到静态库
c:若指定的静态库不存在则创建该文件
s:更新静态文件的索引,使之包含新加入的目标文件的内容
链接时:
gcc main.c -lfun.a -o main
gcc -L. main.c -o main
-L紧跟静态库路径
(2)动态库
gcc -shared -fPIC -o lib.so lib,c
选项的含义:
-shared:生成动态库
-fPIC:生成位置无关代码
链接时:
gcc main.c ./lib.so -o main
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
可执行文件在运行时:
除了代码段、数据段、BSS段,还有堆区和栈区
堆区:用于动态分配内存,用 malloc、free申请和释放
从低地址向高地址增长
链式存储
效率比栈低
栈区:由操作系统自动分配和释放,存储函数的参数值、局部变量的值等
从高地址向低地址增长
连续内存
最大容量固定
最新文章
- HibernateUtil.java
- mach 和 array 方法
- java的分层开发
- 每天一个linux命令--退出<;符号
- Windows 下Apace tomcat
- Spring学习1-初识Spring
- eclipse启动tomcat错误:A Java Exception has occurred(转)
- iis6兼容32位运行
- phonegap 附件下载及打开附件
- hdu 2680 Choose the best route
- xml--通过SAX解析XML
- Squares(哈希)
- 利用pyinstaller将python脚本打包发布
- Linux设置文件读写权限
- (NO.00001)iOS游戏SpeedBoy Lite成形记(九)
- bind、call和apply对比和使用
- 配置SSH使用秘钥登录
- css 悬浮框
- html5 选择多张图片在页面内预览并上传到后台
- 编写python的程序