您的位置:首页 > 运维架构 > Linux

Linux C程序的预处理、编译、汇编、链接及运行过程

2019-03-21 16:36 585 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_39982235/article/details/88718992

Linux C程序的预处理、编译、汇编、链接及运行过程

Hello Word 程序直接编译运行过程

在Linux系统下,任意目录内创建一个简单的C程序,命名为hello.c,其代码如下:

1 #include <stdio.h>
2 int main(){
3   //这里有个注释
4   printf("Hello Word\n");
5   return 0;
6 }

编译代码,生成可执行文件 a.out:

XXXX@ubuntu:~/hello$ gcc hello.c
XXXX@ubuntu:~/hello$ ls
a.out  hello.c

运行可执行文件a.out ,生成结果:

XXXX@ubuntu:~/hello$ ./a.out
Hello Word

以上是一个程序最简单、最快捷的编译运行方式,但是在实际上,程序从代码到机器可执行的过程中,涉及预处理、编译、汇编、链接及运行等过程,了解这些过程是十分有必要的。

预处理

对上面的程序hello.c进行预处理过程,通常会进行以下操作:
1、删除程序里的注释内容;
2、把头文件的内容复制到预处理指令位置。

对==.c==文件的预处理,可以采用下述方法:

XXXX@ubuntu:~/hello$ gcc -E hello.c -o hello.i
XXXX@ubuntu:~/hello$ ls
hello.c  hello.i

说明:
1、gcc -E filename.c 表示对一个.c文件进行预处理,E必须大写
2、gcc -E filename.c -o filename.i 表示把预处理文件命名为filename.i,此处的 -o 必须小写
3、预处理文件用 filename.i来表示。

1 # 1 "<built-in>"
2 # 1 "<command-line>"
3 # 1 "/usr/include/stdc-predef.h" 1 3 4
4 # 1 "<command-line>" 2
5 # 1 "hello.c"
6 # 1 "/usr/include/stdio.h" 1 3 4
7 # 27 "/usr/include/stdio.h" 3 4
8 # 1 "/usr/include/features.h" 1 3 4
9 # 367 "/usr/include/features.h" 3 4
10 # 1 "/usr/include/i386-linux-gnu/sys/cdefs.h" 1 3 4
11 # 410 "/usr/include/i386-linux-gnu/sys/cdefs.h" 3 4
12 # 1 "/usr/include/i386-linux-gnu/bits/wordsize.h" 1 3 4
13 # 411 "/usr/include/i386-linux-gnu/sys/cdefs.h" 2 3 4
14 # 368 "/usr/include/features.h" 2 3 4
15 # 391 "/usr/include/features.h" 3 4
16 # 1 "/usr/include/i386-linux-gnu/gnu/stubs.h" 1 3 4
17
18
19

……
855
856
857
858 # 3 "hello.c"
859 int main(){
860
861   printf("Hello Word\n");
862   return 0;
863 }

上述代码段中,行号1~858所代表的代码即是 ==#include <stdio.h>==所指向的内容,行号859~863的代码即是自己编写的main函数,可以看到,所标示的注释内容被清空了。

编译

预处理过程只是对文件的一个预处理,并没有进行语法的检查等。而且此时代码还只是C语言,需要先转换成汇编语言,这样的过程叫做编译。

XXXX@ubuntu:~/hello$ gcc -S hello.i -o hello.s
XXXX@ubuntu:~/hello$ ls
hello.c  hello.i  hello.s

说明:
1、gcc -S filename.i 表示对一个.i文件进行编译,S必须大写
2、gcc -S filename.i -o filename.s 表示把编译后的文件命名为filename.s,此处的 -o 必须小写
3、编译后的文件用 filename.s来表示。

用vim指令打开hello.s文件

1         .file   "hello.c"
2         .section        .rodata
3 .LC0:
4         .string "Hello Word"
5         .text
6         .globl  main
7         .type   main, @function
8 main:
9 .LFB0:
10         .cfi_startproc
11         leal    4(%esp), %ecx
12         .cfi_def_cfa 1, 0
……
31         .cfi_def_cfa 4, 4
32         ret
33         .cfi_endproc
34 .LFE0:
35         .size   main, .-main
36         .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5    .4.0 20160609"
37         .section        .note.GNU-stack,"",@progbits

此时的文件已经被翻译成AT&T汇编语言文件。

汇编

接下来,进行汇编语言到机器语言的翻译,这个过程叫汇编,过程结束后,生成目标文件.o。

XXXX@ubuntu:~/hello$ gcc -c hello.s
XXXX@ubuntu:~/hello$ ls
hello.c  hello.i  hello.o  hello.s

说明:
1、-c 中的c一定要小写,不需要再加-o进行命名
2、hello.o是目标文件,是机器语言编写成的,但是还不可以执行,缺少必要的运行时文件。

链接

为了生成可执行文件,需要将运行时文件及目标文件进行绑定,这个过程即是链接,采用如下指令:

XXXX@ubuntu:~/hello$ gcc hello.o
XXXX@ubuntu:~/hello$ ls
a.out  hello.c  hello.i  hello.o  hello.s

此时 a.out可执行文件生成。

运行

运行可执行文件:

XXXX@ubuntu:~/hello$ ./a.out
Hello Word

此时,输出结果Hello Word。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐