时隔一个月的假期(自从上一篇文章开始我就开始着手于写编译器,由于是以学习为目的,所以我自己写的编译器的数据结构和书上的完全不同,导致花费了很多时间,终于今天晚上写完了符号表的内容终于到了我的主要目的COFF文件结构)
这章主要是记录COFF文件结构的,因为PE文件结构和COFF文件结构有很多相似的地方,所以也会记录的比较详细。
概念部分的最仔细的说明:http://blog.csdn.net/diamont/article/details/4291131 这个文章很大部分内容实际上就是对这篇文章做简化解释和说明的
基本概念(名词): 属性证书:就是将一个可以用于校验的声明和映像关联器来的证书。 日期/时间戳:由于不同目的而用于PE或COFF文件中好几个地方的戳。 文件指针:某文件在被处理前的磁盘位置 映像文件:可执行文件(EXE或DLL),可以被认为是内存映像 目标文件:传入链接器进行处理的文件,链接器生成一个映像文件 RVA:相对虚拟地址,对于映像文件来说,他是某项内容被加载进内存后的地址减去映像文件地址的基地址;对于目标文件来说,因为内存的位置香味分配,所以RVA没有意义,但是RVA的节是依然保存的并且会在后面链接是重定位。 节:COFF,PE文件中代码或数据的基本单元 VA:和RVA相似,但是不减去映像文件基地址
下面是COFF文件头的标准格式: WORD字 DWORD = double word 双字,一个字大小是两字节,也就是16位,DWORD就是4字节
typedef struct _IMAGE_FILE_HEADER { WORD Machine; //一个标识目标机器类型的数字 WORD NumberOfSections; //节的数目 DWORD TimeDateSetup; //从UTC时间开始到文件创建时的总秒数 DWORD PointerWoSymbolTable; //符号表的文件偏移 DWORD NumberOfSymbol; //符号表中的元素数目 WORD SizeOfOptionalHeader; //可选文件头的大小 WORD Characteristics; //文件属性标志 } //注意这里总的字节数是20个在书中有一个例子: 这里我就用VS编译结果做示范吧: 注意看我们可以知道: Machie = 0x014c // 兼容386的CPU NumberOfSections = 0x11 //有17个节 TimeDateSetup = 0x59a7daa3 PointerWoSymbolTable = 0x00001565 NumberOfSymbol = 0x43 最后两位为0 最后我们看看符号表的位置: 时间计算: 0x59a7daa3 = 1504172707 现在是31号的晚上7点30 为 1504207799秒 其实大体上会发现是差不多的(文件是我下午写的,具体就不算了) 相关的机器类型和文件属性标志都在上面的那个地址里面给的相当详细了,这就不说了 节头表:
#define IMAGE_SIZEOF_SHORT_NAME 8 tyepdef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; //一个由8字节组成的UTF-8编码字符串,当其等于8时结尾不包含0,不足时由0填充,超出8位时将会以一个/后面跟一个十进制数字,标识字符串的偏移,可执行映像文件不支持长度超过8字节的节名。 union { DWORD PhysicalAddress; DWORD VirtualSize; //加载进内存时这个节的大小 }Misc; DWORD VirtualAddress; //对于映像来说,这个值是这个节被加载进内存之后的相对于映像基址的偏移,对于目标文件来说,这个域的值是没有重定位之前第一个字节的地址。 DWORD SiezOfRawData; //对于目标文件来说这个是节的大小,对于映像来说这个是磁盘文件中已初始化数据的大小,但是如果这个值小于VirtualSize时多的那部分内存由0填充。 DWORD PointerToRawData; //指向COFF文件中接的第一个页面的文件指针,当节中仅当只有为初始化的数据时这个域为0 DOWRD PointerToLinenumbers; //指向节中重定位项开都的文件指针 WORD NumberOfRelocations; //节中重定位项的个数 WORD NumberOfLinenumber; //节中行号项的个数 DWORD Characteristics; //描述节特征的标志 }IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER;这个节头表一般是紧跟着文件头的: 我们那第一个节头分析一下: 发现40后面着就是(2020202F): 一共占了0x102个字节(02 01 00 00),所以就是2BC(BC 02 00 00)+102刚好就是3BE属性是00 0A 10 00 当然,还有一些特殊节,这个列表也在上面的地址里面有详细说明的 接下来说的是几个符号表的内容: COFF符号表: 符号表是一个由记录组成的数组,每个记录长18个字节 以下是标准符号表的格式:
typedef struct _IMAGE_SYMBOL { union { BYTE ShortName[8]; //8字节名称 struct { DWORD Short; //过长时为0 DWORD Long; //偏移量 }Name; PBYTE LongName[2]; //两个指针,其中第二个是指向过长的节名称的,第一个为0(union) }N; DWORD Value; //与符号相关的值 SHORT SectionNumber; //节表的索引,以标识定义这个符号的节 WORD Type; //一个表示类型的数字 BYTE StorageClass; //一个标识储存类别的枚举类型值 BYTE NumberOfAuxSymbol;//在最后一个记录后的辅助符号表数量 }IMAGE_SYMBOL;COFF字符串表: 这个是在符号表后面的字符串表其位置在节头中可以找到,然后符号的个数在符号表中也可以找到,一次我们就可以通过符号表和字符串标表找到相应的符号表中的字符串。
COFF重定位信息: 目标文件中包含的,用来指出当节中的数据被放进映像文件以及将来被加载进内存时应该如何修改这些数据
typedef struct _IMAGE_RELOCATION { union { DOWRD VirtualAdress;//需要重新定位的代码或地址 DWORD RelocCount; }; DWORD SymbolTableIndex; //符号表的索引 WORD Type; //重定位类型 }IMAGE_RELOVATION;明天就要开始实现生成目标文件了,加油!