gcc介绍

编译系统(过程)

p7
p8

编译过程是将源代码转换成可执行文件的几个步骤的集合。每一步生成不同类型的文件,这些文件在最终的可执行程序中扮演不同的角色。以下是详细的步骤以及每个阶段产生的文件的作用:

1. 预处理(Preprocessing)

命令: gcc -E test.c -o test.i

文件: test.i

作用:

  • 预处理器处理 #include#define 和其他预处理指令。

  • 结果是一个展开的源文件,其中所有的宏已被展开,包含文件已被插入。

2. 编译(Compilation)

命令: gcc -S test.i -o test.s

文件: test.s

作用: - 编译器将预处理过的源文件(通常是 .i 文件,但可以直接使用 .c 文件)转换成汇编语言代码。 - 生成的汇编文件包含目标平台的汇编指令,但尚未转换为机器代码。

3. 汇编(Assembling)

命令: gcc -c test.s -o test.o

文件: test.o

作用: - 汇编器将汇编语言代码(.s 文件)转换为机器代码。 - 生成的目标文件(.o 文件)包含机器代码以及与程序相关的其他信息,如符号表和重定位信息。 - 目标文件尚未完全链接为可执行文件。它是可以被其他目标文件链接的中间文件。

4. 链接(Linking)

命令: gcc test.o -o test

文件: test

作用: - 链接器将一个或多个目标文件(.o 文件)和可能的库文件链接成一个最终的可执行文件。 - 处理符号解析和重定位。符号解析涉及到解决目标文件中引用的外部符号(例如库函数)的地址。 - 生成的可执行文件可以直接在操作系统上运行。

中间文件总结

  1. .i 文件(预处理输出):
    • 包含展开的源代码,所有宏和包含文件都被处理。
    • 用于检查预处理后的代码是否正确。
  2. .s 文件(汇编代码):
    • 包含汇编语言的源代码,描述了机器指令。
    • 用于查看编译器生成的汇编代码。
  3. .o 文件(目标文件):
    • 包含机器代码、符号表、重定位信息等。
    • 用于最终的链接步骤,是编译的中间产物。
  4. 可执行文件(通常没有文件扩展名):
    • 包含最终的机器代码,可以直接运行。
    • 经过链接器处理,所有符号都被解析,重定位信息已处理。

例子总结

假设 test.c 内容如下:

1
2
3
4
5
6
7
void f() {
// 空实现
}

int main() {
return 0;
}
  • 预处理: gcc -E test.c -o test.i
  • 编译: gcc -S test.c -o test.s
  • 汇编: gcc -c test.c -o test.o
  • 链接: gcc test.c -o test

解释: - test.i 是预处理后的源代码。 - test.s 是编译生成的汇编代码。 - test.o 是编译生成的目标文件。 - test 是最终生成的可执行文件,可以运行。


gcc 相关命令用法

GCC(GNU Compiler Collection)是一个强大的编译器,支持多种编程语言。以下是一些常用的 GCC 命令和选项,特别是用于编译 C 程序以及生成汇编文件的相关选项:

编译 C 程序

  1. 编译并链接
    1
    gcc -o output_executable source.c
    • -o output_executable:指定输出可执行文件的名称。
    • source.c:源文件。
  2. 仅编译,不链接
    1
    gcc -c source.c
    • -c:只编译源代码,==不链接==生成可执行文件。这会生成一个目标文件(source.o)。

生成汇编文件

  1. 生成汇编代码
    1
    gcc -S source.c
    • -S:将源代码编译为汇编代码,而不是目标文件。生成的汇编文件扩展名通常为 .s

预处理

  1. 仅进行预处理
    1
    gcc -E source.c -o source.i
    • -E:仅执行预处理,并将结果输出到指定文件。

显示编译信息

  1. 显示编译过程中调用的命令
    1
    gcc -v source.c
    • -v:显示编译过程中的详细信息。
  2. 显示预定义宏
    1
    gcc -dM -E - < /dev/null
    • -dM:显示所有预定义的宏。
    • -E:执行预处理。

优化选项

  1. 优化代码
    1
    2
    3
    gcc -O1 source.c -o output_executable
    gcc -O2 source.c -o output_executable
    gcc -O3 source.c -o output_executable
    • -O1, -O2, -O3:分别表示不同级别的优化。

调试信息

  1. 生成调试信息
    1
    gcc -g source.c -o output_executable
    • -g:生成调试信息,用于调试器(如 gdb)。

其他常用选项

  1. 定义宏
    1
    gcc -DNAME=value source.c -o output_executable
    • -DNAME=value:定义一个预处理宏。
  2. 包含目录
    1
    gcc -I/path/to/include source.c -o output_executable
    • -I/path/to/include:指定额外的头文件搜索路径。
  3. 链接库
    1
    gcc -L/path/to/lib -lname source.c -o output_executable
    • -L/path/to/lib:指定库文件搜索路径。
    • -lname:链接名为 libname.solibname.a 的库。

实例

假设有一个简单的 C 程序文件 main.c,我们可以使用以下命令:

  1. 编译并链接生成可执行文件

    1
    gcc -o my_program main.c

  2. 生成汇编文件

    1
    gcc -S main.c

  3. 仅编译为目标文件

    1
    gcc -c main.c

  4. 进行优化编译

    1
    gcc -O2 -o my_program main.c

  5. 生成带有调试信息的可执行文件

    1
    gcc -g -o my_program main.c

这些命令和选项可以帮助你在不同的场景下灵活使用 GCC 编译器。


objdumphexdump 是两个在软件开发和分析中非常有用的命令行工具。它们用于处理和查看二进制文件的内容,但用途和输出方式不同。下面是这两个命令的详细介绍及示例说明。


相关常用的代码分析工具

objdump

objdump 是一个用于显示二进制文件的内容的工具,尤其是可执行文件、目标文件和库文件。它可以显示反汇编代码、符号表、段信息等。objdump 常用于调试和逆向工程。

常用选项

  • -d:反汇编可执行文件或目标文件的代码。
  • -S:在反汇编代码中插入源代码(如果可用)。
  • -t:显示符号表。
  • -h:显示段头信息。
  • -x:显示所有头信息。

示例

假设有一个简单的 C 文件 hello.c

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

void hello() {
printf("Hello, World!\n");
}

int main() {
hello();
return 0;
}

编译成可执行文件 hello

1
gcc -o hello hello.c

使用 objdump 查看反汇编代码:

1
objdump -d hello

输出可能如下所示(部分):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
hello:     file format elf64-x86-64


Disassembly of section .text:

0000000000001139 <hello>:
1139: 55 push %rbp
113a: 48 89 e5 mov %rsp,%rbp
113d: bf 00 00 00 00 mov $0x0,%edi
1142: e8 00 00 00 00 callq 0 <puts@plt>
1147: 90 nop
1148: 5d pop %rbp
1149: c3 retq

000000000000114a <main>:
114a: 55 push %rbp
114b: 48 89 e5 mov %rsp,%rbp
114e: e8 f0 ff ff ff callq 1139 <hello>
1153: b8 00 00 00 00 mov $0x0,%eax
1158: 5d pop %rbp
1159: c3 retq

hexdump

hexdump 是一个用于查看文件的十六进制表示的工具。它可以显示文件内容的十六进制值及其对应的 ASCII 字符。hexdump 常用于查看和分析二进制文件或数据文件的内容。

常用选项

  • -C:以十六进制和 ASCII 字符显示文件内容。
  • -n:指定读取的字节数。
  • -v:显示所有行(默认情况下,连续相同的行会被压缩)。

示例

假设有一个文本文件 example.txt,内容如下:

1
Hello, World!

使用 hexdump 查看其十六进制表示:

1
hexdump -C example.txt

输出可能如下所示:

1
2
00000000  48 65 6c 6c 6f 2c 20 57  6f 72 6c 64 21 0a        |Hello, World!.|
0000000e

其中,左侧是文件的偏移地址,中间是文件内容的十六进制表示,右侧是对应的 ASCII 字符。

总结

  • objdump:用于分析和反汇编二进制文件,适合调试和逆向工程。
  • hexdump:用于查看文件的十六进制表示,适合查看和分析文件的低级内容。

这两个工具在不同的情况下都有很大的用处,可以帮助开发者和分析人员更好地理解和处理二进制文件。


c 程序中内联汇编代码

在 C 程序中插入汇编代码有两种主要的方法:内联汇编(Inline Assembly)汇编语言文件(Assembly Language Files)。这两种方法允许在 C 程序中嵌入汇编代码,但它们的用法和应用场景有所不同。下面是对这两种方法的详细说明:

1. 内联汇编(Inline Assembly)

内联汇编允许在 C 代码中直接嵌入汇编指令。这种方法适用于在 C 程序中需要插入少量汇编代码的情况。它使得在一个 C 函数中直接嵌入汇编代码成为可能。

语法

在 GCC 中,内联汇编使用 __asm__asm 关键字。可以使用以下语法:

1
asm("assembly code" : output operands : input operands : clobbered registers);
  • "assembly code": 要插入的汇编代码。
  • output operands: 说明汇编代码将写入哪些 C 变量(如果有的话)。
  • input operands: 说明汇编代码将读取哪些 C 变量(如果有的话)。
  • clobbered registers: 说明汇编代码将修改哪些寄存器(如果有的话)。

示例

下面是一个在 C 代码中使用内联汇编的示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main() {
int a = 10;
int b;

// 内联汇编代码:将 a 的值加到 b 中
asm("addl %1, %0" : "=r" (b) : "r" (a), "0" (b));

printf("The result is %d\n", b);
return 0;
}

解释: - addl %1, %0 是要执行的汇编指令,将 a 的值加到 b 中。 - "=r" (b) 表示 b 是一个输出操作数,使用一个通用寄存器。 - "r" (a) 表示 a 是一个输入操作数,也使用一个通用寄存器。 - "0" (b) 表示 b 在汇编代码中也是一个输入操作数,但也用作输出操作数,0 表示它是输出操作数的寄存器的相同位置。

2. 汇编语言文件(Assembly Language Files)

汇编语言文件是使用汇编语言编写的独立文件,通常具有 .s.asm 扩展名。这种方法适用于需要大量汇编代码或需要将汇编代码与 C 代码分开的情况。

使用方法

  1. 创建汇编语言文件:

    创建一个名为 example.s 的汇编文件,内容如下:

    1
    2
    3
    4
    5
    .global my_function
    .text
    my_function:
    movl $42, %eax
    ret

    解释:

    • .global my_functionmy_function 声明为全局符号,使其可以被其他文件引用。
    • movl $42, %eax 将值 42 加载到寄存器 %eax
    • ret 返回到调用函数的地方。
  2. 在 C 程序中声明和调用汇编函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>

    extern int my_function();

    int main() {
    int result = my_function();
    printf("The result is %d\n", result);
    return 0;
    }
  3. 编译和链接:

    编译和链接汇编语言文件和 C 文件:

    1
    2
    gcc -c example.s -o example.o
    gcc -o main main.c example.o

    这将生成可执行文件 main,其中包含汇编和 C 代码的混合。

总结

  • 内联汇编:直接在 C 代码中插入汇编指令,适用于少量汇编代码和需要直接与 C 变量交互的场景。
  • 汇编语言文件:将汇编代码放在独立文件中,适用于较复杂的汇编代码或需要与多个 C 文件分开的情况。

这两种方法各有其优点和适用场景,可以根据具体需求选择使用。


gcc介绍
http://example.com/2024/09/07/gcc介绍/
作者
JunBin Liang
发布于
2024年9月7日
许可协议