C - 从源码到可运行程序


环境

操作系统: Win10 编译系统: mingw-w64

前言

了解程序从源代码开始, 到生成可运行程序是怎么一个流程.

生命周期

C 程序主要经过这个几个流程:

  1. 预处理器
  2. 编译器
  3. 汇编器
  4. 链接器

最后生成可执行文件.

预处理器

让我们来编写一个 C 程序 hello.c

#include <stdio.h>

int main() 
{
          
   
    printf("hello, world
");
    return 0;
}

执行命令 gcc -E hello.c -o hello.i 将会得到预处理好的文件 hello.i, hello.i 包含了所引入的头文件 <stdio.h> 相关信息:

编译器

紧接着, 该编译器出场了, 执行命令 gcc -S hello.i -o hello.s

.file	"hello.c"
	.text
	.def	__main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
.LC0:
	.ascii "hello, world"
	.text
	.globl	main
	.def	main;	.scl	2;	.type	32;	.endef
	.seh_proc	main
main:
	pushq	%rbp
	.seh_pushreg	%rbp
	movq	%rsp, %rbp
	.seh_setframe	%rbp, 0
	subq	$32, %rsp
	.seh_stackalloc	32
	.seh_endprologue
	call	__main
	leaq	.LC0(%rip), %rcx
	call	puts
	movl	$0, %eax
	addq	$32, %rsp
	popq	%rbp
	ret
	.seh_endproc
	.ident	"GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
	.def	puts;	.scl	2;	.type	32;	.endef

生成的文件保存着 hello.c 对应的汇编代码.

汇编器

有了汇编代码, 那么就需要汇编器帮我们生成和机器相关的可重定位目标文件. 执行命令 gcc -c hello.s -o hello.o 则就会生成二进制文件 hello.o, 最后一步则就是链接器了.

链接器

链接器(Linker)是一个程序, 将一个或多个由编译器和汇编器生成的目标文件外加库链接为一个可执行文件. 目标文件包括机器码和链接器可用信息的程序模块. 简单的讲, 链接器的工作就是解析未定义的符号引用, 将目标文件的占位符替换为符号的地址. 链接器还要完成程序中各目标文件的地址空间组织, 这可能涉及重定位工作. —百度百科

例如我们的 hello.c 文件, 经过汇编器处理后会得到 hello.o 目标文件, 但我们还调用了一个系统函数 printf(), 所以还需要相对应的目标文件, 和我们自己编写的 hello.o 目标文件组合生成可执行目标程序, 链接器会自动帮我们寻找这些系统目标文件. 执行命令 gcc hello.o -o hello.exe

最后执行 hello.exe 就会打印出

总结

这里我们只是简单的了解程序是如何生成的, 以及相关的参数. gcc -E 预处理器 gcc -S 编译器 gcc -c 汇编器 gcc 链接器

经验分享 程序员 微信小程序 职场和发展