在把Linux内核源代码生成Image之前,需要把执行文件头结构信息剔除出来。这个过程对理解Linux内核具有很大的帮助。同时,由于是对可执行文件进行直接读写操作,想写DUL工具的童鞋可以在这里学习到基本的二进制文件读写方法。
首先,我们看一下minix可执行文件的格式(Linux和minix很基情)。
struct exec {
unsigned char a_magic[2];
unsigned char a_flags;
unsigned char a_cpu;
unsigned char a_hdrlen;
unsigned char a_unused;
unsigned short a_version;
long a_text;
long a_data;
long a_bss;
long a_entry;
long a_total;
long a_syms;
long a_trsize;
long a_drsize;
long a_tbase;
long a_dbase;
};
下面来具体看下读写代码:linux/tools/build.c line 60-117
char buf[1024];
...
...
for (i=0;i<sizeof buf; i++) buf[i]=0; //buf初始化
if ((id=open(argv[1],O_RDONLY,0))<0) //处理boot二进制文件
die("Unable to open 'boot'");
if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) //读入MINIX_HEADER长度的内容
die("Unable to read header of 'boot'");
if (((long *) buf)[0]!=0x04100301) //其中的0x0301表示minix头部的a_magic魔数;0x10表示a_flag可执行;0x04 - a_cpu
die("Non-Minix header of 'boot'");
if (((long *) buf)[1]!=MINIX_HEADER) //a_hdrlen是否正确
die("Non-Minix header of 'boot'");
if (((long *) buf)[3]!=0) //数据段长是否为0
die("Illegal data segment in 'boot'");
if (((long *) buf)[4]!=0) //a_bss是否为0
die("Illegal bss in 'boot'");
if (((long *) buf)[5] != 0) //a_entry是否为0?哈哈,汇编的入口哦《Linux内核源代码分析——Linux内核入口》中的答案
die("Non-Minix header of 'boot'");
if (((long *) buf)[7] != 0)
die("Illegal symbol table in 'boot'");
i=read(id,buf,sizeof buf);
fprintf(stderr,"Boot sector %d bytes.\n",i);
if (i != 512)
die("Boot block must be exactly 512 bytes");
if ((*(unsigned short *)(buf+510)) != 0xAA55)
die("Boot block hasn't got boot flag (0xAA55)");
buf[508] = (char) minor_root;
buf[509] = (char) major_root;
i=write(1,buf,512); //剔除文件头之后,把执行代码写入标准输出
if (i!=512)
die("Write call failed");
close (id); //处理boot二进制文件结束
...
...
所以,读写二进制文件的关键在于对Unix基本的api的熟悉。可以通过《Unix环境高级编程》得到这些基础知识。