源文件是如何转换成可执行文件的

源文件是如何转换成可执行文件的

几个小知识点

  1. CPU可以解析和运行的程序形式为本地代码

  2. 链接器将多个目标文件结合生成.exe文件

  3. .obj文件为本地代码

  4. 收录多个目标文件的是库文件

    链接器从库文件中抽取出必要的目标文件,并将其结合到exe文件中

    此外,还存在一种程序运行时结合的dll形式的库文件

  5. 仅包含Windows的.dll文件中存储的函数信息的文件为导入库

    把导入库信息结合到exe文件中,这样程序在运行时就可以利用dll内的函数了

  6. 程序运行时,动态申请分配的数据和对象的内存区域形式为,堆的内存空间会根据程序的指令进行申请和释放

本地代码的内容

dump是指把文件的内容,每个字节用2位十六进制来表示的方式

本地代码的内容就是各种数值的罗列,可以把exe文件的内容Dump一下,其实得到的本地代码的内容就是各种数值的罗列。每个数值都表示一个命令或数据,这就是原始的Dump程序

编译器负责转换源代码

编译器能够把C语言等高级编程语言编写的源代码转换成本地代码(.c—>.obj)

每个编写源代码的编程语言都需要其专门的编译器

编译器读入源代码时,要经过语法解析、句法解析、语义解析等,才能成成本地代码。

根据CPU类型的不同,本地代码的类型也不同。编译器不仅和编程语言的种类有关,还和CPU的类型是相关的。同时编译器作为一种程序,也需要运行环境。(如Windows的C编译器)

因此选择编译器,需要兼顾的问题有:

  1. 何种编程语言的编译器
  2. 编译器生成的本地代码适用于那种CPU
  3. 该编译器在什么环境下使用

链接器链接得到EXE文件

​ 编译后得到的文件为.obj目标文件,虽然目标文件的内容是本地代码,但是无法直接运行,原因就是:当前程序还处于未完成状态。故.obj文件是尚未完成的本地代码。

#sample.c

#include <windows.h>
#include <stdio.h>

//消息框的标题
char* title ="test program";

//返回两个参数的平均数 
double Average(double a,double b){
    
    
	return (a+b)/2;
} 

// 程序运行起始位置的函数 
int WINAPI WinMain(HINSTANCE h,HINSTANCE d, LPSTR s,int m){
    
    
	double ave;		//保存平均数的变量 
	char buff[80];		//保存字符串的变量 
	ave=Average(123,456);
	
	//编写显示在消息框中的字符串 
	sprintf(buff,"aver=%f",ave);
	
	//打开消息框 
	MessageBox(NULL,buff,title,MB_OK);
}

上面的源代码生成的目标文件为sample.obj

Average()用来返回两个参数的平均值;WinMain()是程序的运行起始函数,函数Average()和函数WinMain()是我们自己编写的,处理的内容记述在源代码中。

sprintf()是通过指定格式把数值变换成字符串的函数;MessageBox()是消息框函数。不过代码中并没有记述这两个函数的处理内容。因此就必须将存储这sprintf()MessageBox()的处理内容的目标文件(假设为c0w32.obj)和sample.obj结合,否则处理就不完整,.exe文件就无法完成

  • 把多个目标文件(obj文件)结合,最终生成一个exe文件的处理就是链接,运行链接的程序就是链接器(linkage editor)

库文件

  • 库文件指的是把多个目标文件集合保存到一个文件中的形式。

链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成exe文件

Error:无法解析的外部符号'_sprintf'.......

表示的是无法找到记述着目的变量及函数的目标文件,因而无法进行链接的意思。因此需要导入文件包。

sprintf()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的,这样的函数成为标准函数

通过库文件,可以减少链接器的压力。

DLL文件及导入库

Windows以函数的形式为应用提供了各种功能,这些形式的函数成为API(Application Programming Interface),例如MessageBox()不是标准函数,而是Windows提供的API的一种。

在Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在dll(Dynamic Link Library)文件的特殊库文件中。

  • dll文件是程序运行是动态结合文件。

前面提到的MessageBox()的目标文件是存储在import32.lib中的。

MessageBox()的目标文件的实体实际并不存在。

实际上,该import32.lib文件存储着两个信息:

  1. MessageBox()user32.dll这个dll文件中

  2. 存储着dll文件的文件夹信息

  • import.lib这样的文件称为导入库。

相反,存储这目标文件的实体,并直接和exe文件结合的库文件成为静态链接库(static

如:存储sprintf()的目标文件cw32.lib就是静态链接库。

通过结合导入库文件,执行时从dll文件中调出对应的函数就会和exe文件进行结合

Windows中的编译和链接机制

在这里插入图片描述

补充点:

编译器是在运行前对所有源代码进行解释处理的。

解释器是运行时对源代码的内容一行一行地进行解释处理的。

参考书籍:《程序是怎样跑起来的》

猜你喜欢

转载自blog.csdn.net/weixin_43865875/article/details/108161879