当前位置:   article > 正文

预处理编译汇编链接(程序运行过程中的细节)_可以在汇编文件.s中使用预编译吗

可以在汇编文件.s中使用预编译吗

1.预处理过程

2主要处理那些源代码文件中的以“#”开始的预编译指令。如“#include”、“#define”等,主要处理规则如下:
将所有的“#define”删除,并且展开所有的宏定义。
处理所有条件预编译指令,比如“#if”、“#ifdef”、“#elif”、“#else”、“#endif”
处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。注意,这个过程是递归进行的,也就是说被包含的文件可能还包含其他文件。
删除所有的注释“//”和“/* */”。
添加行号和文件名标识,比如#2“hello.c”2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
保留所有的#pragma编译器指令,因为编译器须要使用它们。
经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件.所以我们无法判定宏定义是否正确或头文件包含时候正确.

2.编译:

编译可以分为词法分析,语法分析,语义分析,中间代码以及目标代码优化后生产的相应的的代码文件.

编译是将高级语言变成汇编代码.编译后的文件是.s文件.

汇编代码就是将高级语言翻译成计算机应该对应的操作,例如压入esi  eds或者是移动某个值到寄存器里进行操作.

2.1词法分析

首先源代码被输入到扫描器里,经过扫描器之后程序被拆分,变成了很多个记号.例如:array[i]就会被拆成array [  i  ]这四个记号,

2.2语法分析

语法分析器将对扫描器产生的记号进行语法分析,产生语法树,语法树是以表达式为节点的树,能将一整个语句连接起来.

例如:array[index] = (index + 4) * (2 + 6)

语法树如下

 在语法分析中把把很多运算符的优先级也确定下来了,比如确定小括号的优先级最高,运算时先计算小括号内的内容,*在这个语句中是乘法运算,在指针里也会用,是解引用又或者是定义指针时使用.他的含义也是在语法分析中确定的.还有例如括号不匹配,表达式缺少操作符等也是在此阶段检查出来的.

语法分析是找那些外表的错,比如少个括号,少个分号,或者写*的时候不小心写了两个**

或者手误多打了一个无用字符.

2.3语义分析

语义分析器完成

语法分析仅仅是完成了表达式语法层面的分析,也就是检测这个操作符不符合语法,在语法层面是否能通过..但是他并不了解这句话的真正是否有意义,比如c语言里两个指针做乘法是没有意义的,但是他是合法的.

而语义分析是找表达式内部的错误,比如

int a=10;  double b=3,14;  

int a=b;这个是在语义分析里检测出来的,在语法层面他是合法的,在语义方面经过类型转换他也是合法的,所以语义层面会进行类型转换.

再比如把一个指针变量付给一个整形这就是错误的,类型转换也不管用.

以上都是静态语义:

动态语义分析是再运行期才能检测的,比如将0作为除数.

2.4中间代码生成:中间代码已经很接近目标代码,中间代码进行的操作是将一些部分优化,例如上述的2+6;在中间代码里直接被替换为8

2.5目标代码生成与优化

代码生成器将中间代码转换成机器代码...这个过程十分依赖与机器,因为不同的机器有着不同的字长,寄存器等等.最后目标代码优化器对上述的目标代码进行优化,比如选择合适的寻址方式,使用位移代替乘法运算,删除多余的指令等

3汇编

简单的说就是把编译后的汇编代码转换成机器码

4.链接,由链接器完成

链接器的作用是链接各个小的文件组成一个大的文件

例如main.c里调用了func模块里的foo()函数,在编译时都是单独编译的,在编译main.c时并不知道

foo()函数在哪,所以他会把调用foo函数的目标地址搁置,等到链接的时候,连接器会找到在这个函数的地址.填入main.c里....如果func模块被重新编译,foo函数的地址也会发生改变.即使这样链接器也能找到函数入口地址.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/413602
推荐阅读
相关标签
  

闽ICP备14008679号