程序员的自我修养

折月煮酒 提交于 2020-11-04 16:45:03

章节目录

  • 静态链接
    – 编译和链接
    – 目标文件
    – 静态链接
    – 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文件来管理工程。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!