メインコンテンツへスキップ
  1. ノート/
  2. ツールとデプロイ/

gcc 紹介

·3735 文字·8 分· loading · loading · · ·
ICE345
著者
ICE345
CS Student | System | Linux | OCaml
この記事は中国語版をもとにした日本語版メモです。コマンド、コード、数式、画像リンクは原文の意味を壊さないように保持し、説明文と見出しを日本語向けに整理しています。

コンパイルシステム(过程)
#

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 内容以下:

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. コンパイル并链接

    gcc -o output_executable source.c
    • -o output_executable:指定输出可执行ファイル的名称。
    • source.c:源ファイル。
  2. 仅コンパイル,不链接

    gcc -c source.c
    • -c:只コンパイル源コード,==不链接==生成可执行ファイル。这会生成一个目标ファイル(source.o)。

生成汇编ファイル
#

  1. 生成汇编コード
    gcc -S source.c
    • -S:将源コードコンパイル为汇编コード,而不是目标ファイル。生成的汇编ファイル扩展名通常为 .s

预处理
#

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

显示コンパイル信息
#

  1. 显示コンパイル过程中调用的コマンド

    gcc -v source.c
    • -v:显示コンパイル过程中的详细信息。
  2. 显示预定义宏

    gcc -dM -E - < /dev/null
    • -dM:显示所有预定义的宏。
    • -E:执行预处理。

优化选项
#

  1. 优化コード
    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. 生成调试信息
    gcc -g source.c -o output_executable
    • -g:生成调试信息,用于调试器(如 gdb)。

其他常用选项
#

  1. 定义宏

    gcc -DNAME=value source.c -o output_executable
    • -DNAME=value:定义一个预处理宏。
  2. 包含ディレクトリ

    gcc -I/path/to/include source.c -o output_executable
    • -I/path/to/include:指定额外的头ファイル搜索パス。
  3. 链接库

    gcc -L/path/to/lib -lname source.c -o output_executable
    • -L/path/to/lib:指定库ファイル搜索パス。
    • -lname:链接名为 libname.solibname.a 的库。

实例
#

假设有一个简单的 C 程序ファイル main.c,我们できます使用以下コマンド:

  1. コンパイル并链接生成可执行ファイル

    gcc -o my_program main.c
  2. 生成汇编ファイル

    gcc -S main.c
  3. 仅コンパイル为目标ファイル

    gcc -c main.c
  4. 进行优化コンパイル

    gcc -O2 -o my_program main.c
  5. 生成带有调试信息的可执行ファイル

    gcc -g -o my_program main.c

这些コマンド和选项できます帮助你在不同的场景下灵活使用 GCC コンパイル器。


objdumphexdump 是两个在软件开发和分析中非常有用的コマンド行ツール。它们用于处理和確認二进制ファイル的内容,但用途和输出方式不同。下面是这两个コマンド的详细紹介及例説明。


相关常用的コード分析ツール
#

objdump
#

objdump 是一个用于显示二进制ファイル的内容的ツール,尤其是可执行ファイル、目标ファイル和库ファイル。它できます显示反汇编コード、符号表、段信息等。objdump 常用于调试和逆向工程。

常用选项
#

  • -d:反汇编可执行ファイル或目标ファイル的コード。
  • -S:在反汇编コード中插入源コード(もし可用)。
  • -t:显示符号表。
  • -h:显示段头信息。
  • -x:显示所有头信息。

#

假设有一个简单的 C ファイル hello.c

#include <stdio.h>

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

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

コンパイル成可执行ファイル hello

gcc -o hello hello.c

使用 objdump 確認反汇编コード:

objdump -d hello

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

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,内容以下:

Hello, World!

使用 hexdump 確認其十六进制表示:

hexdump -C example.txt

输出可能以下所示:

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 关键字。できます使用以下语法:

asm("assembly code" : output operands : input operands : clobbered registers);
  • "assembly code": 要插入的汇编コード。
  • output operands: 説明汇编コード将写入哪些 C 变量(もし有的话)。
  • input operands: 説明汇编コード将读取哪些 C 变量(もし有的话)。
  • clobbered registers: 説明汇编コード将変更哪些寄存器(もし有的话)。

#

下面是一个在 C コード中使用内联汇编的例:

#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 的汇编ファイル,内容以下:

    .global my_function
    .text
    my_function:
        movl $42, %eax
        ret

    解释:

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

    #include <stdio.h>
    
    extern int my_function();
    
    int main() {
        int result = my_function();
        printf("The result is %d\n", result);
        return 0;
    }
  3. コンパイル和链接:

    コンパイル和链接汇编语言ファイル和 C ファイル:

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

    这将生成可执行ファイル main,其中包含汇编和 C コード的混合。

まとめ
#

  • 内联汇编:直接在 C コード中插入汇编指令,适用于少量汇编コード和必要直接与 C 变量交互的场景。
  • 汇编语言ファイル:将汇编コード放在独立ファイル中,适用于较复杂的汇编コード或必要与多个 C ファイル分开的情况。

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