程序的生命周期:从.c文件到二进制文件

本文最后更新于:2022年9月4日 下午

一个.c文件是如何成为一个可执行二进制文件的?

文件后缀 被执行过程 工具 细节
.c 预处理 预处理器(cpp,c pre-processor) 宏替换、头文件展开、注释删除
.i 编译 ccl C语言程序转化为汇编语言程序(.s)
.s 汇编 编译器 汇编语言程序转化可重定位目标文件(.o)
.o 链接 ld(链接器) 将多个.o文件链接为一个可执行文件

预处理

使用cpp(C 预处理器)完成了:

  • 将.c文件转化为.i文件
    • 在这里.i文件只是一个后缀而已,本质上仍然是文本文件
  • 宏替换
  • 头文件展开
    • 找到#include的文件内容将其插入到.c文件中
  • 注释删除

将hello.c文件得到的预处理结果重定向到hello.i

1
cpp hello.c > hello.i

可以使用man cpp得到预处理器的相关信息

测试代码:

1
2
3
4
5
6
7
8
9
10
11
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
char *msg = "Hello, world!\n";
syscall(SYS_write, 1, msg, strlen(msg));

return 0;
}

编译

  • 使用编译器将.i文件转换为.s文件
  • 将C语言文本转换为汇编语言文本(Assembly Code)
  • 命令: gcc hello.i -S -o hello.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
        .file   "hello.c"
.text
.section .rodata
.LC0:
.string "Hello, world!\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
leaq .LC0(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call strlen@PLT
movq %rax, %rdx
movq -8(%rbp), %rax
movq %rdx, %rcx
movq %rax, %rdx
movl $1, %esi
movl $1, %edi
movl $0, %eax
call syscall@PLT
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
.file 源文件
.text 代码段
.global 全局变量
.data 存放已经初始化的全局和静态C 变量
.section .rodata 存放只读变量
.align 对齐方式
.type 表示是函数类型/对象类型
.size 表示大小
.long .string 表示是long类型/string类型

汇编

  • 编译器将汇编语言程序转化为可重定位目标文件
  • .s —> .o 指令为gcc -c hello.s -o hello.o
  • objdump 分析hello.o:objdump -d hello.o

链接

将多个.o文件链接为一个可执行文件

关于链接器的更多内容:man ld


程序的生命周期:从.c文件到二进制文件
http://gls.show/p/2e9a027c/
作者
郭佳明
发布于
2022年9月4日
许可协议