程序员的自我修养学习笔记——第五章
PE: Portable Executable
COFF: Common Object File Format
跟ELF一样,PE中也允许程序员将变量后函数放到自定义段。在GCC中使用“__attribute__((section)("name"))”,在VISUAL C++中可以使用 “#pragma”编译器指示。
#pragma data_seg("FOO")
int global = 1;
#pragma data_seg(".data")
使用cl 编译器:
开始 –> 所有程序 -> Microsoft Visual Studio ->
Visual Studio Tools -> Developer Command Prompt
cl /c /Za SimpleSectionc.c
/c参数表示只编译,不链接,生成SimpleSection.obj
/Za 参数禁用这些扩展,使得我们的程序跟标准的C/C++ 兼容,使用/Za参数时,编译器自动定义了__STDC__这个宏,我们可以再程序里通过判断这个宏是否被定义而确定编译器是否禁用了Microsoft C/C++ 语法扩展。
Windows下查看可执行文件和目标文件的工具:dumpbin
查看SimpleSection.obj:
dumpbin /ALL SimpleSection.obj > SimpleSection.txt
该命令打印出所以目标文件的相关信息,输出到SimpleSection.txt中。
查看基本信息:
D:\Program Files\...>dumpbin SimpleSection.obj /SUMMARY
Microsoft (R) COFF/PE Dumper Version 11.00.50214.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file SimpleSection.obj
File Type: COFF OBJECT
Summary
4 .bss
C .data
84 .debug$S
18 .drectve
4E .text
COFF文件结构:
COFF文件头包括两部分:一个是描述文件总体和属性的映像头,另外一个是描述该文件中包含的段属性的段表
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; //运行平台
WORD NumberOfSections; //区块数目
DWORD TimeDateStamp; //文件日期时间戳
DWORD PointerToSymbolTable; //指向符号表
DWORD NumberOfSymbols; //符号表中的符号数量
WORD SizeOfOptionalHeader; //映像可选头结构的大小
WORD Characteristics; //文件特征值
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
对应“SimpleSection.txt”中的输出信息,“FILE HEADER VALUES”中的内容跟COFF映像头中的成员是一一对应的:
Dump of file SimpleSection.obj
File Type: COFF OBJECT
FILE HEADER VALUES
14C machine (x86)
5 number of sections
4F84D87A time date stamp Wed Apr 11 09:03:54 2012
204 file pointer to symbol table
14 number of symbols
0 size of optional header
0 characteristics
映像头后面紧跟着的是COFF文件的段表,是一个类型为“IMGAE_SECTION_HEADER”结构的数组,数组中每个元素代表一个段,跟ELF文件中的“Elf32_Shdr”很相似。
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
每个段拥有的属性包括:段名(Section Name)、物理地址(Physical address)、虚拟地址(Virtual address)、原始数据大小(Size of raw data)、段在文件中的位置(File pointer to raw data)、该段的重定位表在文件中的位置(File pointer to relocation table)、该段的行号表在文件中的位置(File pointer to line numbers)、标志位(Characteristics)等。
符号表:
“SimpleSection.txt”的最后一部分是COFF符号表(Symbol table),COFF文件的符号表包含的内容几乎跟ELF文件的符号表一样,主要就是符号名、、符号的类型、所在的位置。
SimpleSection.obj的符号表:
COFF SYMBOL TABLE
000 00CEC426 ABS notype Static | @comp.id
001 80000191 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 18, #relocs 0, #linenums 0, checksum 0
004 00000000 SECT2 notype Static | .debug$S
Section length 84, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .data
Section length C, #relocs 0, #linenums 0, checksum AC5AB941
008 00000000 SECT3 notype External | _global_init_var
009 00000004 UNDEF notype External | _global_uninit_var
00A 00000004 SECT3 notype Static | $SG1281
00B 00000008 SECT3 notype Static | ?static_var@?1??main@@9@9 (`main'::`2'::static_var)
00C 00000000 UNDEF notype () External | _printf
00D 00000000 SECT4 notype Static | .text
Section length 4E, #relocs 5, #linenums 0, checksum CC61DB94
00F 00000000 SECT4 notype () External | _func1
010 00000020 SECT4 notype () External | _main
011 00000000 SECT5 notype Static | .bss
Section length 4, #relocs 0, #linenums 0, checksum 0
013 00000000 SECT5 notype Static | ?static_var2@?1??main@@9@9 (`main'::`2'::static_var2)
String Table Size = 0x5D bytes
第三列是符号所在的位置,“ABS”表示符号的绝对值,它不存在于任何段中;SECT1(Section#1)表示符号所表示的对象定义在COFF文件的第一个段中,即本例中的.drectve段;UNDEF(Undefined)表示符号是未定义的,即这个符号被定义在其他目标文件中的。Static表示绝不变量,External表示全局变量。
“_global_init_varabal”这个符号位于Section#3即 .data段,它的长度是4个字节,可见范围是全局的。
PE文件是基于COFF扩展,比COFF文件多了几个结构。最主要的变化有两个:第一个是文件最开始部分不是COFF文件头,而是DOS MZ可执行文件格式的文件头和桩代码,第二个变化是原来的COFF文件头中的“IMAGE_FILE_HEADER”被扩展成为了PE文件头结构“IMGAE_NT_HEADERS”
PE 文件格式