对于需要编译的编程语言(c, c , java, c# ...高级语言),源码写完后,是无法直接运行的;需要有 编译,链接的过程才能生成最终可以执行的二进制文件;
编译:
编译的过程通常包含: A. 预编译过程,就是在源代码中进行文本替换工作,比如c中的#include的替换,以及宏定义的替换等;最终输出的依然是 普通的文本文件;在Linux中使用gcc可以用如下命令获得预编译的结果:
代码语言:javascript复制[root@www ~]# cat hello.c #查看hello.c的源代码;
#include <stdio.h>
int main() {
printf("Hello,2020 !n");
}
[root@www ~]# gcc -E hello.c -o hello.i #手动生成预编译文件hello.i , -E 参数表示 预编译完成后停止继续编译,所以可以通过 -E 参数获得预编译的结果;
[root@www ~]# ls | grep hello
hello.c
hello.i
[root@www ~]#
B. 编译过程, 这个过程是把预编译的结果进行转换,从而获得对应的汇编语言;
代码语言:javascript复制[root@www ~]# gcc -S hello.i -o hello.s #手动把预编译的结果 编译为汇编语言;-S 表示 编译为汇编语言后停止后续的编译操作,所以可以获得源代码对应的汇编语言代码;
[root@www ~]# ls | grep hello
hello.c # 这个是源代码文件
hello.i #这个是预编译结果的文件;
hello.s #这个是汇编语言的代码
[root@www ~]# cat hello.s #查看汇编语言的代码
.file "hello.c"
.section .rodata
.LC0:
.string "Hello,2020 !"
.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
movl $.LC0, �i
call puts
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)"
.section .note.GNU-stack,"",@progbits
[root@www ~]#
C. 汇编过程,该过程把上述的汇编代码(hello.s) 转变成机器码;这一过程可以用如下的步骤来完成:
代码语言:javascript复制[root@www ~]# as hello.s -o hello.obj #as 命令是用来将汇编语言转变成机器码的;目标文件是hello.obj
[root@www ~]# ls | grep hello
hello.c
hello.i
hello.obj
hello.s
[root@www ~]# file hello*
hello.c: C source, ASCII text
hello.i: C source, ASCII text
hello.obj: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped #目标文件是一个elf格式的二进制文件;
hello.s: ASCII text
[root@www ~]#
NOTE:
上面的步骤手动展示了编译的大概过程(预编译--->编译--->汇编),而在实际使用的时候,并不是这样一步步进行操作的(也不需要这样一步步进行操作),linux 下用 gcc -c hello.c -o hello.obj 这样的方式一步到位来完成编译(一般的IDE集成开发环境,直接点击"编译"按钮就完成了), 其隐藏了上述编译的步骤, 直接输出编译的结果;