从C源代码到可执行文件的四个过程:预处理、编译、汇编、链接

从C源代码到可执行文件的四个过程:预处理、编译、汇编、链接

总览

在这里插入图片描述

我们将在Linux操作系统中,以C语言的Hello World程序为例,用gcc编译器分步执行这四个步骤。

我们有再熟悉不过的HelloWorld程序,hello.c

#include <stdio.h>

int main(){
    printf("Hellow World.\n");
    return 0;
}

预处理

预处理阶段 预处理器(cpp)根据以#字节开头的命令,修改原始的C程序,

执行预处理命令:gcc -E hello.c -o hello.i,我们得到由.c文件得到.i文件:hello.i

# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
# 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 424 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 427 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 428 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
# 429 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 425 "/usr/include/features.h" 2 3 4
# 448 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
# 449 "/usr/include/features.h" 2 3 4
# 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4

编译

编译阶段 编译器(cc1)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。

执行编译命令:gcc -S hello.i -o hello.s,我们得到由.i文件得到.s文件:hello.s,这就是汇编文件:

	.file	"hello.c"
	.text
	.section	.rodata
.LC0:
	.string	"Hellow World."
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	leaq	.LC0(%rip), %rdi
	call	puts@PLT
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
	.section	.note.GNU-stack,"",@progbits

汇编

汇编阶段 汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并保存在hello.o文件中,这是一个二进制文件,无法直接用文本编辑器查看。

执行编译命令:gcc -c hello.s -o hello.o,我们得到由.s文件得到.o文件:hello.o,可重定向文件文件,这个文件就不是文本文件了,因此无法展示。

至此以上三步其实可以由-c参数直接得到可重定向文件:gcc -c hello.c -o hello.o,以上是为了说明预处理和编译两步,专门分步进行,以查看输出。

链接

链接阶段 hello程序调用了printf函数,它来自C标准库,具体存在于一个已经预编译好的printf.o文件,链接器(ld)负责将这个文件与我们的hello文件合并起来。

执行链接命令gcc hello.o -o hello,我们有.s文件得到可执行文件hello,直接./hello执行即可在命令行打印输出Hellow World

Ref:CSAPP

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值