LIB文件格式

LIB文件格式

LIB文件{
   char[8] flag;//“!<arch>\n”
   Section First;
   Section Second;
   Section Long;
   Section Obj[x];//包含有多少个obj文件,就有多少个obj section
}

FirstSec

  第一节,通常就是Lib中的每一个小节。它的名称是“/”。其数据部分的结构如下:
typedef struct {
   unsigned long SymbolNum;       // 库中符号的数量
   unsigned long SymbolOffset[n]; // 符号所在目标节的偏移
   char StrTable[m];              // 符号名称字符串表
}FirstSec;
  第一个成员SymbolNum是符号的数量。注意!它是以Big-Endian方式储存的(x86平台上的数据是以Little-Endian方式储存的。这里应该注意转换。后面给出的convert函数可以在Little-Endian格式与Big-Endian格式之间进行相互转换)。
  第二个成员SymbolOffset是一个数组,它的长度n就是符号的数量,也就是SymbolNum。这个数组储存了每一个符号所在的目标节的偏移。我们可以方便地通过它来查找符号所在的目标文件。注意!它也是以Big-Endian格式储存的。
  第三个成员StrTable是一个字符串表,它的长度m就是SectionHeader.Size的值减去(SymbolNum+1)*4。其结构很简单,就是一堆以‘\0’结尾的字符串(和COFF文件中的字符串表结构相同)。在有的系统中,它还可能是以“/\n”这两个字符结尾的字符串的集合。
  很简单的一个结构,不过有两个成员的长度是不定的。怎么才能方便地从Lib中读出这些数据,留给大家自己想吧!下面我只给出一个进行Little-Endian与Big-Endian互转的函数。

SectionHeader

SectionHeader{
   char Name[16];   // 名称
   char Time[12];   // 时间
   char UserID[6];  // 用户ID
   char GroupID[6]; // 组ID
   char Mode[8];    // 模式
   char Size[10];   // 长度
   char EndOfHeader[2];// 结束符,其内容为“`\n”
}

  要从文件提取obj文件,我们一般只需要关注第二个区段。这个里面保存了如下的信息:
typedef struct {
     unsigned long ObjNum;        // Obj Sec的数量
     unsigned long ObjOffset[x];  // 每一个Obj Sec的偏移
     unsigned long SymbolNum;     // 库中符号的数量
     unsigned short SymbolIdx[n]; // 符号在ObjOffset表中的索引
     char StrTable[m];            // 符号名称字符串表
 }SecondSec;
 但是我们却不能直接去读取他,因为
 ObjOffset[x];  // 每一个Obj Sec的偏移
 长度是不固定的,取决于
 ObjNum;        // Obj Sec的数量

 而且,first section的长度也是不固定的。这怎么办呢?

   解决办法如下:
   first section和second section都以
char szSecName[16] = {'/', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,  0x20,0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
 这样的形式开头。

  我就定义了一个char,一个个字节去读取,遇到'/'就判断后面是不是15个0x20,如果读了2次这样的结构,那么说明到了second section,马上读后面的内容。这就是ObjNum,也就是obj的数量。

  然后去申请一块内存,用来存储ObjOffset[x];  // 每一个Obj Sec的偏移
 ULONG* m_offset = new ULONG[ObjNum],然后从文件里面将obj偏移读取到这个数组。

  请注意,这些偏移值,并不是由小到大排列的,所以得自己排列一次。

  用第二个偏移减去第一个偏移,得到的就是第一个obj section的大小(不是obj文件的大小)。因为每个obj section前面还有一个SectionHeader结构体,所以obj文件真正的偏移是:

  读出来的偏移 offset + sizeof(SectionHeader),从这里开始读,才是obj文件的首地址。



  这一节与第一节很相似!它通常也就是Lib文件的第二个节。它的名字也是“/”(注意:文件中第一个叫“/”的节是第一节,第二个就是第二节)。不过它的结构与第一节有些不同,如下:
typedef struct {
    unsigned long ObjNum;        // Obj Sec的数量
    unsigned long ObjOffset[x];  // 每一个Obj Sec的偏移
    unsigned long SymbolNum;     // 库中符号的数量
    unsigned short SymbolIdx[n]; // 符号在ObjOffset表中的索引
    char StrTable[m];            // 符号名称字符串表
}SecondSec;
  第一个成员ObjNum是库中Obj Sec的数量。
  第二个成员ObjOffset是一个偏移表,它记录了库中所有Obj Sec的偏移。这个表的记录数x就是ObjNum。
  第三个成员SymbolNum与First Sec中的SymbolNum意义相同。
  第四个成员SymbolIdx变成了一个索引,它记录了相应名称字符串在ObjOffset这个表中的位置,我们要通过两次索引才能找到我们所要符号的Obj Sec位置。它的项目数n为SymbolNum。但请注意,这个索引是unsigned short型,不再是unsigned long型。
  第五个成员StrTable结构与First Sec中的一样。不过,它的长度m为SectionHeader.Size的值减去((ObjNum+1)*4+(SymbolNum+2)*2)。
值得注意的是,这里的所有数据都是Little-Endian格式的。千万不要弄错了!

Longname Sec

  这个小节就是一个字符串表,它的名称为“//”,其结构同FirstSec.StrTable。这里就不多说了。

Obj Sec

  这一节中的数据就是COFF文件的原始数据,把它读出来存成文件,就是一个COFF文件。它的格式请参考《COFF格式》一文。
要指出的是它的命名方式有些特殊。如果Obj文件的名称少于16个字符,它就会被保存在SectionHeader的Name成员中,以‘/’字符结尾。如果无法保存在Name成员中,则Name成员的第一个字符就为‘/’,之后再跟上这个名称在Longname Sec中的偏移。
例如:
!<arch>\n
……
LongName Sec:
This_Is_Long_Name0001\0
This_Is_Long_Name0002\0
……
Obj Sec1:
Name[16]:“shortname”
……
Obj Sec2:
Name[16]:“0// 这里使用了第一个长文件名This_Is_Long_Name0001
……
Obj Sec3:
Name[16]:“22// 这里使用了第二个长文件名This_Is_Long_Name0002

参考

1)  http://baike.baidu.com/link?url=CIikyt5pz7dxD5pDv-BW7ov8KO4eRLHe9kyDRpxxB3Ft-fP_bMEPQfOumRGYGjO6DLkGt2OfQDe7_XM4cqQBea

转载于:https://my.oschina.net/u/184090/blog/323627

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值