- 在线时间
- 0 小时
- 最后登录
- 2005-9-17
- 注册时间
- 2005-9-17
- 听众数
- 2
- 收听数
- 0
- 能力
- 0 分
- 体力
- 55 点
- 威望
- 0 点
- 阅读权限
- 20
- 积分
- 21
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 8
- 主题
- 8
- 精华
- 0
- 分享
- 0
- 好友
- 0
升级   16.84% 该用户从未签到
 |
< ><STRONG>重要声明:本文乃转载自其他社区,由于在下无法获得任何有关作者和出处的信息,所以不能在此登出,恳请作者原谅,并希望知情者能告知在下。本着资源的共享的精神,在下深信作者不会拒绝在下的转载行为。同时强烈BS数学中国的下载系统,它不但不能及时给予他人需要的帮助,还浪费了他人大量的时间,仅仅是为了获得无聊的点数,而且遗憾的是,那些点数并不能保证你真能获得帮助!</STRONG></P>5 [7 \, F, _% }- B
< > 在掌握了COFF目标文件的结构后,如果你试着做一个应用程序的连接器(Linker),就会发现,仅仅有目标文件是不够的。我们在连接程序时,不仅仅要用到目标文件,库文件也是必不可少的。<BR> 库文件是怎么样的结构呢?<BR> 其实,库文件的结构也很简单。它就是“一堆”目标文件的集合。把目标文件做成库以后,我们在使用目标文件中所实现的功能时,连接程序会自动在库文件里查找相应的目标文件,并使用它。这大大减少了我们对目标文件的管理工作,减轻了代码重用的负担。<BR> <STRONG>Lib文件中的节</STRONG><BR> COFF格式中所用到的“节”的概念再次出现在Lib格式中。不过,Lib文件的节要简单得多。先让我们来看看它的整体结构:<BR></P>
- h; r- Q m9 r0 z' ~: n$ S<DIV>
. r* R: h, ]% v+ g<TABLE cellSpacing=0 cellPadding=0 width="85%" align=left border=0>
5 \4 J1 A: i* a6 d2 o$ z* D! E: b; X) J8 u* S: \4 ^# L
<TR>% ~1 j( x/ |( g- Y% ~) y& Z! n
<TD> 如右图所示:<BR> Lib格式只有四种类型的节(Section),即First Sec,Second Sec,Longname Sec和Obj Sec;其中Second Sec与Longname Sec是可选节,很多Lib文件中都没有。而开头的Singature只是一个标识,它相当于COFF目标文件中的魔法数字。它是一个长度为8的字符串,值为“!<arch>\n”。<BR> First Sec,顾名思义,就是第一个节。它包含了库中所有的符号名以及这些符号所在的目标文件在库中的位置(绝对偏移)。<BR> Second Sec就是第二节。它的内容和First Sec是相同的。不同的是,Second Sec是一个有序表,通过它来查找库中的符号比通过First Sec来查找要快很多。</TD>0 V$ |6 I3 g" Z& V* c/ z$ M) y: ~
<TD>
* B' @( K# q0 ^9 f! Z8 a<TABLE cellSpacing=0 borderColorDark=#ffffff cellPadding=0 width=100 align=center bgColor=#ffffff borderColorLight=#000000 border=1>0 y u; u7 |! M* @
) d8 ]1 d0 }/ N# p3 b9 D<TR>4 F# {: h a- ]% v2 b% Y3 n- T
<TD>Signature</TD></TR>
' r# R5 |6 m; h" L- T" p- H% r<TR>: R1 r- f {' \# H
<TD>First Sec</TD></TR>5 U- a" Q$ C. K9 x( h
<TR>! d' V% @9 X( L- b
<TD>Second Sec</TD></TR>
/ p" n6 j+ y( Z$ w, d7 L$ n<TR>- O" ?7 h' I0 S! _( E
<TD>Longname Sec</TD></TR>0 P9 @8 R% J0 M' Q
<TR>8 K. u3 Q( J8 m
<TD>Obj Sec1</TD></TR>0 R2 @' g4 O6 X; ^4 Q* V
<TR>
; b! T3 I3 B% a t0 x f0 I<TD>Obj Sec2</TD></TR>( a/ W- f3 Z! d y% A5 N! ^; m4 l
<TR>9 \" [9 S) q! E- ]- a8 k
<TD>……</TD></TR></TABLE></TD></TR></TABLE></DIV>& K; ~' D) X7 g* k; }: c0 f% V Y
<DIV><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR> Longname Sec是长名称节。这一节是一个字符串表。它包含了所有长目标文件名。如果后面的Obj Sec中没有给出相应的目标文件名,我们就要到这一节中来查找。<BR> Obj Sec就是目标文件节。这些节中存储着不同的目标文件的原始数据。</DIV>: Z; Q* V) P: N% O+ ~0 A; ]
<DIV> </DIV>
- ]6 a0 u) R% M/ s2 d6 Q<DIV> 在库文件中,每一节都有两个部分。一个部分是头,另一个部分才是该节的数据;数据紧跟在头的后面。头描述了该节数据的类型、长度等信息。这些头的格式都是相同的。其结构用C语言描述如下:<BR> typedef struct {<BR> char Name[16]; // 名称<BR> char Time[12]; // 时间<BR> char UserID[6]; // 用户ID<BR> char GroupID[6]; // 组ID<BR> char Mode[8]; // 模式<BR> char Size[10]; // 长度<BR> char EndOfHeader[2];// 结束符<BR> } SectionHeader;<BR> 可以看到,头中的数据全都是字符串。用字符串的好处是可以提高格式的兼容性,因为在不同的机器上,数据的排列方式是不同的。有的机器是以Little-Endian方式工作,还有的是以Big-Endian方式工作,它们互不兼容(这两种方式的区别!?请看我的《COFF格式》一文,其中的文件头一节有说明)。用字符串就不会有这种问题(后面我们将会遇到)。但它也有不方便的地方,就是必须把字符串转换成数值,多了一个步骤。<BR> 在这个结构中,最常用的Name、Size以及EndOfHeader三个成员。Name就是节的名称啦!Size也很好理解,就是该节数据的长度。现在要注意的就是这个EndOfHeader成员了!这个成员标志着头的结束,其内容为“`\n”(注意,这里没有打错,是两个字符“`”和“\n”)。怎么样?有点奇怪吧?为什么要有这个结束符?每一节的头长度一定,每节中的数据长度也知道。按顺序向下读不行吗?答案是:不行!因为每一节之间存在间隙!通常是一个字节或零个字节。如果是零个字节倒好,按顺序向下读是OK的。可是如果不为零的话,这样读就要错位了。要知道错位没有,只好用一个结束符来定位了。如果在读头的时候发现结束符不对,那就要一个字节一个字节地向下查找,直到找到结束符,才能算是对齐了。切记!切记!<BR> 当然,通过First Sec或Second Sec中给出的偏移来读数据就不存在这个问题。不会发生错位,放心读吧!<BR> 现在让我们来看看每一节中的数据是什么样子。</DIV> |
zan
|