代码的编译原理,以Linux系统为例

程序编译分为预编译、编译、汇编和链接四个阶段。在Windows操作系统中,编译工具用的是集成的开发环境,在Linux系统中没有很好的继承开发环境,用的是gcc编译器或者g++,gcc用于C语言代码的编译,g++用在C++的编译过程中。在Linux下的编译有一步到位和分布进行两种方式,接下来就以一个简单的示例演示一个两种编译

//hello.cpp
#include<iostream>
using namespace std;

#define MAX 1024
int main()
{
	cout<<MAX<<endl;
	return 0;
}

1.一步到位式的编译:

gcc hello.c                  //默认会生成一个名为a.out的可执行文件
gcc hello.c -o hello         //会生成一个名hello的可执行文件

 

 2.分步编译

gcc -E hello.c  -o  hello.i      //预处理
gcc -S hello.i   -o hello.s      //编译
gcc -c hello.s -o hello.o        //汇编
gcc hello.o -o hello             //链接

01.预编译阶段:完成头文件和宏定义的替换,生成hello.i

在预编译阶段会把头文件的内容都包含进来,预编译阶段的另一个工作就是进行宏替换

# 996 "/usr/include/c++/11/istream" 2 3
# 41 "/usr/include/c++/11/iostream" 2 3

namespace std __attribute__ ((__visibility__ ("default")))
{

# 60 "/usr/include/c++/11/iostream" 3
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;


  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;




  static ios_base::Init __ioinit;


}
# 2 "hello.cpp" 2

# 2 "hello.cpp"
using namespace std;

//上面有好几页是头文件的内容,在预编译阶段会把头文件的内容都包含进来
int main()
{
 cout<<1024<<endl; //预编译阶段的另一个工作就是进行宏替换
 return 0;
}

02.编译阶段:生成汇编文件hello.s

这是生成的hello.s 文件,可以看到C语言的代码已经被翻译成了汇编指令

	.file	"hello.cpp"
	.text
	.local	_ZStL8__ioinit
	.comm	_ZStL8__ioinit,1,1
	.globl	main
	.type	main, @function
main:
.LFB1731:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$1024, %esi
	leaq	_ZSt4cout(%rip), %rax
	movq	%rax, %rdi
	call	_ZNSolsEi@PLT
	movq	_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rdx
	movq	%rdx, %rsi
	movq	%rax, %rdi
	call	_ZNSolsEPFRSoS_E@PLT
	movl	$0, %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1731:
	.size	main, .-main
	.type	_Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB2231:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	cmpl	$1, -4(%rbp)
	jne	.L5
	cmpl	$65535, -8(%rbp)
	jne	.L5
	leaq	_ZStL8__ioinit(%rip), %rax
	movq	%rax, %rdi
	call	_ZNSt8ios_base4InitC1Ev@PLT
	leaq	__dso_handle(%rip), %rax
	movq	%rax, %rdx
	leaq	_ZStL8__ioinit(%rip), %rax
	movq	%rax, %rsi
	movq	_ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
	movq	%rax, %rdi
	call	__cxa_atexit@PLT
.L5:
	nop
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE2231:
	.size	_Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
	.type	_GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB2232:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	$65535, %esi
	movl	$1, %edi
	call	_Z41__static_initialization_and_destruction_0ii
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE2232:
	.size	_GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
	.section	.init_array,"aw"
	.align 8
	.quad	_GLOBAL__sub_I_main
	.hidden	__dso_handle
	.ident	"GCC: (Debian 11.3.0-5) 11.3.0"
	.section	.note.GNU-stack,"",@progbits

03.汇编阶段:生成目标文件hello.o,在Windows操作系统中生成的是hello.obj

汇编阶段将hello.s的汇编语言代码翻译成了计算机能够识别的二进制代码,我们使用vim直接打开显示的是乱码,只有使用特定的软件显示的就全是由“0”和“1”组成的二进制数据。

 04.链接:用所有的目标文件链接生成可执行文件

猜你喜欢

转载自blog.csdn.net/fencecat/article/details/128316202