程序编译执行流程
- 编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序就把人们熟悉的语言换成2进制。
- 编译程序把一个源程序翻译成目标程序分为5个阶段:词法分析,语法分析,语以检查和中间代码生成,代码优化,目标代码生成。
- GCC编译过程:
对于GCC而言,处理一个标准的C/C++程序,GCC又分为:预处理,编译,汇编,链接四个过程。
预处理阶段:
在预处理阶段,编译器读取源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理。
伪指令包括引用头文件(#include等),宏指令(#define,#undef等),条件编译指令(#ifdef,#endif,#else和一些特殊符号)
以一个简单的C语言程序为例:
#include <stdio.h> int main(int argc, const char * argv[]) { printf("hello, world\n"); return 0; }
使用命令将预处理命令输入到文件中:
gcc -E hello.c -o hello.i
查看main.i文件;
# 1 "main.cpp" # 1 "<built-in>" 1 # 1 "<built-in>" 3 # 374 "<built-in>" 3 # 1 "<command line>" 1 # 1 "<built-in>" 2 # 1 "main.cpp" 2 # 1 "/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/stdio.h" 1 3 # 102 "/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/stdio.h" 3 # 1 "/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__config" 1 3 # 57 "/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__config" 3 # 444 "/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/__config" 3 ...
在预处理过程中,GCC对源程序中声明的#include<stdio.h>做了引入工作,同样,还对stdio.h中的引用和一些声明做了预处理
编译阶段:
在一切环境准备好之后,就进入了编译阶段,编译阶段就,GCC首先要检查代码的规范性,是否有语法错误等,即在编译原理中的词法分析与语法分析,确认没有什么错误以后,则进行语义分析,从而生成中间代码(汇编代码)。
使用GCC命令,将编译阶段的逻辑输出出来
gcc -S hello.i -o hello.s
打开hello.s文件就是编译后所得到的结果,汇编程序:
.section __TEXT,__text,regular,pure_instructions .build_version macos, 10, 15 sdk_version 10, 15 .globl _main ## -- Begin function main .p2align 4, 0x90 _main: ## @main .cfi_startproc ## %bb.0: pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset %rbp, -16 movq %rsp, %rbp .cfi_def_cfa_register %rbp subq $32, %rsp movl $0, -4(%rbp) movl %edi, -8(%rbp) movq %rsi, -16(%rbp) leaq L_.str(%rip), %rdi movb $0, %al callq _printf xorl %ecx, %ecx movl %eax, -20(%rbp) ## 4-byte Spill movl %ecx, %eax addq $32, %rsp popq %rbp retq .cfi_endproc ## -- End function .section __TEXT,__cstring,cstring_literals L_.str: ## @.str .asciz "hello world!\n" .subsections_via_symbols
汇编阶段:
汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程,被翻译系统处理的每一个C/C++语言源程序,都将最终经过这一个处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标机器语言代码,即二进制目标代码。
使用下面命令来查看具体过程:
gcc -c hello.s -o hello.o
查看hello.o文件:
链接阶段:
汇编后的程序并不能直接运行,其中可能还存在许多没有解决的问题:
某个源文件中的函数可能引用了另一个源文件中定义的某个符号,如变量或者函数调用。
链接阶段的主要工作就是将有关的目标文件彼此相连接,即将在一个文件中引用的符号同该符号在另一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
具体操作可以使用如下命令完成:
gcc hello.o -o hello
例如:上述程序中的printf函数以及一些设计的操作也一起连接进入hello中。
- Android平台上的C/C++编译过程并不是直接在Android上编译完成的,使用了NDK中的arm-linux-gcc进行了交叉编译来完成的,与gcc编译类似,只不过是将gcc换为了arm-linux-gcc。
- 对C/C++语言进行反汇编对时候,就是将应用程序的动态链接库或静态链接库,逆向到编译阶段生成的汇编语言,从而分析高级语言C/C++的逻辑代码。