存档文件格式简介存档文件格式简介
出于好奇,想了解一下linux的存档文件(*.a)的格式。在网上大概找了一下,没找到比较好的(没细找),
所以想自己摸索一下,把它的文件格式弄清楚。结果发现这个文件的格式竟然那么简单。在这里和大家分享
一下,有错误的地方希望大家指正。
1.存档文件(archive)简介
存档文件(*.a)文件相当于windows的静态链接库,他把很多的目标文件(*.o)文件打包为单一的库
文件。在链接程序的时候,需要用到库里面的函数时,只需在链接时加上-lX (X表示库的名字),链接
器会自动得根据要调用函数,...
存档文件格式简介
出于好奇,想了解一下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) <---------------------定义一个函数和一个变量
{
return 0;
};
int error;
[root:/root/test/ar]gcc -o test_ar.o -c test_ar.c
[root:/root/test/ar]cat test_ar_1.c
int test(void) <------------------------定义一个函数
{
return 1;
}
[root:/root/test/ar]gcc -o test_ar_1.o -c test_ar_1.c
[root:/root/test/ar]ar -rv libtest_ar.a test_ar.o test_ar_1.o r - test_ar.o
r - test_ar_1.o
[root:/root/test/ar]ar -vt libtest_ar.a
rw-rw-r-- 0/0 706 Jul 17 15:45 2008 test_ar.o
rw-rw-r-- 0/0 686 Jul 17 15:45 2008 test_ar_1.o
这样,我们把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 |!.| <----头部标志
00000008
上面是头部标志部分,位于文件最前面。
[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
<-------0xa0是紧接着test_ar.o的ar_hdr之后的地址
000000a0 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 000000b0 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 000000c0 b4 00 00 00 00 00 00 00 34 00 00 00 00 00 28 00 |........4.....(.| 000000d0 09 00 06 00 55 89 e5 b8 00 00 00 00 5d c3 00 00 |....U.......]...| 000000e0 00 47 43 43 3a 20 28 47 4e 55 29 20 34 2e 31 2e |.GCC: (GNU) 4.1.| 000000f0 32 20 32 30 30 37 30 39 32 35 20 28 52 65 64 20 |2 20070925 (Red | 00000100 48 61 74 20 34 2e 31 2e 32 2d 33 33 29 00 00 2e |Hat 4.1.2-33)...| 00000110 73 79 6d 74 61 62 00 2e 73 74 72 74 61 62 00 2e |symtab..strtab..| 00000120 73 68 73 74 72 74 61 62 00 2e 74 65 78 74 00 2e |shstrtab..text..|
00000130 64 61 74 61 00 2e 62 73 73 00 2e 63 6f 6d 6d 65 |data..bss..comme| 00000140 6e 74 00 2e 6e 6f 74 65 2e 47 4e 55 2d 73 74 61 |nt..note.GNU-sta| 00000150 63 6b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |ck..............| 00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000170 00 00 00 00 00 00 00 00 00 00 00 00 1b 00 00 00 |................| 00000180 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 00000190 0a 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................| 000001a0 00 00 00 00 21 00 00 00 01 00 00 00 03 00 00 00 |....!...........| 000001b0 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| 000001c0 00 00 00 00 04 00 00 00 00 00 00 00 27 00 00 00 |............'...| 000001d0 08 00 00 00 03 00 00 00 00 00 00 00 40 00 00 00 |............@...| 000001e0 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................| 000001f0 00 00 00 00 2c 00 00 00 01 00 00 00 00 00 00 00 |....,...........| 00000200 00 00 00 00 40 00 00 00 2e 00 00 00 00 00 00 00 |....@...........| 00000210 00 00 00 00 01 00 00 00 00 00 00 00 35 00 00 00 |............5...| 00000220 01 00 00 00 00 00 00 00 00 00 00 00 6e 00 00 00 |............n...| 00000230 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000240 00 00 00 00 11 00 00 00 03 00 00 00 00 00 00 00 |................| 00000250 00 00 00 00 6e 00 00 00 45 00 00 00 00 00 00 00 |....n...E.......| 00000260 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 |................| 00000270 02 00 00 00 00 00 00 00 00 00 00 00 1c 02 00 00 |................| 00000280 90 00 00 00 08 00 00 00 07 00 00 00 04 00 00 00 |................| 00000290 10 00 00 00 09 00 00 00 03 00 00 00 00 00 00 00 |................| 000002a0 00 00 00 00 ac 02 00 00 16 00 00 00 00 00 00 00 |................| 000002b0 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 000002c0 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 000002d0 00 00 00 00 00 00 00 00 04 00 f1 ff 00 00 00 00 |................| 000002e0 00 00 00 00 00 00 00 00 03 00 01 00 00 00 00 00 |................| 000002f0 00 00 00 00 00 00 00 00 03 00 02 00 00 00 00 00 |................| 00000300 00 00 00 00 00 00 00 00 03 00 03 00 00 00 00 00 |................| 00000310 00 00 00 00 00 00 00 00 03 00 05 00 00 00 00 00 |................| 00000320 00 00 00 00 00 00 00 00 03 00 04 00 0b 00 00 00 |................| 00000330 00 00 00 00 0a 00 00 00 12 00 01 00 10 00 00 00 |................| 00000340 04 00 00 00 04 00 00 00 11 00 f2 ff 00 74 65 73 |.............tes| 00000350 74 5f 61 72 2e 63 00 74 65 73 74 00 65 72 72 6f |t_ar.c.test.erro| 00000360 72 00 |r.|
00000362
[root:/root/test/ar]hexdump -C -s 0x0 -n 706 test_ar.o
00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 01 00 03 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 b4 00 00 00 00 00 00 00 34 00 00 00 00 00 28 00 |........4.....(.| 00000030 09 00 06 00 55 89 e5 b8 00 00 00 00 5d c3 00 00 |....U.......]...| 00000040 00 47 43 43 3a 20 28 47 4e 55 29 20 34 2e 31 2e |.GCC: (GNU) 4.1.| 00000050 32 20 32 30 30 37 30 39 32 35 20 28 52 65 64 20 |2 20070925 (Red |
00000060 48 61 74 20 34 2e 31 2e 32 2d 33 33 29 00 00 2e |Hat 4.1.2-33)...| 00000070 73 79 6d 74 61 62 00 2e 73 74 72 74 61 62 00 2e |symtab..strtab..| 00000080 73 68 73 74 72 74 61 62 00 2e 74 65 78 74 00 2e |shstrtab..text..| 00000090 64 61 74 61 00 2e 62 73 73 00 2e 63 6f 6d 6d 65 |data..bss..comme| 000000a0 6e 74 00 2e 6e 6f 74 65 2e 47 4e 55 2d 73 74 61 |nt..note.GNU-sta| 000000b0 63 6b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |ck..............| 000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000d0 00 00 00 00 00 00 00 00 00 00 00 00 1b 00 00 00 |................| 000000e0 01 00 00 00 06 00 00 00 00 00 00 00 34 00 00 00 |............4...| 000000f0 0a 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................| 00000100 00 00 00 00 21 00 00 00 01 00 00 00 03 00 00 00 |....!...........| 00000110 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........| 00000120 00 00 00 00 04 00 00 00 00 00 00 00 27 00 00 00 |............'...| 00000130 08 00 00 00 03 00 00 00 00 00 00 00 40 00 00 00 |............@...| 00000140 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................| 00000150 00 00 00 00 2c 00 00 00 01 00 00 00 00 00 00 00 |....,...........| 00000160 00 00 00 00 40 00 00 00 2e 00 00 00 00 00 00 00 |....@...........| 00000170 00 00 00 00 01 00 00 00 00 00 00 00 35 00 00 00 |............5...| 00000180 01 00 00 00 00 00 00 00 00 00 00 00 6e 00 00 00 |............n...| 00000190 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 000001a0 00 00 00 00 11 00 00 00 03 00 00 00 00 00 00 00 |................| 000001b0 00 00 00 00 6e 00 00 00 45 00 00 00 00 00 00 00 |....n...E.......| 000001c0 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 |................| 000001d0 02 00 00 00 00 00 00 00 00 00 00 00 1c 02 00 00 |................| 000001e0 90 00 00 00 08 00 00 00 07 00 00 00 04 00 00 00 |................| 000001f0 10 00 00 00 09 00 00 00 03 00 00 00 00 00 00 00 |................| 00000200 00 00 00 00 ac 02 00 00 16 00 00 00 00 00 00 00 |................| 00000210 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 00000220 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 00000230 00 00 00 00 00 00 00 00 04 00 f1 ff 00 00 00 00 |................| 00000240 00 00 00 00 00 00 00 00 03 00 01 00 00 00 00 00 |................| 00000250 00 00 00 00 00 00 00 00 03 00 02 00 00 00 00 00 |................| 00000260 00 00 00 00 00 00 00 00 03 00 03 00 00 00 00 00 |................| 00000270 00 00 00 00 00 00 00 00 03 00 05 00 00 00 00 00 |................| 00000280 00 00 00 00 00 00 00 00 03 00 04 00 0b 00 00 00 |................| 00000290 00 00 00 00 0a 00 00 00 12 00 01 00 10 00 00 00 |................| 000002a0 04 00 00 00 04 00 00 00 11 00 f2 ff 00 74 65 73 |.............tes| 000002b0 74 5f 61 72 2e 63 00 74 65 73 74 00 65 72 72 6f |t_ar.c.test.erro| 000002c0 72 00 |r.|
000002c2
对比上面两个输出,内容是完全一致的,正是我之前期盼的那样。
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)从库中复制一份出来,
链接到可执行程序中。
本文档为【存档文件格式简介】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。