免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1190 | 回复: 0
打印 上一主题 下一主题

linux存档文件(archive)分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-28 16:53 |只看该作者 |倒序浏览
出于好奇,想了解一下linux的存档文件(*.a)的格式。在网上大概找了一下,没找到比较好的(没细找),所以想自己摸索
一下,把它的文件格式弄清楚。结构发现这个文件的格式竟然那么简单。在这里和大家分享一下,有错误的地方希望大家指正。
1.存档文件(archive)简介
存档文件(*.a)文件相当于windows的静态链接库,他把很多的目标文件(*.o)文件打包为单一的库文件。在链接程序
的时候,需要用到库里面的函数时,只需在链接时加上-lX    (X表示库的名字),链接器会自动得根据要调用函数,找到相应的
目标文件,链接到可执行程序中,不需要的目标不会被链接到可执行程序中。
2.archive文件的格式[参考/usr/include/ar.h中的说明]
archive文件的格式主要保护两个部分,主要是:
一个头部标志ARMAG,
多个数据区。
['头部标志'和'数据区'是我自己为了方便说明起的名字,跟官方的说法应该是有出入的]。
2.1 头部标志
头部标志的作用仅用于说明这是一个archive文件
在ar.h中定义了两个宏:
#define ARMAG   "!\n" /* String that begins an archive file.  */
#define SARMAG  8       /* Size of that string.  */
ARMAG指明了头部标志的内容,SARMAG说明了头部标志的长度。
2.2 数据区
一个archive文件有多个数据区,每个数据区包含一个头部(ar_hdr)和一段数据段,他们是紧跟在一起的。
在ar.h中ar_hdr的声明是这样的
struct ar_hdr
{
     char ar_name[16];       /* Member file name, sometimes / terminated. */
      char ar_date[12];       /* File date, decimal seconds since Epoch.  */
       char ar_uid[6], ar_gid[6];  /* User and group IDs, in ASCII decimal.  */
       char ar_mode[8];        /* File mode, in ASCII octal.  */
       char ar_size[10];       /* File size, in ASCII decimal.  */
       char ar_fmag[2];        /* Always contains ARFMAG.  */
};
在archive中每个目标文件(*.o)都会被分配一个数据区,数据区的数据段是该目标文件(*.o)原封不动的拷贝,ar_hdr
则存放了对该目标文件的说明。
ar_name文件说明了目标文件的名字(以/作为终止符),
ar_date说明了该文件的日期,
ar_uid、ar_gid指明了该目标文件的用户ID和组ID,
ar_mode指明了文件的访问属性(权限),
ar_size指明了目标文件的大小,同时是该数据区数据段的大小
ar_fmag总是包含ARFMAG,该宏被定义为#define ARFMAG  "`\n" , 用户指明ar_hdr的尾部。

除了为每个目标文件分配一个数据区之外,archive文件还添加一个特殊的数据区,它位于第一个数据区,它的数据段
包含了该archive文件的符号数(函数/全局变量)、符号名称、符号所在目标文件的偏移量。
3.archive文件的分析
首先,建立两个测试文件,并把它们加到archive文件中:
[root:/root/test/ar]cat test_ar.c
int test(void)   
这样,我们把test_ar.o test_ar_1.o放到了libtest_ar.a中。我们用hexdump对libtest_ar.a进程剖析
(不熟悉hexdump用法的参见man hexdump)
[root:/root/test/ar]hexdump -C -s 0x0 -n 8 libtest_ar.a   
00000000  21 3c 61 72 63 68 3e 0a                           |!.|  
上面是头部标志部分,位于文件最前面。
[root:/root/test/ar]hexdump -C -s 0x8 -n 60 libtest_ar.a
00000008  2f 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |/               |
00000018  31 32 31 36 32 38 30 37  39 36 20 20 30 20 20 20  |1216280796  0   |
00000028  20 20 30 20 20 20 20 20  30 20 20 20 20 20 20 20  |  0     0       |
00000038  33 32 20 20 20 20 20 20  20 20 60 0a              |32        `.|
00000044
上面是第一个数据区的头部ar_hdr,名字为空, '/'是终止符,1216280796是文件的时间,是被字符串化
的time_t类型的数据,三个0中前两个分别为uid和gid,后面一个标志目标文件属性,在这忽略,32是该数据
区后面数据段的长度, `.是终止符。

[root:/root/test/ar]hexdump -C -s 0x44 -n 32 libtest_ar.a
00000044  00 00 00 03 00 00 00 64  00 00 00 64 00 00 03 62  |.......d...d...b|
00000054  74 65 73 74 00 65 72 72  6f 72 00 74 65 73 74 00  |test.error.test.|
上面是特殊数据区的数据段,第一行中00 00 00 03表示的是该archive文件向外
导出的符号数,这里为3(注意,这里的数据都是按大尾的编码方式的)。00 00 00 64 、
00 00 00 64、 00 00 03 62分别是三个符号所在目标文件的ar_hdr在该archive文件中的
偏移量,分别是0x64、0x64、0x362,紧接着是符号名称的字符串表。
[root:/root/test/ar]hexdump -C -s 0x64 -n 60 libtest_ar.a
00000064  74 65 73 74 5f 61 72 2e  6f 2f 20 20 20 20 20 20  |test_ar.o/      |
00000074  31 32 31 36 32 38 30 37  31 38 20 20 30 20 20 20  |1216280718  0   |
00000084  20 20 30 20 20 20 20 20  31 30 30 36 36 34 20 20  |  0     100664  |
00000094  37 30 36 20 20 20 20 20  20 20 60 0a              |706       `.|
000000a0
[root:/root/test/ar]hexdump -C -s 0x362 -n 60 libtest_ar.a
00000362  74 65 73 74 5f 61 72 5f  31 2e 6f 2f 20 20 20 20  |test_ar_1.o/    |
00000372  31 32 31 36 32 38 30 37  35 30 20 20 30 20 20 20  |1216280750  0   |
00000382  20 20 30 20 20 20 20 20  31 30 30 36 36 34 20 20  |  0     100664  |
00000392  36 38 36 20 20 20 20 20  20 20 60 0a              |686       `.|
0000039e
上面验证了0x64、0x362是目标文件的ar_hdr在该archive文件中的偏移量,可以看出,第一个test和error定义在
test_ar.o中,第二个test定义在test_ar_1.o中,这和我们之前写的文件是相符的。
上面第一命令,同样test_ar.o/是目标文件的名字,1216280718是时间,两个0分别是uid和gid,100644表示文件
权限(rw_rw_r__), 706是该目标文件的大小,也是下面数据段的大小。
[root:/root/test/ar]ls -l *.o
-rw-rw-r-- 1 root root 686 07-17 15:45 test_ar_1.o
-rw-rw-r-- 1 root root 706 07-17 15:45 test_ar.o
和archive文件中的数据相符的。
接下来我们对比一下存档中的内容和目标文件的内容。
[root:/root/test/ar]hexdump -C -s 0xa0 -n 706 libtest_ar.a      
对比上面两个输出,内容是完全一致的,正是我之前期盼的那样。
4.链接
在上面的例子中,我故意在test_ar.c、test_ar_1.c中定义了同名的函数。但一个返回0,
一个返回1,主要是为了检查符号的解析。
我又写了一个测试文件。
[root:/root/test/ar]cat main.c
#include
int main()
{
        int i = test();
        printf("%d\n", i);
        return 0;
}
[root:/root/test/ar]gcc -o main main.c -L. -ltest_ar
[root:/root/test/ar]./main
0
输出结果为0,也就是它调用的时test_ar.o中的test()函数而不是调用test_ar_1.o中的函数。
我们看上面符号表中的数据
00000044  00 00 00 03 00 00 00 64  00 00 00 64 00 00 03 62  |.......d...d...b|
00000054  74 65 73 74 00 65 72 72  6f 72 00 74 65 73 74 00  |test.error.test.|
test_ar.o中test在前面,链接的过程我猜想是这样的[如有错误请纠正]:
1.函数遇到一个未解析的符号,它在-l指定的连接归档库中查找。
2.当查找到第一个符合的符号时,他即停止搜索。
3.根据符号获得目标文件在archive中的偏移量,把相关的目标文件(*.o)从库中复制一份出来,
链接到可执行程序中。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/73874/showart_1671167.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP