gcc编译

本文详细介绍了GCC编译过程,包括预处理、语法检查、汇编和生成目标代码的阶段。重点讲解了如何通过GCC选项进行语法检查、遵循特定C语言标准,以及汇编和生成ELF格式目标代码。同时,探讨了ELF文件的结构,如可重定位、可执行和共享库的不同,并推荐了用于分析ELF文件的工具。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、预处理

#define

#ifdef 

……

#endif

#include <>

宏定义、文件包含、条件编译等命令进行处理

 

代码优化,编译可执行文件变小,执行效率降低。

2、编译(翻译)

编译之前,C 语言编译器会进行词法分析、语法分析,接着会把源代码翻译成中间语言,即汇编语言。如果想看到这个中间结果,可以用 gcc -S。需要提到的是,诸如 Shell 等解释语言也会经历一个词法分析和语法分析的阶段,不过之后并不会进行“翻译”,而是“解释”,边解释边执行。

把源代码翻译成汇编语言,实际上是编译的整个过程中的第一个阶段,之后的阶段和汇编语言的开发过程没有什么区别。这个阶段涉及到对源代码的词法分析、语法检查(通过 -std 指定遵循哪个标准),并根据优化(-O)要求进行翻译成汇编语言的动作。

语法检查

如果仅仅希望进行语法检查,可以用 gcc-fsyntax-only 选项;如果为了使代码有比较好的可移植性,避免使用 gcc 的一些扩展特性,可以结合 -std-pedantic(或者 -pedantic-erros )选项让源代码遵循某个 C 语言标准的语法。这里演示一个简单的例子:

$ cat hello.c
#include <stdio.h>
int main()
{
    printf("hello, world\n")
    return 0;
}
$ gcc -fsyntax-only hello.c
hello.c: In function ‘main’:
hello.c:5: error: expected ‘;’ before ‘return’
$ vim hello.c
$ cat hello.c
#include <stdio.h>
int main()
{
        printf("hello, world\n");
        int i;
        return 0;
}
$ gcc -std=c89 -pedantic-errors hello.c    #默认情况下,gcc是允许在程序中间声明变量的,但是turboc就不支持
hello.c: In function ‘main’:
hello.c:5: error: ISO C90 forbids mixed declarations and code

语法错误是程序开发过程中难以避免的错误(人的大脑在很多情况下都容易开小差),不过编译器往往能够通过语法检查快速发现这些错误,并准确地告知语法错误的大概位置。因此,作为开发人员,要做的事情不是“恐慌”(不知所措),而是认真阅读编译器的提示,根据平时积累的经验(最好总结一份常见语法错误索引,很多资料都提供了常见语法错误列表,如《C Traps & Pitfalls》和编辑器提供的语法检查功能(语法加亮、括号匹配提示等)快速定位语法出错的位置并进行修改。

汇编

 

简述

汇编实际上还是翻译过程,只不过把作为中间结果的汇编代码翻译成了机器代码,即目标代码,不过它还不可以运行。如果要产生这一中间结果,可用 gcc -c,当然,也可通过 as 命令处理汇编语言源文件来产生。

汇编是把汇编语言翻译成目标代码的过程,如果有在 Windows 下学习过汇编语言开发,大家应该比较熟悉 nasm 汇编工具(支持 Intel 格式的汇编语言),不过这里主要用 as 汇编工具来汇编 AT&T 格式的汇编语言,因为 gcc 产生的中间代码就是 AT&T 格式的。

生成目标代码

下面来演示分别通过 gcc -c 选项和 as 来产生目标代码。

$ file hello.s
hello.s: ASCII assembler program text
$ gcc -c hello.s   #用gcc把汇编语言编译成目标代码
$ file hello.o     #file命令用来查看文件类型,目标代码可重定位的(relocatable),
                   #需要通过ld进行进一步链接成可执行程序(executable)和共享库(shared)
hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
$ as -o hello.o hello.s        #用as把汇编语言编译成目标代码
$ file hello.o
hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

gccas 默认产生的目标代码都是 ELF 格式的,因此这里主要讨论ELF格式的目标代码(如果有时间再回顾一下 a.outcoff 格式,当然也可以先了解一下,并结合 objcopy 来转换它们,比较异同)。

ELF 文件初次接触

目标代码不再是普通的文本格式,无法直接通过文本编辑器浏览,需要一些专门的工具。如果想了解更多目标代码的细节,区分 relocatable(可重定位)、executable(可执行)、shared libarary(共享库)的不同,我们得设法了解目标代码的组织方式和相关的阅读和分析工具。下面主要介绍这部分内容。

BFD is a package which allows applications to use the same routines to operate on object files whatever the object file format. A new object file format can be supported simply by creating a new BFD back end and adding it to the library.

binutils(GNU Binary Utilities)的很多工具都采用这个库来操作目标文件,这类工具有 objdumpobjcopynmstrip 等(当然,我们也可以利用它。如果深入了解ELF格式,那么通过它来分析和编写 Virus 程序将会更加方便),不过另外一款非常优秀的分析工具 readelf 并不是基于这个库,所以也应该可以直接用 elf.h 头文件中定义的相关结构来操作 ELF 文件。

下面将通过这些辅助工具(主要是 readelfobjdump),结合 ELF 手册来分析它们。将依次介绍 ELF 文件的结构和三种不同类型 ELF 文件的区别。

 

ELF 文件的结构

ELF Header(ELF文件头)
Program Headers Table(程序头表,实际上叫段表好一些,用于描述可执行文件和可共享库)
Section 1
Section 2
Section 3
...
Section Headers Table(节区头部表,用于链接可重定位文件成可执行文件或共享库)

对于可重定位文件,程序头是可选的,而对于可执行文件和共享库文件(动态链接库),节区表则是可选的。可以分别通过 readelf 文件的 -h-l-S 参数查看 ELF 文件头(ELF Header)、程序头部表(Program Headers Table,段表)和节区表(Section Headers Table)。

文件头说明了文件的类型,大小,运行平台,节区数目等。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值