编译器、连接器学习笔记--(二)--编译

本文只记录学习过程中整理后的知识结构,不涉及具体细节,具体细节参考man手册和相关书籍,我再怎么说肯定都不如它们说的正确。

内容很浅,如果需要详细细节的可以点叉叉了,对此表示抱歉。


而且本来想写的详细一些,但是写着写着就跑题了,而且因为修改了多次,结果感觉中间错误很多


一、简单介绍

编译过程很复杂,而且不同的编程语言的编译过程也有所不同。

但是万变不离其踪,该有的过程还是得有,这个过程就是:

(Source Code)-->Scanner-->(Tokens)-->Parser-->(Syntax Tree)-->Semantic Analyzer-->(Commented Syntax Tree)-->Source Code Optimizer-->(Intermediate Representation)-->Code Generator-->(Target Code)-->Code Optimizer-->(Final Target Code)
这个过程很长,大致的过程就是:

扫描(词法分析)--》语法分析--》语义分析--》源代码优化--》源代码优化--》代码生成--》目标代码优化

1、1 词法分析

源代码被输入到扫描器(Scanner)将代码分割成一系列的记号(Token)。

例如:lex就是一个词法扫描器。

1、2 语法分析

在1、1中产生的标记,被送入语法分析器,产生语法树(Syntax Tree)

例如:yacc就是一个语法分析器


1、3 语义分析

这部分工作由语义分析器完成,但是它能分析的仅仅是静态语义。


1、4 源码优化

这部分由源码优化器完成,生成相应的中间代码。

常见中间代码有:三地址码,P -码等


1、1~1、4中的内容由被归纳成编译器前端,主要负责产生机器无关的中间代码。


1、5目标代码

这部分由代码生成器和目标代码优化器完成


 1、5中的内容又被划分到编译器后端。主要将中间码变成机器码。


上面的只是一些概念性的东西,其实也没什么大用。

编译过程其实很复杂,不仅和源代码使用的语言类型有关,还和具体的CPU体系相关,所以就以C语言为例,使用GCC编译,CPU是X86架构,下面分两个部分介绍:

(1)从C源码到目标文件

(2)分析目标文件


使用工具:

gcc、objdump,readelf。



2、从C源码到目标文件

2.1 预编译

功能:

  • 宏展开
  • 处理与编译指令,如“#if”,“#ifdef”等
  • 删除注释
  • 添加行号--便于编译时候产生调试用的行号信息和产生错误时候能够显示行号
  • 其他


使用指令1编译代码1,得到test.i,内容如下:

# 1 "test.c"
# 1 "<command-line>"
# 1 "test.c"

int main()
{

    int a = 100;
    returun;
}

与test.c比较,容易发现

  • 宏定义被展开
  • 注释被删除
  • 预编译指令也被处理
  • 注:这里没有使用头文件

注意:预编译不检查任何错误,测试代码中,return语句拼写错误,并且不带返回值,但是可以执行成功。


2.2 编译

功能

生成汇编源代码


使用指令2编译代码1,得到test.s,其内容如下:

        .file   "test.c"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        subl    $16, %esp
        movl    $100, -4(%ebp)
        movl    $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.7.1 20120721 (prerelease)"
        .section        .note.GNU-stack,"",@progbits

这个是X86下的汇编原代码。以后如果开始看链接过程,就需要对这个语法有一定了解。

汇编我也学的不怎么样。感觉比较重要的就是:

(1)弄明白ebp和esp寄存器作用,因为后面涉及到栈的操作,尤其是函数调用时候的栈操作。

(2)弄明白eax,ebx……几个寄存器的作用,尤其是eax寄存器,系统调用以及函数返回值都需要借助它保存一些临时变量。

(3)当然还有几个在代码中没有体现的,段寄存器和控制寄存器,内存寻址都依靠这些寄存器。

其他的基本看名字都能猜明白是什么意思。应该压力不大了。


2.3 汇编

功能:

将汇编源代码,编译成可执行指令


使用指令3编译代码1,得到test.o文件

使用指令4,查看得到的test.o文件,显示如下:

00000000  7f 45 4c 46 01 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
00000010  01 00 03 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  fc 00 00 00 00 00 00 00  34 00 00 00 00 00 28 00  |........4.....(.|
00000030  0b 00 08 00 55 89 e5 83  ec 10 c7 45 fc 64 00 00  |....U......E.d..|
00000040  00 b8 00 00 00 00 c9 c3  00 47 43 43 3a 20 28 47  |.........GCC: (G|
00000050  4e 55 29 20 34 2e 37 2e  31 20 32 30 31 32 30 37  |NU) 4.7.1 201207|
00000060  32 31 20 28 70 72 65 72  65 6c 65 61 73 65 29 00  |21 (prerelease).|
00000070  14 00 00 00 00 00 00 00  01 7a 52 00 01 7c 08 01  |.........zR..|..|
00000080  1b 0c 04 04 88 01 00 00  1c 00 00 00 1c 00 00 00  |................|
00000090  00 00 00 00 14 00 00 00  00 41 0e 08 85 02 42 0d  |.........A....B.|
000000a0  05 50 c5 0c 04 04 00 00  00 2e 73 79 6d 74 61 62  |.P........symtab|
000000b0  00 2e 73 74 72 74 61 62  00 2e 73 68 73 74 72 74  |..strtab..shstrt|
000000c0  61 62 00 2e 74 65 78 74  00 2e 64 61 74 61 00 2e  |ab..text..data..|
000000d0  62 73 73 00 2e 63 6f 6d  6d 65 6e 74 00 2e 6e 6f  |bss..comment..no|
000000e0  74 65 2e 47 4e 55 2d 73  74 61 63 6b 00 2e 72 65  |te.GNU-stack..re|
000000f0  6c 2e 65 68 5f 66 72 61  6d 65 00 00 00 00 00 00  |l.eh_frame......|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
下文忽略
………………………………
内容很乱
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值