程序是怎样跑起来的-第08章 从源文件到可执行文件

08 从源文件到可执行文件

热身问题


1:CPU可以解析和运行的程序形式称为什么代码?

    本地代码(机器语言代码),通过编译源代码得到本地代码。


2:将多个目标文件结合生成EXE文件的工具称为什么?

    连接器,通过编译和连接,得到EXE文件。


3:扩展名为.obj的目标文件的内容,是源代码还是本地代码?

    本地代码,通过对源文件进行编译,得到目标文件。例如,C语言中,将Samplel.c这个源文件编译后,就会得到Samplel.obj这个目标文件。目标文件的内容就是本地代码。


4:把多个目标文件收录在一起的文件称为什么?

    库文件,连接器会从库文件中抽取出必要的目标文件并将其结合到EXE文件中。此外,还存在一种程序运行时结合的DLL形式的库文件。


5:仅包含Windows的[DLL文件中存储的函数信息]的文件称为什么?

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


6:在程序运行时,用来动态申请分配(数据和对象)的内存区域形式称为什么?

    堆,堆的内存空间会根据程序的命令进行申请及释放。



8.1 计算机只能运行本地代码

    用某种编程语言编写的程序就称为源代码(source code),保存源代码的文件称为源文件。

    源代码是无法直接运行的,CPU能直接解析并运行的不是源代码而是本地代码的程序。CPU只能解释已经转换成本地代码的程序内容。

    本地(native)这个术语有母语的意思,对于CPU来说,母语就是机器语言。 本地代码就是转换成机器语言的程序。

    即使是使用不同编程语言编写的代码,转换成本地代码后,也就变成同一种语言(机器语言)来表示了。



8.2 本地代码的内容

    计算机把所有的信息作为字节的集合来处理的,计算机指令也是字节的结合。


8.3 编译器负责转换源代码

    编译器:能够把C语言等高级编程语言编写的源代码转换成本地代码的程序称为编译器。C语言编写的源代码转换成本地代码的编译器称为C编译器。

    编译器通过语法解析、句法解析、语义解析等流程生成本地代码。

    又因为CPU类型不同,本地代码的类型也不同。因而,编译器不仅和编程语言的种类有关, CPU的类型也是相关的。也就是说不通类型CPUC编译器也是不同的。  

    这样一来,同样的源代码就可以翻译成适用于不同CPU的本地代码。

    因为编译器本身也是一种程序,所以也需要运行环境。

    用下面的三个问题

        想要的是何种编程语言用的编译器?

        编译器生成的本地代码是用于哪种CPU的?

        该编译器是在什么环境下使用的?

    可以确定一个编译器。例如:一个 C语言 用的、用来输出 X86CPU 本地代码的、Windows环境下的编译器。


8.4 仅靠编译是无法得到可执行文件的

    仅靠编译是无法得到可执行文件的。

    编译器把源代码转换成本地文件后,此本地文件也是无法直接运行的,因为它还处于未完成状态。为了得到可执行文件,编译之后还需要进行链接处理。

    通过C编译器对C源文件进行编译后生成扩展名为”.obj”的目标文件。

    如以下文件:

        #include<windows.h>

        #include<stdio.h>

        char *title = “示例程序”;

        double Average(double a,double b) {

            return (a+b)/2;

        }


        int WINAPI WinMain(….)

        {

            double ave;

            char buff[80];

            ave = Average(123,456);

            sprintf(buff,”平均值=%f”,ave);

            MessageBox(NULL,buff,titlemMB_OK);

            return 0;

        }

    仅仅通过编译是无法生成可执行文件的,如上代码,MessageBoxsprintf等方法都不是我们实现的,我们的源代码中并没有记录这些函数的处理内容。我们必须将存储着MessageBoxsprintf等方法的目标文件同上面的代码生成的目标文件结合起来,否则处理就不完整。

    把多个目标文件结合起来,生成一个可执行文件的处理就是链接,运行链接的程序就称为链接器(linkage editor或连接器)。


8.5 启动及库文件

    库文件指的是把多个目标文件集成保存到一个文件中的形式。链接器指定库文件后,就会从中把需要的目标文件抽取出来,并同其他目标文件结合生成可执行文件。

    如上例,如果在链接时不指定MessageBoxsprintf等方法所在的库文件,则会外部符号无法解析的错误。外部符号是指其他目标文件中的变量或函数。

    库文件:

        像sprint()等函数,不是通过源代码形式而是通过库文件形式和编译器一起提供的。这样的函数称为标准函数。之所以使用库文件,是为了简化为链接器的参数指定多个目标文件这一过程。例如,在链接调用了数百个标准函数的程序时,就要在链接器的命令中指定数百个目标文件,这样太繁琐了。而利用存储着多个目标文件的库文件的话,只需要在链接器的命令行中指定介个库文件就可以了。

        通过以目标文件的形式或集合多个目标文件的库文件形式来提供函数,就可以不用公开标准函数的源代码内容。源代码是公司的重要资产。


8.6 DLL文件及导入库

    Windows以函数的形式为应用提供了各种功能。这种形式的函数称为APIApplication Programming Interface,应用程序接口)。

    Windows中,API的目标文件,并不是存储在通常的库文件中,而是存储在名为DLLDynamic Link Library)文件的特殊库文件中。DLL文件是程序运行时动态结合的文件。

    MessageBox()为例,MessageBox的信息存储在import.lib(假设)库文件中,实际上import.lib仅存储两个信息,一是MessageBoxuser.dll(假设)这个DLL文件中。另一个是存储着DLL文件的文件夹信息,import.libMessageBox的目标文件的实体实际上并不存在。我们把import.lib这样的库文件称为导入库。

    与此相反,存储着目标文件的实体,并直接和可执行文件结合的库文件形式称为静态链接库。


8.7 可执行文件运行时的必要条件

    再配置信息:

        本地代码在对程序中记述的变量进行读写时,是参照数据存储的内存地址来进行命令的。在调用函数是,程序的处理流程就会跳转到存储着程序处理内容的内存地址上。可执行文件作为本地代码的程序,并没有指定变量以及函数的实际内存地址。

        类似于Windows操作系统这样的可以加在多个可执行程序的运行环境中,每次运行时,程序内的变量以及函数被分配的地址都是不同的,那么,在可制行文件中,变量和函数的内存地址的值,是如何来表示的呢?

        可执行未见中给变量以及函数分配了虚拟的内存地址。在程序运行时,虚拟的内存地址会转换成实际的内存地址。连接器会在可执行文件的开头,追加转换内存地址所需要的必要信息,这些信息称为再配置信息。

         可执行文件的再配置信息,就成为了变量和函数的相对地址。相对地址表示的是相对于基点地址的偏移量,也就是相对距离。

        在源代码中,虽然变量以及函数是在不同位置分散记述的,但是在链接后的可执行文件中,变量及函数就会变成一个连续排列的组。这样,各变量的内存地址就可以用相对于变量组起始位置这一基点的偏移量来表示,各函数的内存地址也可以用相对于函数组起始位置这一基点的偏移量来表示。而各组基点的内存地址则是在程序运行时被分配的。

        可执行文件的内容分为再配置信息,变量组和函数组,当程序加载到内存后,除此之外还会额外生成两个组,那就是栈和堆。栈是用来存储函数内部临时使用的变量(局部变量),以及函数调用时所用的参数的内存区域。堆是用来存储程序运行时的任意数据及对象的内存领域。

       栈中对数据进行存储和舍弃的代码,是由编译器自动生成的。堆中的内存空间,则要根据程序猿编写的程序,来明确进行申请分配或释放。



    编译器和解释器有什么不同?

        编译器是在运行前对所有源代码进行解释处理的。而解释器则是在运行时对源代码的内容一行一行地进行解释处理的。


    使用DLL文件的好处是什么?

        DLL文件中的函数可以被多个程序公用。因此,借助该功能可以节约内存和磁盘。此外,在对函数的内容进行修正是,还不需要重新链接使用这个函数的程序。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值