注意:本文中的大部分是阅读 《程序员的自我修养》 作 者:俞甲子,石凡,潘爱民 的读书笔记。推荐大家看看这本书。
一,微软采用的可执行文件/目标文件格式
微软采用的可执行文件格式是PE(Portable Executable),目标文件格式是COFF。
使用Visual C++编译产生的文件的代码段是.code,数据段是.data。PE中也允许程序员自定义段,例如在Visual C++中使用#pragma编译器指示:
#pragma data_seg("FOO")
int global=1;
#pragma data_seg(".data")
这样将global放于FOO段,之后又切换回来(到.data段)。
二,Visual C++环境
Visual C++的编译器是cl,链接器是link,可执行文件查看使用dumpbin。这些工具需要在命令行下运行。
安装完Visual C++(比如VS2005)后, 开始/程序/Micfosoft Visual Studio 2005/Visual Studio Tools/Visual Studio 2005 Command Prompt中即可使用这些工具。
cd 进入源代码目录。比如使用如下命令:
cl /c /Za SimpleSection.c
cl是Compilter的缩写,/c表示只编译不链接,否则cl会在编译后调用link链接器将obj文件与默认C运行库链接形成.exe文件。
MSDN中Microsoft Extensions to C and C++中有关于Visual C++对C/C++的专有拓展的描述,这些在ANSI C/C++标准中没有定义。/Za意思是禁用这些拓展,使得程序与标准C/C++兼容。使用/Za,编译器自动定义宏__STDC__,我们可以在程序中用以判断是否禁用微软的C/C++拓展。
查看:
dumpbin /ALL SimpleSection.obj>SimpleSection.txt
/ALL表示打印出目标文件所有信息,>重定向。使用/SUMMARY则只会打印段名和长度。
PE可执行文件很多时候被称作Image(映像)文件。COFF文件的结构如下:
文件头由映像头和段表组成。VC或者SDK中可以找到文件和段的数据结构的有关定义VC/PlatformSDK\include\WinNT.h。
三,两个ELF中没有的段
链接指示信息:
.drectve段。Directive段内容是编译器传递给链接器的指令。其flags是IMAGE_SCN_ALIGN_!BYTES、IMAGE_SCN_LNK_REMOVE、IMAGE_SCN_LNK_INFO的组合。表示对其为1字节、连接成映像文件时抛弃、该段是注释或其他信息。
dumpbin会对该段进行解析。比如可能有/DEFAULTLIB:'LIBCMT'表示链接时使用静态多线程C语言库。使用/Zi可以关闭默认C库的链接指令。
调试信息:
.debug$T表示类型相关
.debug$S表示符号相关
.debbug$P表示预编译头文件相关
等等。
四,符号表
与ELF大致相同(详细参考书籍),但是这里会对字符串常量自动产生符号,ELF则不会。这种字符串的符号是编译器自动给它赋予的名字,对外部不可见。
五,PE文件
比COFF多了几个结构。一是文件开始部分不是COFF文件头,而是DOS MZ可执行文件格式的文件头和桩代码(DOS MZ File Header and Stub),这个是为了兼容DOS用的,其中的e_lfanew指向IMAGE_NT_HEADERS在文件中的偏移,如果是0则表明是DOS程序;第二个是COFF中的IMAGE_FILE_HEADER拓展成了IMAGE_NT_HEADERS。IMAGE_NT_HEADERS是真正的PE文件头,包含原来的和PE拓展头部结构(PE Optional Header),PE拓展头部结构是DLL和可执行文件都必须的。
六,PE数据目录
Windows装载PE可执行文件时,需要很快找到加载所需的数据结构,比如导入/导出表、异常表、资源、重定位表,TLS等,这些都被保存到了称为“数据目录(DataDirectory)”的结构中,可以通过解析这个数据结构,知道导入/导出表、异常表、资源、重定位表,TLS等的入口、大小等信息。