程序员的自我修养学习笔记——第五章

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 文件格式

程序员的自我修养学习笔记——第五章

 

你可能感兴趣的:(学习笔记)