




已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
=精选公文范文,管理类,工作总结类,工作计划类文档,欢迎阅读下载=程序编译过程程序编译过程 程序编译 程序的编译过程如下图所示,分为预处理、编译、汇编、链接等几个阶段。预处理:预处理相当于根据预处理命令组装成新的C程序,不过常以i为扩展名。 编译:将得到的i文件翻译成汇编代码。s文件。 汇编:将汇编文件翻译成机器指令,并打包成可重定位目标程序的O文件。该文件是二进制文件,字节编码是机器指令。 链接:将引用的其他O文件并入到我们程序所在的o文件中,处理得到最终的可执行文件。编译程序 把用高级程序设计语言书写的源程序,翻译成等价的计算机汇编语言或机器语言书写的目标程序的翻译程序。 汇编程序汇编代码:汇编语言编写的程序,机器不能直接识别,要一种程序将汇编语言翻译成机器语言,这种起翻译作用的程序叫汇编程序,汇编程序是系统软件中语言处理系统软件。目标程序又称“目的程序”。 编译程序将源程序编译成与之等价的机器码构成的,计算机能直接运行的程序,该程序叫目标程序。链接器 (linker) 将一个个的目标文件 ( 或许还会有若干程序库 ) 链接在一起生成一个完整的可执行文件。在符号解析 (symbol resolution) 阶段,链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合 : (1) 集合 E 是将被合并到一起组成可执行文件的所有目标文件集合; (2) 集合 U 是未解析符号 (unresolved symbols ,比如已经被引用但是还未被定义的符号 ) 的集合; (3) 集合 D 是所有之前已被加入到 E 的目标文件定义的符号集合。一开始, E 、 U 、 D 都是空的。 链接器的工作过程: (1): 对命令行中的每一个输入文件 f ,链接器确定它是目标文件还是库文件,如果它是目标文件,就把 f 加入到 E ,并把 f 中未解析的符号和已定义的符号分别加入到 U 、 D 集合中,然后处理下一个输入文件。 (2): 如果 f 是一个库文件,链接器会尝试把 U 中的所有未解析符号与 f 中各目标模块定义的符号进行匹配。如果某个目标模块 m 定义了一个 U 中的未解析符号,那么就把 m 加入到 E 中,并把 m 中未解析的符号和已定义的符号分别加入到 U 、 D 集合中。不断地对 f 中的所有目标模块重复这个过程直至到达一个不动点 (fixed point) ,此时 U 和 D 不再变化。而那些未加入到 E 中的 f 里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。 (3): 如果处理过程中往 D 加入一个已存在的符号 ,或者当扫描完所有输入文件时 U 非空,链接器报错并停止动作。否则,它把 E 中的所有目标文件合并在一起生成可执行文件。这种翻译通常有两种方式,即编译方式和解释方式。编译方式是指利用事先编好的一个称为编译程序的机器语言程序, 作为系统软件存放在计算机内,当用户将高级语言编写的源程序输入计算机后,编译程序便把源程序整个地翻译成用 机器语言表示的与之等价的目标程序,然后计算机再执行该目标程序,以完成源程序要处理的运算并取得结果。 解释方式是指源程序进入计算机后,解释程序边扫描边解释,逐句输入逐句翻译,计算机一句句执行,并不产生目标程序。可执行文件格式 Microsoft引进了PE文件格式,更经常被称为PE格式,作为最初的Win32规范的一部分。 然而PE文件源自VAX/VMS上早期的通用目标文件格式。 Microsoft编译器生成的OBJ文件也使用COFF格式。 PE文件一个非常好的地方就是它的数据结构在磁盘上与在内存(逻辑地址空间)中一样。加载一个可执行文件到内存主要就是把PE文件中的某个部分映射到地址空间中。如果你知道如何在一个 PE文件中找到某些内容,你几乎可以确定当文件被加载进内存时可以找到同样的信息。 注意到PE文件并不是作为单一的内存映射文件被映射进内存的这一点非常重要。相反,Windows加载器查看PE文件并确定文件中的哪些部分需要被映射。当映射进内存时,文件中的高偏移相对于内存中的高地址。某项内容在磁盘文件中的偏移可能与它被加载进内存之后的偏移不同,但是将磁盘文件中的偏移转换成内存偏移需要的所有信息都存在。 当PE文件Windows加载器加载进内存时,它在内存中被称为模块。文件被映射到的内存的起始地址被称为HMODULE。这是需要记住的一点:给你一个HMODULE,你就知道在那个地址处到底有什么样的数据结构,并且你可以根据PE文件的知识找到内存中所有其它的数据结构。这个强大的功能可以被用作其它用途,例如拦截API。 内存中的模块代表一个进程所需的可执行文件中的所有代码、数据和资源。PE文件中的其它部分可能会被读取,但并不被映射进内存。一些部分可能根本就不被映射,例如放在文件末尾的调试信息。PE文件头中的一个域告诉系统将这个可执行文件映射进内存时需要占用多少内存。不被映射的数据放在文件末尾,位于所有需要被映射的部分之后。 描述PE文件的关键位置是文件。在这个头文件中,你能找到几乎所有结构的定义、枚举类型以及使用PE文件或它在内存中的等价结构所需的定义。有许多工具可以用来查看PE文件。Visual Studio附带的Dumpbin和Platform SDK附带的Depends就是其中的两个。 PE文件的节 PE文件的节代表代码或某些类型的数据。虽然代码只能是代码,但数据却有许多种不同类型。除了可读/可写的程序数据外,节中其它类型的数据包括函数导入表和导出表、资源以及重定位信息等。每个节都有它自己的一组内存属性,其中包括节中是否包含代码,是只读的还是可读/可写的以及节中的数据是否在所有使用这个可执行文件的进程中是共享的等等。 一般说来,一个节中的所有代码和数据在逻辑上是相关的。通常一个PE文件中至少有两个节,一个是代码节,另一个是数据节。一般在PE文件中至少还有一种其它类型的数据节。第二部分中具体描述各种节。 每个节都有一个惟一的名字。它通常用来表示节的用途。例如一个名为.rdata的节表明它是一个只读数据节。使用节名只是为了方便人们处理文件,它对操作系统来说无关紧要。一个名为FOOBAR的节可能实际上是一个代码节,就像.text节一样。Microsoft通常在它们的节名前加一个圆点,但这并不是必须的。多少年来,Borland链接器使用的节名都是CODE和DATA。 节并不是完全链接器生成的,在OBJ文件中就有它们的身影。这通常是编译器放在那里的。链接器的工作就是把OBJ文件和库文件中所有需要的节组合成PE文件中最终相应的节。例如你的工程中的每个OBJ文件可能都至少有一个包含代码的.text节。链接器把各种OBJ文件中的所有.text节组合成单个的.text节放入PE文件。同样,各种OBJ文件中的所有.data节也被组合成PE文件中单个的.data节。 节有两种对齐值,一种是在文件中的对齐值,另一种是在内存中的对齐值。PE文件头中指定了这两种值,它们可以不同。每个节的起始地址都是对齐值的倍数。例如在PE文件中,典型的对齐值是0x200。因此每个节的起始起始地址都是0x200的倍数。 一旦映射进内存,节总是从页的边界开始。也就是说,当PE文件被映射进内存时,每个节的开头都对应于一个内存页的开始。在x86 CPU上,页按4KB对齐;在IA-64上,页按8KB对齐。以下是PEDUMP输出的Windows XP中的的.text节和.data节的情况: Section Table 01 .textVirtSize: VirtAddr: raw data offs: raw data size: 02 .dataVirtSize: CA VirtAddr: raw data offs: 00074C00 raw data size: 上面的输出表明,.text节的文件偏移是0x400,在内存中它比KERNEL32的加载地址高0x1000字节。同样,.data节的文件偏移是0x74C00,它在内存中比KERNEL32的加载地址高0x76000字节。可以创建一个PE文件,使它的节在文件中的偏移与在内存中的偏移相同。但这会使可执行文件相当大,不过可以提高它在Windows 9x或Windows Me中的加载速度。使用默认的/OPT:WIN98链接器选项就可以创建这样的PE文件。在Visual Studio? .NET中,链接器可能使用也可能不使用这个选项,这取决于文件是不是足够小。 链接器一个比较有趣的功能就是合并节。如果两个节属性相似、相互兼容时,它们通常会在链接时被合并成一个节。这是通过链接器的/MERGE选项来完成的。例如以下的链接器选项会把.rdata节和.text节组合成单个的.text节: /MERGE:.rdata=.text 把节合并起来的好处是可以节省在磁盘上和在内存中的空间。每个节至少要在内存中占用一个页面。如果你能将一个可执行文件中节的数目从四个减少到三个,你很可能就会少占用一页内存。当然,这取决于那两个被合并的节中未使用的空间加起来够不够一页。 当你合并节时就会发生一些有趣的情况,因为这并没有硬性的和快速的规则可以遵守。例如,把.rdata节合并到.text节当然可以,但是你不能把.rsrc节、.reloc节或者.pdata节合并到其它节中。在Visual Studio .NET之前,你可以把.idata节合并到其它节中。但是在Visual Studio .NET中,这是不允许的。但在创建程序的发行版本时,链接器自己却经常把部分的.idata节合并到其它节中,例如.rdata节。 于导入表要被Windows加载器改写,你可能想知道它们怎么能被放在只读节中。这是因为在加载时系统临时将包含导入表的那些页面的属性设置为可读/可写。一旦导入表被初始化,这些页面就会被设置成原来的属性。 相对虚拟地址 在可执行文件中,许多地方都需要被指定一个在内存中的地址。例如在使用全局变量时需要它的地址。PE文件可以被加载到进程地址空间中的任何地方。虽然它有一个首选地址,但你却不能依赖可执行文件一定会被加载到那个地址。因此就需要按一定方式指定地址,使它们并不依赖于可执行文件的加载地址。 为了避免在PE文件中硬编码内存地址,因此就使用了RVA。RVA只是一个相对于PE文件在内存中的加载位置的偏移。例如假定一个EXE文件被加载在0x处,而它的代码节在0x处。那么这个代码节的RVA就是: 0x - 0x = 0x1000 要把一个RVA转换成实际地址,只需要简单地逆着上述过程进行:将RVA与实际加载地址相加就能得到实际的内存地址。顺便说一下,按照PE格式中的说法,实际的内存地址被称为虚拟地址。另外一种考虑VA的方式就是把它当成RVA加上首选加载地址。不要忘了我前面说过加载地址与HMODULE是一回事。 想在内存中探索一些DLL内部的数据结构吗?这里就是方法用DLL的名称作为参数调用GetModuleHandle函数,它返回的HMODULE就是这个DLL的加载地址,你可以利用你学的关于PE文件结构的知识在这个模块中找到你想找到的一切。 数据目录 在可执行文件中有许多数据结构需要被快速地定位。导入表、导出表、资源以及基址重定位信息等就是一些明显的例子。所有这些广为人知的结构都是以同样的方式被定位的,这些位置被称为数据目录。 struct _IMAGE_DATA_DIRECTORY DWORD VirtualAddress; DWORD Size; IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES16 数据目录是一个有16个元素的结构数组。每个数组元素所指代的内容已经被预先定义好了。文件中的这些IMAGE_DIRECTORY_ENTRY_xxx定义就是数据目录的索引。下表描述了每个IMAGE_DIRECTORY_ENTRY_xxx值所指代的内容。它们指向的许多数据结构将在的第二部分中详细描述。值 描述IMAGE_DIRECTORY_ENTRY_EXPORT 指向导出表。 IMAGE_DIRECTORY_ENTRY_IMPORT 指向导入表。 IMAGE_DIRECTORY_ENTRY_RESOURCE 指向资源。 IMAGE_DIRECTORY_ENTRY_EXCEPTION 指向异常处理程序表。它特定于CPU,用于基于表的异常处理。适用于除x86之外所有类型的CPU。 IMAGE_DIRECTORY_ENTRY_SECURITY 指向WIN_CERTIFICATE结构列表。此结构定义在文件中。它并不作为映像的一部分被映射进内存。因此VirtualAddress域是文件偏移,而不是RVA。 IMAGE_DIRECTORY_ENTRY_BASERELOC 指向基址重定位信息。 IMAGE_DIRECTORY_ENTRY_DEBUG 指向IMAGE_DEBUG_DIRECTORY结构数组。其中的每个元素描述了映像中的一些调试信息。要获得IMAGE_DEBUG_DIRECTORY结构的数目,用Size域除以IMAGE_DEBUG_DIRECTORY结构的大小。早期的Borland链接器将这个IMAGE_DATA_DIRECTORY项的Size域设置成IMAGE_DEBUG_DIRECTORY结构的数目,而不是数组的大小。 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 指向与平台相关的数据,这个数据是一个IMAGE_ARCHITECTURE_HEADER结构数组。x86平台和IA-64平台并不使用,但好像已经用于DEC/Compaq Alpha平台。 IMAGE_DIRECTORY_ENTRY_GLOBALPTR 在某些平台上,其VirtualAddress域保存的是全局指针的RVA。x86平台上不使用,但IA-64平台上使用。Size域并未使用。要获取更多关于IA-64 GP方面的信息,可以参考2000年11月的Under The Hood专栏。 IMAGE_DIRECTORY_ENTRY_TLS 指向线程局部存储初始化节。 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 指向IMAGE_LOAD_CONFIG_DIRECTORY结构。此结构中的信息特定于Windows NT、Windows 2000和Windows XP。如果你的可执行文件要使用这个结构,需要定义一个名称为_load_config_used,类型为IMAGE_LOAD_CONFIG_DIRECTORY的全局结构体。对于非x86平台,这个名称需要被定义成_load_config_used。如果你想使用IMAGE_LOAD_CONFIG_DIRECTORY结构,必须使用这个技巧才能在你的C+代码中得到正确的名字。链接器看到的符号名一定要是_load_config_used。C+编译器要在全局符号前加一个下划线。另外,它还使用类型信息来修饰全局符号。因此要使一切正常,你应该像下面这个样子使用: extern
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年事业单位工勤技能-江苏-江苏工程测量员三级(高级工)历年参考题库含答案解析
- 2025年事业单位工勤技能-江苏-江苏仓库管理员四级(中级工)历年参考题库含答案解析(5套)
- 2025年事业单位工勤技能-广西-广西水文勘测工五级(初级工)历年参考题库典型考点含答案解析
- 2025年事业单位工勤技能-广西-广西地图绘制员三级(高级工)历年参考题库含答案解析
- 2025年事业单位工勤技能-广东-广东防疫员二级(技师)历年参考题库典型考点含答案解析
- 2025年事业单位工勤技能-广东-广东热力运行工二级(技师)历年参考题库典型考点含答案解析
- 2025年事业单位工勤技能-广东-广东地图绘制员四级(中级工)历年参考题库含答案解析
- 2025年综合评标专家-河北-河北综合评标专家(咨询类)历年参考题库含答案解析(5套)
- 乐都中考试题及答案
- 季风水田课件
- GB/T 45911-2025人工影响天气作业用弹药存储安全要求
- 排污许可证审核及环境应急管理服务方案投标文件(技术方案)
- 驻京信访工作组管理办法
- 尿道下裂的诊断及分型
- 肿瘤的诊断与治疗
- 【高朋律师事务所】RWA发展研究报告:法律、监管和前瞻(2025年)
- DB42∕T 2272-2024 微粒化岩沥青改性沥青路面施工技术规范
- 办公耗材应急方案(3篇)
- 新高中班级团建活动方案
- 仓储主管考试试卷及答案
- 地理探索之旅:初中研学旅行方案策划
评论
0/150
提交评论