章节目录
- 静态链接
– 编译和链接
– 目标文件
– 静态链接
– windows COFF - 装载和动态链接
– 可执行文件的装载与进程
– 动态链接
– Linux共享库的组织
– Windows下的动态链接 - 库与运行库
– 内存
– 运行库
– 系统调用与API
– 运行库实现
一、编译和链接
从hello_world.c 到可执行文件(executable file),经历了编译、链接过程。这个过程分为4步:
- 预处理 Prepressing
- 编译 Compilation, Compile
- 汇编 Assembly, Assemble
- 链接 Linking, Link
1.1 预处理
处理“#”开始的预编译命令,例如包含头文件、宏的文本替换、#if 条件预处理、删掉注释,调试器需要的文件、行号信息,也在此时加入。
1.2 编译
预处理之后的文件,进行
- 词法分析
- 语法分析
- 语义分析
- 优化
- 生成汇编代码文件
词法分析
处理关键字、标识符(变量名)等
语法分析
是不是符合语法,例如:分号;,括号{},运算符(操作数,优先级)
语义分析
分析if,for, while,等逻辑。变量类型的匹配、转换。
优化
好的编译器会对代码进行优化。
例如,删去明显不可能执行的if分支。例如if(char > 1000),而char 范围在0-255。
例如,a = 2+3; 这样的语句很明显可以优化成a=5;
生成汇编代码文件
高级语言–>汇编语言
1.3 汇编
将汇编文件转变为机器码(指令)。
因为不同的CPU都有自己的指令体系,是由芯片厂家制定的,这就是CPU架构的概念,例如ARM架构。例如同样的MOV R0 R1; 翻译成ARM指令或Thumb指令的二进制值不同。指令,可以理解为集成电路实现的switch语句,一个指令进一个case分支。
所谓集成电路(IC)设计,就是用晶体管组成电路,实现选择、循环、顺序等逻辑。设计时用的是HDL(hardware description language)硬件描述语言,和C语言类似。
1.4 链接
直到汇编完成,都是每个c文件生成单独的二进制文件(.o文件),c文件之间互相调用关系还没有完成。连接器就是把.o文件通过他们的关系链接起来,最终生成.out文件
(.out是Linux的可执行文件(executable file)的格式,Window中是.exe文件)
例如a.c中的main()函数调用了b.c中的add(x,y)函数,那么链接之前,a.c并不知道add函数存不存在,在什么位置,于是把add函数的入口地址空着(默认0)。等链接器找到add函数,再把地址填到这里。
在简单的嵌入式系统中,这个地址就是实际的物理地址。嵌入式系统厂家,一般也不会把RAM地址设为0x0,例如是0x1000,那就需要给链接器提供这些信息。
1.5 总结
这样看来一个好的IDE(Intergrated Develop Environment),应该包括:
- 编辑器
写代码。好的编辑器还能给丰富的提示、语法检查等功能。 - 编译器(广义)
把代码生成可执行文件。包括:预处理器,编译器,链接器。好的编译器,会在编译出错时给出充分的错误信息。 - 调试器
程序运行出问题时debug。一般过程:设断点,控制执行,分析变量值,手动修改变量值,找出bug原因。好的调试器,能提供方便、丰富的调试工具,展示充分的信息。
嵌入式系统因为其特殊性,一般其调试器需要硬件联调,需要有硬件沟通PC和待调试设备,例如JTAG(J-link),SWD等。
在复杂工程中,链接器会需要链接脚本ld文件。或者编写make文件来管理工程。
来源:oschina
链接:https://my.oschina.net/u/4318872/blog/4701846