OS39.5.【Linux】分析ar命令生成的归档文件的格式

目录

1.知识回顾

2.archives是什么

3.ar命令打包非链接文件

ar命令特别说明

准备工作

十六进制分析test.a

归档文件头(魔数)

文件内容

元数据

文件名(char ar_name[16])

时间戳(char ar_date[12])

UID(char ar_uid[6])

GID(char ar_gid[6])

拥有者、所属组、其他人的八进制权限(char ar_mode[8])

文件大小(char ar_size[10])

ar_fmag

所有元数据一览


1.知识回顾

之前在OS39.【Linux】动态库和静态库 自制静态库文章提到过使用ar -rc命令生成静态库,即将所有o文件的集合(不含main函数的源文件生成的o文件)打包(ar命令)为静态库

其实ar命令不仅仅能打包o文件,准确来说,ar命令的作用是"create, modify, and extract from archives",即创建、修改、解压归档文件

博主比较好奇,就研究了一下ar归档文件的格式

2.archives是什么

百度翻译对archive的解释:

man手册对archives的描述:

The GNU ar program creates, modifies, and extracts from archives.  An archive is a single file holding a collection of other files in a structure that makes it possible to retrieve the original individual files (called members of the archive).

archives定义:

1.归档是一个单一文件,以一种结构包含一组其他文件

2.这种结构可以检索出(retrieve)原始各个文件(称为归档成员文件)

man手册对文件内容的描述:

       The original files' contents, mode (permissions), timestamp, owner, and group are preserved in the archive, and can be restored on extraction.

可以看出"归档是一个单一文件,以一种结构包含一组其他文件"中的结构还含有其他内容,例如模式(权限),时间戳,所有者,所属组,还有文件的原始内容,说明: 归档文件中含有的其他文件没有经过压缩

3.ar命令打包非链接文件

从以上分析可以看出ar命令不仅仅可以打包链接文件,还可以打包非链接文件

ar命令特别说明

ar命令不是从Linux才有的,其实早在Unix就已经出现了ar命令\,可以参考Unix早期版本的源代码:

Unix版本树:

https://www.tuhs.org/cgi-bin/utree.pl

Unix V10源代码:

https://www.tuhs.org/cgi-bin/utree.pl?file=V10

准备工作

现将3个文件打包为一个归档文件

文件1: test.txt

teststring

文件2: test.bin

四字节的十六进制数据

0xAA 0xBB 0xCC 0xDD
printf '\xAA\xBB\xCC\xDD' > test.bin

文件3: test.c

int main()
{
    return 0;
}

修改test.bin的拥有者为root:

sudo chown root test.bin

test.bin添加可执行权限:

sudo chmod a+x test.bin

修改test.txt的所属组为root:

sudo chgrp root test.txt

打包为test.a:

ar -rc test.a test.txt test.c test.bin

使用file命令分析test.a:

test.a是一个ar命令生成的归档文件

十六进制分析test.a

十六进制编辑器打开test.a,这里使用Windows下的HxD:

归档文件头(魔数)

文件开头的字节就是归档文件的魔数,用来表明这是一个归档文件

是!<arch>还是!<arch>加上后面的0x0A呢? 换句话说,是下图的哪种情况?

由于ar命令是Unix引入的,那么这要查Unix源码了,在Unix V10的/cmd/asd/ar.h中:

#define	ARMAG	"!<arch>\n"
#define	SARMAG	8

#define	ARFMAG	"`\n"

struct ar_hdr {
	char	ar_name[16];
	char	ar_date[12];
	char	ar_uid[6];
	char	ar_gid[6];
	char	ar_mode[8];
	char	ar_size[10];
	char	ar_fmag[2];
};

这个ARMAG是ARchive MAGic number(归档文件魔数)的缩写,其为"!<arch>\n",需要带上\n,而且\n的ASCII码为0x0A

那么这个图是对的:

文件内容

原来没有归档时的文件内容:

对应到下图红框部分:

注意:所有数据按偶字节边界对齐,即每个成员(归档文件头 + 归档文件内容)的起始偏移必须是2的倍数,因此某些情况下,文件内容的末尾会添加0x0A用于对齐,就像上图的那样

元数据

上方代码的struct ar_hdr结构体ar_hdr是archive_header的缩写,即归档文件头,存储这每个文件的元数据(meta data),有心的读者可能会去算这个结构体的大小:

#include <iostream>
struct ar_hdr {
	char	ar_name[16];
	char	ar_date[12];
	char	ar_uid[6];
	char	ar_gid[6];
	char	ar_mode[8];
	char	ar_size[10];
	char	ar_fmag[2];
};

int main()
{
	std::cout<<sizeof(ar_hdr);
    return 0;
} 

运行结果:

占60字节,对应到test.a,从文件名开始,到文件内容前,统计字节数:

0x43-0x08+1==0x3C==十进制的60

0x8B-0x50+1==0x3C==十进制的60

0xE5-0xAA+1==0x3C==十进制的60

发现从文件名开始,到文件内容前这部分占的字节数都是60,恰为struct ar_hdr结构体的大小

结论: 显然这部分内容就是每个文件的struct ar_hdr结构体实例化后的内容

有了这个结构体就能解析struct ar_hdr结构体的各个字段了

文件名(char ar_name[16])

下图黄框部分:

Unix源代码的/cmd/ar.c是这样打印归档文件中的各个文件名的:

char *
trim(s)
char *s;
{
	register char *p1, *p2;

	for(p1 = s; *p1; p1++)
		;
	while(p1 > s) {
		if(*--p1 != '/')
			break;
		*p1 = 0;
	}
	p2 = s;
	for(p1 = s; *p1; p1++)
		if(*p1 == '/')
			p2 = p1+1;
	return(p2);
}

结论: 文件名的结尾是/

时间戳(char ar_date[12])

下图紫框部分:

UID(char ar_uid[6])

下图橙框部分:

GID(char ar_gid[6])

下图灰框部分:

拥有者、所属组、其他人的八进制权限(char ar_mode[8])

下图蓝框部分:

文件大小(char ar_size[10])

文件大小是以ASCII码的形式呈现的,下图棕框部分:

ar_fmag

这个ar_fmag是每个归档文件头末尾必须要有的,在https://unix.org/whitepapers/ar-format.html网站中有说明:

例如在Unix V10源码的/cmd/ar.c的getdir()函数中(截取部分代码):

if (strncmp(arbuf.ar_fmag, ARFMAG, sizeof(arbuf.ar_fmag))) {
		fprintf(stderr, "ar: malformed archive (at %ld)\n", lseek(af, 0L, 1));
		done(1);
	}

会发现strncmp将arbuf.ar_fmag和宏ARFMAG比较,而ARFMAG会被替换为0x60 0x0A,也就是/cmd/asd/ar.h中定义的:

#define	ARFMAG	"`\n"
所有元数据一览

下图的每一格中的数据代表一个字节,用十六进制表示

213C617263683E0A746573742E747874
2F202020202020203020202020202020
20202020302020202020302020202020
36343420202020203131202020202020
2020600A74657374737472696E670A0A
746573742E632F202020202020202020
30202020202020202020202030202020
20203020202020203634342020202020
32392020202020202020600A696E7420
6D61696E28290A7B0A20202020726574
75726E20303B0A7D0A0A746573742E62
696E2F20202020202020302020202020
20202020202030202020202030202020
20203634342020202020342020202020
20202020600AAABBCCDD
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值