关键词: 网卡
ARP头文件的解释Unix系统(共5篇)
篇1:ARP头文件的解释Unix系统
[color=red:f163fa8829][size=18:f163fa8829] 作者:陈嘉洲 前几日,为了将一台安装SCOUNIX5.0.5主机上的TAR打包文件备份,需要将其通 过网络传送到另外一台配有磁带机的UNIX主机上,两台主机通过TX530网卡相连,用FTP 传送的时候,前几个文件分别在10M、20M
[color=red:f163fa8829][size=18:f163fa8829]
作者:陈嘉洲
前几日,为了将一台安装SCO UNIX 5.0.5主机上的TAR打包文件备份, 需要将其通
过网络传送到另外一台配有磁带机的UNIX主机上。两台主机通过TX530网卡相连,用FTP
传送的时候,前几个文件分别在10M、20M字节大小,都能够顺利传送。但其中有一个文
件压缩后体积已达98M之巨,传送了几次,要么只能传40M, 要么只能传20M左右就导致
网络崩溃,换画面PING对方主机,本应为零的速率延迟降为2400多毫秒,而且误码率极
高,只有重新启动两台主机才能恢复网络通讯。
UNIX的SHELL功能强大,非WINDOWS可比,从上面使用的TAR、FTP已可管窥。同样,
UNIX已经提供了文件切割功能,不需要费力气去寻找第三方的文件切割程序。能完成
这个功能的UNIX命令就是DD。
要切割的大文件为DGJD,共98336321字节,则:
dd if=dgjd of=zz1 bs=1 count=0000
dd if=dgjd of=zz2 bs=1 count=20000000 skip=20000000
dd if=dgjd of=zz3 bs=1 count=20000000 skip=40000000
dd if=dgjd of=zz4 bs=1 count=20000000 skip=60000000
dd if=dgjd of=zz5 bs=1 count=18336321 skip=80000000
其中IF(INPUT FILENAME)是要切割的大文件名,OF(OUTPUT FILENAME)是切割后
的子文件名,BS是指明以多少字节作为一个切割记录单位,COUNT是要切割的单位记录数,
SKIP是说明切割时的起点,单位同样以BS设定值为准。通过上述五条指令就将DGJD大文件
切割成为4个2千万字节、1个18336321字节的子文件。要注意的是SKIP的值不能错。 由此
也不难看出,DD切割是“非损耗”式的切割,并且支持从任意位置开始的任意大小的切割。
要将生成的ZZ1、ZZ2、ZZ3、ZZ4四个子文件组装为XDGJD,则:
dd if=zz1 of=xdgjd bs=1 count=20000000
dd if=zz2 of=xdgjd bs=1 count=20000000 seek=20000000
dd if=zz3 of=xdgjd bs=1 count=20000000 seek=40000000
dd if=zz4 of=xdgjd bs=1 count=20000000 seek=60000000
dd if=zz5 of=xdgjd bs=1 count=18336321 seek=80000000
其中SKIP参数改为SEEK参数,指明组装的新大文件XDGJD每次的开始位置是从文件头开
始多少字节。如果缺省,则组装从文件头开始,显然这不是我们每次都希望的, 所以需用
SEEK参数明确指出开始位置,
通过以上5个指令,即可将5个子文件重新组装为一个大文件。
将切割后生成的子文件重新用FTP传送,结果有的能够顺利传送, 有的仍然导致网络瘫痪,
不怕,继续切割,切成每个一千万字节,再传,OK!成功传送!
测试表明,每次传送的文件最好小于12M字节,否则可能导致网络故障。另外,DD这个
命令最初是为了进行编码转换而设计的,用于在大型机中将EBCDIC字符代码转换为ASCII代
码,但此功能已不常用,现在DD成了文件系统备份的工具,以及做一些类似文件切割的“另
类业务”,正所谓“有心栽花花不开,无心插柳柳成荫”,不过对于用户来说,重要的是软
件能否完成自己需要的功能,它的“本职工作”是什么并不重要,“不管白猫黑猫,捉住老
鼠就是好猫”!实用为本,软件的生命力就在于实用。
[/color:f163fa8829][/size:f163fa8829]
Nestle 回复于:-02-20 09:18:41不错,不过我用split命令,这个命令原本就是用来分割文件的。组合的时候按字母顺序拷到一块就可以了。
luxr 回复于:2003-02-20 11:41:18[quote:a742325a51=“Nestle”]不错,不过我用split命令,这个命令原本就是用来分割文件的。组合的时候按字母顺序拷到一块就可以了。[/quote:a742325a51]
请详细介绍split命令的用法
hongliny 回复于:2003-02-20 11:49:12对,应将split的用法写出来,向陈嘉洲兄一样,搞一个示例!
muzx 回复于:2003-02-20 13:09:02各有各的用处嘛!
split 计量单位是行(line),只能对行式文件进行操作;
而dd 的计量单位是字节(byte),可以方便的对二进制文件进行操作。
陈君涛 回复于:2003-02-21 14:15:29谢谢陈嘉洲兄的例子.
bzzyg 回复于:2003-02-21 15:38:47[quote:e28a0cf99a=“luxr”]
请详细介绍split命令的用法[/quote:e28a0cf99a]
介绍是可以,不过太多了.还是在你的unix机器上用man split看吧.
午夜聆听 回复于:2003-02-21 16:22:46收下
zoukunhong 回复于:2003-03-12 17:15:11可能陈嘉洲兄的网络配置有问题,我的网络并不是很快,但一二百M文件10分钟搞掂
saintdragon 回复于:2003-03-13 10:35:05不错,DD和SPLIT用的场合不同。DD其实比SPLIT要强大
sd-feng 回复于:2003-03-13 14:14:31好
answer 回复于:2003-03-13 16:52:09要试一下。
快乐羔羊 回复于:2003-03-20 11:13:09本人试了一下 split:
#split -l 100 inputfile outfile
xiechq 回复于:2003-03-22 19:22:11split也可以按容量来分割文件的。
海德 回复于:2003-03-27 06:54:24:lol:
小跑 回复于:2003-03-29 22:27:40弓虽!!
maidx 回复于:2003-12-21 21:11:30好像530tx有bug.
原文转自:www.ltesting.net
篇2:ARP头文件的解释Unix系统
如果系统中还没有加载 proc 文件系统,可以通过如下命令加载 proc 文件系统:
mount -t proc proc /proc
上述命令将成功加载你的 proc 文件系统。更多细节请阅读 mount 命令的 man page。
篇3:ARP头文件的解释Unix系统
理解/proc文件系统理解/proc文件系统
◆ 介绍/proc
在过去那些糟糕的日子里,只能通过直接访问内核内存(/dev/kmem)获取进程数据,比如运行ps(1)命令时。为了实现这种访问,需要超级用户权限,而且步骤相当复杂。Sun公司从UNIXSVR4开始解决了进程数据访问问题,现在,可以简单地通过/proc访问进程数据。
/proc文件系统不是普通意义上的文件系统,它是一个到运行中进程地址空间的访问接口。通过/proc,可以用标准Unix系统调用(比如open、read()、write()、ioctl()等等)访问进程地址空间。事实上,Solaris ps(1)命令正是利用/proc获取进程状态。
S (l) 进程状态:
O 正在运行
S 休眠: 进程正在等待某个事件发生/完成
R 可运行: 进程位于运行队列中
Z 僵尸状态: 进程结束了,但是其父进程未处理SIGCHLD信号
T 进程暂停: 可能是任务控制信号所致,或者正在被
跟踪调试
/proc下的大文件对应运行中进程的地址空间,不是标准Unix文件。事实上每个文件名对应运行中进程的PID,文件属主、属组对应进程拥有者的real-uid和primary-gid。权限控制与普通Unix文件一样。文件大小是最令人迷惑的地方,事实上相当好理解,对应进程内存映像大小,并不真正占用硬盘空间,所以你不必担心空间浪费的问题。不要企图删除这些文件!观察图A中列举的/proc例子:
--------------------------------------------------------------------------
$ ls -l /proc
total 43384
-rw------- 1 root root 0 Apr 2 20:07 00000
-rw------- 1 root root 393216 Apr 2 20:07 00001
-rw------- 1 root root 0 Apr 2 20:07 00002
-rw------- 1 root root 0 Apr 2 20:07 00003
-rw------- 1 root root 1695744 Apr 2 20:07 00081
-rw------- 1 root root 1597440 Apr 2 20:07 00083
-rw------- 1 root root 1777664 Apr 2 20:08 00096
-rw------- 1 root root 1683456 Apr 2 20:08 00099
-rw------- 1 root root 1589248 Apr 2 20:08 00101
-rw------- 1 root root 1445888 Apr 2 20:08 00116
-rw------- 1 root root 1404928 Apr 2 20:08 00126
-rw------- 1 root root 798720 Apr 2 20:08 00135
-rw------- 1 root root 1368064 Apr 2 20:08 00195
-rw------- 1 root root 1585152 Apr 2 20:08 00197
-rw------- 1 root root 1368064 Apr 2 20:08 00200
-rw------- 1 root other 225280 Apr 2 20:08 00201
-rw------- 1 root root 1454080 Apr 2 20:08 00203
-rw------- 1 root root 1519616 Apr 2 20:14 00243
-rw------- 1 rthomas wheel 1499136 Apr 2 20:14 00245
-rw------- 1 rthomas wheel 806912 Apr 2 20:16 00261
$
图A: /proc例子
--------------------------------------------------------------------------
操作/proc下文件的方式和操作普通Unix文件一样,可以使用所有你熟悉的系统调用,包括ioctl()。在内核中,针对/proc下文件的vnode操作被转向procfs。这意味着操作vnode的系统调用(比如lookuppn())实际上最终转向procfs-savvy系统调用(比如prlookup())。
◆ /proc能告诉我什么
Solaris下使用/proc的工具相当完善,位于/usr/proc/bin目录中。这些工具提供了一种访问任意指定进程临界数据的简捷办法。比如,想知道一个进程已经打开了多少文件,你可以使用crash(1M)(见鬼,我不会),但是你是root吗?不必担心,可以用/usr/proc/bin/pfiles获取这种信息,图B演示了pfiles(1)命令的使用:
--------------------------------------------------------------------------
[scz@ /export/home/scz]>ps
PID TTY TIME CMD
637 pts/3 0:00 bash
[scz@ /export/home/scz]>pfiles 637
637: -bash
Current rlimit: 64 file descriptors
0: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
1: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
2: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR
3: S_IFDOOR mode:0444 dev:191,0 ino:1618164880 uid:0 gid:0 size:0
O_RDONLY|O_LARGEFILE FD_CLOEXEC door to nscd[213]
63: S_IFCHR mode:0620 dev:151,0 ino:196787 uid:500 gid:7 rdev:24,3
O_RDWR FD_CLOEXEC
[scz@ /export/home/scz]>
图B: 使用pfiles(1)命令
--------------------------------------------------------------------------
正如上面演示的,/usr/proc/bin下的命令使用很简单,只需要在命令行上指定PID。然而,留心权限许可设置,与所有普通Unix文件一样,你无权访问那些权限设置上禁止访问的指定PID的进程数据。
花点事件看看proc(1)手册页,熟悉其中介绍的命令,你将学会列举指定进程相关的库、进程信号设置、进程信任设置,你甚至可以暂停、重启进程。
◆ 编写/proc工具
/proc的魅力在于它包含了你可能想知道的关于一个进程的任何信息,你只需要简单地从中获取。/usr/include/sys/procfs.h文件中定义了两个结构,prstatus和prpsinfo,从中可以获取指定进程的很多信息。下面是个例子,开发者想知道他的应用程序究竟占用了多少内存。简单!ls /proc就可以知道了。但是,他还想知道更多细节,他需要知道总的映像大小、常驻部分的大小、堆区(heap)大小、栈区(stack)大小,
此外,他希望能够定期跟踪这些数据信息,类似vmstat(1M)那种方式。如上所述,听起来象是一个令人生畏的任务。
译者: Solaris 2.6开始这两个结构定义在/usr/include/sys/old_procfs.h文件中
然而,通过使用/proc文件系统,我们可以使这项编程挑战变得容易些。我们写的这个工具称做memlook,将显示指定PID对应的内存统计信息。此外,可以在命令行上指定一个时间间隔,以便定期重新检测内存利用信息。图C演示了一次简单的输出:
--------------------------------------------------------------------------
$ memlook 245
PID IMAGE RSS HEAP STACK
245 1499136 1044480 24581 8192
$
图C: memlook的输出举例
--------------------------------------------------------------------------
下面是memlook.c的源代码
--------------------------------------------------------------------------
/*
* @(#)memlook.c 1.0 10 Nov
* Robert Owen Thomas robt@cymru.com
* memlook.c -- A process memory utilization reporting tool.
*
* gcc -Wall -O3 -o memlook memlook.c
*/
#pragma ident ”@(#)memlook.c 1.0 10 Nov 1997 Robert Owen Thomas robt@cymru.com“
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int counter = 10;
int showUsage ( const char * );
void getInfo ( int, int );
int main ( int argc, char * argv[] )
{
int fd, pid, timeloop = 0;
char pidpath[BUFSIZ]; /* /usr/include/stdio.h: #define BUFSIZ 1024 */
switch ( argc )
{
case 2:
break;
case 3:
timeloop = atoi( argv[2] );
break;
default:
showUsage( argv[0] );
break;
} /* end of switch */
pid = atoi( argv[1] );
sprintf( pidpath, ”/proc/%-d“, pid ); /* -表示向左靠 */
if ( ( fd = open( pidpath, O_RDONLY ) ) < 0 )
{
perror( pidpath );
exit( 1 );
}
if ( 0 < timeloop )
{
for ( ; ; )
{
getInfo( fd, pid );
sleep( timeloop );
}
}
getInfo( fd, pid );
close( fd );
exit( 0 );
} /* end of main */
int showUsage ( const char * progname )
{
fprintf( stderr, ”%s: usage: %s < PID >[time delay]n“, progname, progname );
exit( 3 );
} /* end of showUsage */
void getInfo ( int fd, int pid )
{
prpsinfo_t prp;
prstatus_t prs;
if ( ioctl( fd, PIOCPSINFO, &prp ) < 0 )
{
perror( ”ioctl“ );
exit( 5 );
}
if ( ioctl( fd, PIOCSTATUS, &prs ) < 0 )
{
perror( ”ioctl“ );
exit( 7 );
}
if ( counter >9 )
{
fprintf( stdout, ”PIDtIMAGEttRSSttHEAPttSTACKn“ );
counter = 0;
}
fprintf( stdout, ”%ut%-9ut%-9ut%-15ut%-15un“, pid,
( unsigned int )prp.pr_bysize, ( unsigned int )prp.pr_byrssize,
( unsigned int )prs.pr_brksize, ( unsigned int )prs.pr_stksize );
counter++;
} /* end of getInfo */
--------------------------------------------------------------------------
译者: 作者这里利用了ioctl(),而不是直接读取/proc下文件,这样做的好处在于即使系统升级后/proc布局改变,内核中相应ioctl cmd支持也随之改变,对于应用层的开发者,接口一样,源代码可平稳移植。事实上从作者前面举例来看, memlook.c是在Solaris 2.6以前的版本上开发的,但我并未修改就可以直接用在Solaris 2.6上,虽然此时/proc布局已经发生重大变化。
仔细阅读prstatus和prpsinfo结构,寻找那些你敢兴趣的成员。在未能真正掌握这种技术之前不要针对/proc文件系统使用write()或者ioctl()。针对特定进程胡乱做write()调用,结果未知。
◆ 结论
当痛苦调试程序或者试图获取指定进程状态的时候,/proc文件系统将是你强有力的支持者。通过它可以创建更强大的工具,获取更多信息。
:www.51tech.net/news_html/1607.htm篇4:ARP头文件的解释Unix系统
来源:软件世界李贵林陈朝晖
与DOS/Windows不同,UNIX文件被删除后很难恢复,这是由UNIX独特的文件系统结构决定的。UNIX文件目录不像DOS/Windows那样,文件即使被删除之后仍保存有完整的文件名、文件长度、始簇号(即文件占有的第一个磁盘块号)等重要信息;相反,它的文件信息全部依靠一种被称为i节点的数据结构来描述,而i节点在相应文件被删除之后即被清空,因此,要想直接恢复被删除的文件内容几乎是不可能的,必须另辟蹊径。本文结合实际,讨论几种文件恢复策略及其关键步骤的具体实现。
一、UNIX文件系统结构
我们知道,UNIX是以文件卷作为其文件系统存储格式的,而不同的UNIX系统,文件卷格式是有差异的,甚至即使是同一UNIX操作系统的不同版本,其文件系统未必完全相同,例如:SCOUNIX4.1版与5.0版文件系统结构就有明显差异,但只要是UNIX系统,其文件卷的基本结构是一致的。分析如下:
不管是什么UNIX系统,不管什么版本,其文件卷至少包括引导块、超级块、i节点表、数据区等几个部分。除此之外,不同UNIX版本可能还有不同的差异。例如:SCOUNIX系统的位图索引块和位图块AIX的逻辑卷表等。这些系统的特殊性不影响下文的恢复策略,故这里不作讨论,仅介绍标准UNIX文件卷结构。
1.引导块
位于文件卷最开始的第一扇区,这512字节是文件系统的引导代码,为根文件系统所特有,其他文件系统这512字节为空。
2.超级块
位于文件系统第二扇区,紧跟引导块之后,用于描述本文件系统的结构。如i节点长度、文件系统大小等,其结构存放于/usr/include/sys/filsys.h中,其结构如下:
structfilsys
{
ushorts_isize;/*磁盘索引节点区所占用的数据块数*/
daddr_ts_fsize;/*整个文件系统的数据块数*/
shorts_nfree;/*在空闲块登录表中当前登记的空闲块数目*/
daddr_ts_free[NICFREE];/*空闲块登记表*/
shorts_ninode;/*空闲索引节点数*/
ino_ts_inode[NICINOD];/*空闲节点登记表*/
chars_flock;/*加锁标志位*/
chars_ilock;/*节点加锁标志位*/
chars_fmod;/*超级块修改标志*/
chars_ronly;/*文件系统只读标志*/
time_ts_time;/*超级块上次修改的时间*/
shorts_dinfo[4];/*设备信息*/
daddr_ts_tfree;/*空闲块总数*/
ino_ts_tinode;/*空闲节点总数*/
chars_fname[6];/*文件系统名称*/
chars_fpack[6];
longs_fill[13];/*填空位*/
longs_magic;/*指示文件系统的幻数*/
longs_type;/*新文件系统类型*/
};
3.i节点表
i节点表存放在超级块之后,其长度是由超级块中的s_isize字段决定的,其作用是用来描述文件的属性、长度、属主、属组、数据块表等,其数据结构在/usr/include/sys/ino.h中,如下:
structdinode
{
ushortdi_mode;
shortdi_nlink;
ushortdi_uid;
ushortdi_gid;
off_tdi_size;
chardi_addr[40];
time_tdi_atime;
time_tdi_mtime;
time_tdi_ctime;
};
4.目录结构
UNIX所有文件均存放于目录中,目录本身也是一个文件。目录存放文件的机制如下:首先,目录文件本身也象普通文件一样,占用一个索引节点,其次,由这个索引节点得到目录内容的存放位置,再次,从其内容中取出一个个的文件名和它对应的节点号,从而访问一个文件。目录结构如下:
索引节点号(2字节).(本目录)(14字节)
索引节点号(2字节)..(父目录)(14字节)
索引节点号(2字节)文件名(14字节)
索引节点号(2字节)文件名(14字节)
索引节点号(2字节)文件名(14字节)
由上可知文件名是依靠目录来描述的,文件的内容和其他信息则由索引节点来描述。
二、文件的删除过程
UNIX下删除一个文件的过程很简单,那就是释放索引节点表和文件占用的数据块,清空文件占用的索引节点,但不清除文件内容。但删除文件与删除目录的处理不尽相同,不同命令删除文件的过程也不相同。
1.删除一个文件
UNIX删除一个文件的具体步骤是:根据文件i节点的地址表逐一释放文件占用的磁盘数据块,然后清空相应的节点,最后释放i节点。
2.删除一个目录
删除一个目录的过程:首先逐一删除目录里的所有文件,然后删除目录。目录本身也是一个文件,故删除方法与删除文件一致。
3.几种不同的删除命令
.rm命令
一般删除命令,删除过程上述已说明,
.mv命令
格式:mv文件1文件2
处理过程是将文件2的数据块释放,然后将文件1的名称改为文件2,再释放文件2所占的i节点。
.>命令
格式:>文件名
若产生一个新文件,>命令仅仅申请一个i节点,而不写入任何文件内容;若清空一个已经存在的文件,则释放文件所占的数据块,并将文件长度清零。
三、被删文件的恢复策略
要恢复被删除的文件,只能根据删除后留下的东西去做文章。文件被删除后留下了什么呢?由上述分析可知:其一、留下了文件的内容;其二、留下了“现场”。文件的恢复策略只能从这两个方面来分析。以下谈几种恢复策略。
1.根据磁盘现场进行恢复
如果文件被删除,现场未被破坏(即文件被删除后硬盘未发生过写操作),而且假定只删除了一个文件,那么可根据系统的分配算法进行恢复。因为系统建立一个文件时,必定根据某一特定的分配算法决定文件占用的数据块位置。而当该文件被删除后,它所占用的数据块被释放,又回到系统的分配表中,这时如果重新建立一个文件,系统根据原来的分配算法分配出的数据块必定跟该文件原来占用的数据块一致,而且我们知道,UNIX文件最后一数据块尾部多出的字节是全部置0的,据此只要调用系统的数据分配算法,在系统中一块块的申请数据块,因为UNIX文件最后一个数据块尾部多出的字节全部为0,所以,只要发现一个分配出的数据块中尾部全为0,即可认为文件结束,由此可确定文件长度和内容,进而实现恢复。方法如下:
⑴申请一个索引节点,即向系统申请创建一个新文件名而不写入任何内容。如:#>/tmp/xx
⑵调用系统分配数据块算法getnextfreeblock得到一个数据块号,记入某一地址表变量中。
⑶读出这个数据块,判断其尾部是否全部连续为0,若不是,则回到(2),若是,则进行(4)。
⑷首先用系统函数fstat得到/tmp/xx的i节点号,然后将(2)步所得的地址表写入索引节点的地址表中(注意间址问题),并根据数据块个数和最后一块中有效数据长度计算出文件大小,写入i节点的di_size字段。
⑸回写系统的索引节点表即可。
需要说明的是,第一,系统分配数据块的算法因不同的UNIX版本而不同;第二,有的UNIX如SCOUNIX5.0版,其空闲数据块的分配和回收是使用一种动态链表的数据结构来实现的,它们的文件恢复更加容易,只要在空闲链表中的表尾去寻找即可,笔者另行描述。
2.根据内容恢复。
若现场已被破坏,即硬盘发生过写操作,那么只好根据内容来恢复。而且,由于UNIX是一个多进程、多用户系统,它每一次开关机或硬件、通讯故障等都会记录系统日志、.sh_history等,硬盘现场被破坏可能性极大。因此讨论按内容恢复的方法具有更大的实用价值。笔者经过实际探索得出下列四种恢复策略供参考。
⑴关键字搜索法
如果知道被删除的文件内容中若干字节的内容,而且该文件长度又不超过一个磁盘块,那么可以在整个文件系统中搜索这一字节串,得出一个文件所在的数据块,将它们的块号填入一个i节点,即可恢复一个文件,搜索文件系统的算法很简单,说明如下:
a.#df-k确定文件系统的设备文件名(如/dev/root)
b.用下述函数搜索,若成功,返回数据块号,反之返回-1。其中fsname是文件系统的设备名,如/dev/root,comp()参数是实现搜索条件的函数。
longsearchfs(char*fsname,intcomp())
{
FILE*fp;
charbuf[1024];
longi=0;
fp=fopen(fsname,“r”);
while(!feof(fp))
{
fread(buf,1024,1,fp);
if(comp())/*检查是否符合搜索条件*/
returni;/*若成功返回块号*/
i++;
}
fclose(fp);
return-1;/*未找到符合条件的块,返回-1*/
}
⑵精确长度搜索法
如果知道被删除文件的精确长度(字节数),那么可根据一个数据块的大小,计算出文件的最后一个数据块中数据的精确长度,该数据块中其他字节必然是全0。根据这一条件,通过搜索整个文件系统,找出其中符合条件的数据块,若出现多个块符合要求,则还需要根据其他条件区分。但不管怎样,根据精确长度分析也是恢复数据的一个策略。
⑶内容关联法
如果知道文件内容中存在某种可实现的关联,例如文件的校验和,或者文件内容的某种上下文关系,那么也可通过搜索整个文件系统,通过反复尝试寻找符合关联条件的磁盘数据块,进而恢复一个文件。
⑷环境比较法
如果知道删除文件所在的文件系统的安装过程,那么,另行找一台完全相的机器,按原来完全相同的步骤安装相同版本的UNIX和相应的其他软件,可以想象,新的机器环境会与原来的环境基本相同,比较两个机器上相同文件系统的内容,可以推断出被删除文件的大致位置,至少可以大大减少查找的范围,一旦查找的范围足够小时,可以用逐个观察和尝试的方法结合其他条件恢复数据,降低恢复的难度,增加恢复的可靠性。
UNIX系统下文件系统恢复的具体实现依赖于不同操作系统和不同版本的具体文件系统结构和磁盘块分配算法。本文试图总结出一种一般性的思路和策略,限于篇幅,不能详细讨论它们的具体实现过程。
answer 回复于:-02-12 15:19:02太专业了。
不过是好东西,加精华。
yeungxl 回复于:2003-02-12 15:39:38SCOOSR下有更容易的解决方案,具体参见:
www.chinaunix.net/bbsjh/4/15420.html
午夜聆听 回复于:2003-02-12 19:56:51华山大哥的帖子。好精典
quicksand 回复于:2003-02-13 16:28:05好,收藏!
sdclearcase/“ target=”_blank“ >ccf 回复于:2003-02-13 20:11:57实现起来困难。
篇5:elf文件格式 2Unix系统
elf文件格式-- 2=================== String Table 字符串表=========================
String table sections 保存着以NULL终止的一系列字符,一般我们称为字
符串。object文件使用这些字符串来描绘符号和section名。一个字符串的
参考是一个string table section的索引。第一个字节,即索引0,被定义保
存着一个NULL字符。同样的,一个string table的最后一个字节保存着一个
NULL字符,所有的字符串都是以NULL终止。索引0的字符串是没有名字或者说
是NULL,它的解释依靠上下文。一个空的string table section是允许的;
它的section header的成员sh_size将为0。对空的string table来说,非0的
索引是没有用的。
一个 settion 头的 sh_name 成员保存了一个对应于该 setion 头字符表部分
的索引(就象ELF头的 e_shstrndx 成员所特指的那样。下表列出了一个有 25 字节
的字符串表(这些字符串和不同的索引相关联):
Index +0 +1 +2 +3 +4 +5 +6 +7 +8 +9
===== == == == == == == == == == ==
0 n a m e . V a r
10 i a b l e a b l e
20 x x
+ Figure 1-15: String Table Indexes
Index String
===== ======
0 none
1 “name.”
7 “Variable”
11 “able”
16 “able”
24 null string
如上所示,一个字符串表可能涉及该 section 中的任意字节。一个字符串可能
引用不止一次;引用子串的情况是可能存在的;一个字符串也可能被引用若干次;而
不被引用的字符串也是允许存在的。
==================== Symbol Table 符号表=========================
一个object文件的符号表保存了一个程序在定位和重定位时需要的定义和引用的信息。
一个符号表索引是相应的下标。0表项特指了该表的第一个入口,就象未定义的符号
索引一样。初始入口的内容在该 section 的后续部分被指定。
Name Value
==== =====
STN_UNDEF0
一个符号表入口有如下的格式:
+ Figure 1-16: Symbol Table Entry
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
* st_name
该成员保存了进入该object文件的符号字符串表入口的索引(保留了符号名的表达字符)。
如果该值不为 0 ,则它代表了给出符号名的字符串表索引。否则,该符号无名。
注意:External C 符号和object文件的符号表有相同的名称。
* st_value
该成员给出了相应的符号值。它可能是绝对值或地址等等(依赖于上下文);
细节如下所述。
* st_size
许多符号和大小相关。比如,一个数据对象的大小是该对象所包含的字节数目。
如果该符号的大小未知或没有大小则这个成员为 0 。
* st_info
成员指出了符号的类型和相应的属性。相应的列表如下所示。下面的代码说明了
如何操作该值。
#define ELF32_ST_BIND(i) ((i)>>4)
#define ELF32_ST_TYPE(i) ((i)&0xf)
#define ELF32_ST_INFO(b, t) (((b)<<4)+((t)&0xf))
* st_other
该成员目前为 0 ,没有含义。
* st_shndx
每一个符号表的入口都定义为和某些 section 相关;该成员保存了相关的 section
头索引。就象 Figure 1-8 和相关的文字所描述的那样,某些 section 索引
指出了特殊的含义。
一个符号的属性决定了可链接性能和行为。
+ Figure 1-17: Symbol Binding, ELF32_ST_BIND
Name Value
==== =====
STB_LOCAL 0
STB_GLOBAL1
STB_WEAK 2
STB_LOPROC 13
STB_HIPROC 15
* STB_LOCAL
在包含了其定义的object文件之外的局部符号是不可见的。不同文件中的具有相同
名称的局部符号并不相互妨碍。
* STB_GLOBAL
全局符号是对所有的object目标文件可见的。一个文件中的全局符号的定义可以
满足另一个文件中对(该文件中)未定义的全局符号的引用。
* STB_WEAK
弱符号相似于全局符号,但是他们定义的优先级比较低一些。
* STB_LOPROC through STB_HIPROC
其所包含范围中的值由相应的处理器语义所保留。
全局符号和弱符号的区别主要在两个方面。
* 当链接器链接几个可重定位的目标文件时,它不允许 STB_GLOBAL 符号的同名
多重定义。另一方面,如果一个全局符号的定义存在则具有相同名称的弱符号名不会
引起错误。链接器将认可全局符号的定义而忽略弱符号的定义。与此相似,如果有一个
普通符号(比如,一个符号的 st_shndx 域包含 SHN_COMMON),则一个同名的弱符号
不会引起错误。链接器同样认可普通符号的定义而忽略弱符号。
* 当链接器搜索档案库的时候,它选出包含了未定义的全局符号的存档成员。该成员
的定义或者是全局的或者是一个弱符号。链接器不会为了解决一个未定义的弱符号
选出存档成员。未定义的弱符号具有 0 值。
在每一个符号表中,所有具有 STB_LOCAL 约束的符号优先于弱符号和全局符号。
就象上面 “sections” 中描述的那样,一个符号表部分的 sh_info 头中的成员
保留了第一个非局部符号的符号表索引。
符号的类型提供了一个为相关入口的普遍分类。
+ Figure 1-18: Symbol Types, ELF32_ST_TYPE
Name Value
==== =====
STT_NOTYPE 0
STT_OBJECT 1
STT_FUNC 2
STT_SECTION3
STT_FILE 4
STT_LOPROC13
STT_HIPROC15
* STT_NOTYPE
该符号的类型没有指定。
* STT_OBJECT
该符号和一个数据对象相关,比如一个变量、一个数组等。
* STT_FUNC
该符号和一个函数或其他可执行代码相关。
* STT_SECTION
该符号和一个 section 相关。这种类型的符号表入口主要是为了重定位,一般的
具有 STB_LOCAL 约束。
* STT_FILE
按惯例而言,该符号给出了和目标文件相关的源文件名称。一个具有 STB_LOCAL
约束的文件符号,其 section 索引为 SHN_ABS ,并且它优先于当前对应该文件的
其他 STB_LOCAL 符号。
* STT_LOPROC through STT_HIPROC
该范围中的值是为处理器语义保留的。
共享文件中的函数符号(具有 STT_FUNC 类型)有特殊的意义。当其他的目标文件
从一个共享文件中引用一个函数时,链接器自动的为引用符号创建一个链接表。除了
STT_FUNC 之外,共享的目标符号将不会自动的通过链接表引用。
如果一个符号涉及到一个 section 的特定定位,则其 section 索引成员 st_shndx
将保留一个到该 section 头的索引。当该 section 在重定位过程中不断
移动一样,符号的值也相应变化,而该符号的引用在程序中指向同样的定位。某些
特殊的 section 索引有其他的语义。
* SHN_ABS
该符号有一个不会随重定位变化的绝对值。
* SHN_COMMON
该符号标识了一个没有被分配的普通块。该符号的值给出了相应的系统参数,就象
一个 section 的 sh_addralign 成员。也就是说,链接器将分配一个地址给
该符号,地址的值是 st_value 的倍数。该符号的大小指出了需要的字节数。
* SHN_UNDEF
该 section 表索引表明该符号是未定义的。当链接器将该目标文件和另一个定义
该符号的文件相装配的时候,该文件内对该符号的引用将链接到当前实际的定义。
如上所述,符号表的 0 索引(STN_UNDEF)是保留的,它包含了如下内容:
+ Figure 1-19: Symbol Table Entry: Index 0
Name Value Note
==== ===== ====
st_name 0No name
st_value0Zero value
st_size 0No size
st_info 0No type, local binding
st_other0
st_shndx SHN_UNDEF No section
Symbol Values(符号值)
符号表入口对于不同的目标文件而言对 st_value 成员有一些不同的解释。
* 在可重定位文件中, st_value 保存了 section 索引为 SHN_COMMON 符号
的强制对齐值。
* 在可重定位文件中, st_value 保存了一个符号的 section 偏移。也就是说,
st_value 是从 st_shndx 定义的 section 开头的偏移量。
* 在可执行的和可共享的目标文件中, st_value 保存了一个虚拟地址。为了使
这些文件符号对于动态链接器更为有效,文件层面上的 section 偏移让位于内存
层面上的虚拟地址( section 编号无关的)。
尽管符号表值对于不同的目标文件有相似的含义,相应的程序还是可以有效地访问数据。
====================== Relocation (重定位)==========================
重定位是连接符号引用和符号定义的过程。比如,当一个程序调用一个函数的时候,
相关的调用必须在执行时把控制传送到正确的目标地址。换句话说,重定位文件应当
包含有如何修改他们的 section 内容的信息,从而允许可执行文件或共享目标文件
为一个进程的程序映像保存正确的信息。重定位入口就是这样的数据。
+ Figure 1-20: Relocation Entries
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
* r_offset
该成员给出了应用重定位行为的地址。对于一个重定位文件而言,该值是从该
section 开始处到受到重定位影响的存储单位的字节偏移量。对一个可执行文件
或一个共享目标而言,该值是受到重定位影响的存储单位的虚拟地址。
* r_info
该成员给出了具有受重定位影响因素的符号表索引和重定位应用的类型。比如,
一个调用指令的重定位入口应当包含被调用函数的符号索引。如果该索引是
STN_UNDEF (未定义的符号索引),重定位将使用 0 作为该符号的值。重定位
类型是和处理器相关的。当正文(text)引用到一个重定位入口的重定位类型或符
号表索引,它表明相应的应用 ELF32_R_TYPE或 ELF32_R_SYM 于入口的 r_info
成员。
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define ELF32_R_INFO(s, t) ((s)<<8+(unsigned char)(t))
* r_addend
该成员指定一个常量加数(用于计算将要存储于重定位域中的值)。
如上所述,只有 Elf32_Rela 入口包含一个明确的加数。Elf32_Rel 类型
的入口在可以修改的地址中存储一个隐含的加数。依赖于处理器结构,一种形式
或其他形式也许是必须的或更为方便的。因此,特定机器的应用应当使用一种排他
性的形式或依赖于上下文的另一种形式。
一个重定位 section 关联了两个其他的 section :一个符号表和一个可修改
的 section 。该 section 头的成员 sh_info 和 sh_link (在上文中的
“ section ”部分中有描述)指示了这种关系。重定位入口中的成员 r_offset
对于不同的目标文件有少许差异。
* 在可重定位文件中,r_offset 表示了一个 section 偏移。也就是说,重定位
section自己描述了如何修改其他在文件中的其他section; 重定位偏移量指
明了一个在第二个section中的存储器单元。
* 在可执行和共享的目标文件中,r_offset 表示一个虚拟地址。为了使得这些
文件的重定位入口更为有用(对于动态链接器而言),该 section 偏移(文件
中)应当让位于一个虚拟地址(内存中的)。
尽管为了允许相关的程序更为有效的访问而让 r_offset 的解释对于不同的目标
文件有所不同,重定位类型的含义是相同的。
Relocation Types(重定位类型)
重定位入口描述了怎样变更下面的指令和数据域(位数在表的两边角下)。
+ Figure 1-21: Relocatable Fields
+---------------------------+
| word32 |
31---------------------------0
* word32
指定一个以任意字节对齐方式占用 4 字节的 32 位域。这些值使用与 32 位 Intel
体系相同的字节顺序。
3------2------1------0------+
0x01020304 | 01 | 02 | 03 | 04 |
31------+------+------+------0
下面的计算假设正在将一个可重定位文件转换为一个可执行或共享的目标文件。
从概念上来说,链接器合并一个或多个可重定位文件来组成输出。它首先决定
怎样合并、定位输入文件,然后更新符号值,最后进行重定位。对于可执行文件
和共享的目标文件而言,重定位过程是相似的并有相同的结果。下面的描述使用
如下的约定符号。
* A
表示用于计算可重定位的域值的加数。
* B
表示了在执行过程中一个共享目标被加载到内存时的基地址。一般情况下,一个
共享object文件使用的基虚地址为0,但是一个可执行地址就跟共享object文件
不同了。
* G
表示了在执行过程中重定位入口符号驻留在全局偏移表中的偏移。请参阅
第二部分中的“ Global Offset Table (全局偏移表)”获得更多
的信息。
* GOT
表示了全局偏移表的地址。请参阅第二部分中的“ Global Offset Table
(全局偏移表)”获得更多的信息。
* L
表示一个符号的过程链接表入口的位置( section 偏移或地址)。一个过程
链接表入口重定位一个函数调用到正确的目的单元。链接器创建初始的链接表,
而动态链接器在执行中修改入口。
请参阅第二部分中的“ Procedure Linkage Table (过程链接表)”获得更多
的信息
* P
表示(section 偏移或地址)被重定位的存储单元位置(使用 r_offset 计算的)。
* S
表示索引驻留在重定位入口处的符号值。
一个重定位入口的 r_offset 值指定了受影响的存储单元的首字节的偏移
或虚拟地址。重定位类型指定了哪一位(bit)将要改变,以及怎样计算它们的值。
在 SYSTEM V 体系中仅仅使用 Elf32_Rel 重定位入口,将要被重定位的域中
保留了加数。在所有的情况下,加数和计算结果使用相同字节顺序。
+ Figure 1-22(表 1-22): Relocation Types(重定位类型)
NameValue Field Calculation
========= ===== ===========
R_386_NONE 0 none none
R_386_32 1 word32 S + A
R_386_PC32 2 word32 S + A - P
R_386_GOT32 3 word32 G + A - P
R_386_PLT32 4 word32 L + A - P
R_386_COPY 5 none none
R_386_GLOB_DAT 6 word32 S
R_386_JMP_SLOT 7 word32 S
R_386_RELATIVE 8 word32 B + A
R_386_GOTOFF 9 word32 S + A - GOT
R_386_GOTPC 10 word32 GOT + A - P
有的重定位类型有不同于简单计算的语义。
* R_386_GOT32
这种重定位类型计算全局偏移表基地址到符号的全局偏移表
入口之间的间隔。这样另外通知了 link editor 建立一个全局偏移表 。
* R_386_PLT32
这种重定位类型计算符号的过程链接表入口地址,并另外通知链接器建立一个
过程链接表。
* R_386_COPY
链接器创建该重定位类型用于动态链接,
它的偏移成员涉及一个可写段中的一个
位置。符号表索引指定一个可能存在于当前 object file 或在一个shared object
中的符号。在执行过程中,动态链接器把和 shared object 符号相关的数据
拷贝到该偏移所指定的位置。
* R_386_GLOB_DAT
这种重定位类型用于设置一个全局偏移表入口为指定符号的地址。该特定的重定位
类型允许你决定符号和全局偏移表入口之间的一致性。
* R_386_JMP_SLOT
链接器创建该重定位类型用于动态链接。其偏移成员给出了一个过程链接表入口的
位置。动态链接器修改该过程链接表入口以便向特定的符号地址传递控制。
[参阅第二部分中的 “Procedure Linkage Table(过程链接表)”]
* R_386_RELATIVE
链接器创建该重定位类型用于动态链接。其偏移成员给出了包含表达相关地址值
的一个 shared object 中的位置。动态链接器计算相应的虚拟地址(把该
shared object 装载地址和相对地址相加)。该类型的重定位入口必须为
符号表索引指定为 0 。
* R_386_GOTOFF
这种重定位类型计算符号值和全局偏移表地址之间的不同。另外还通知链接器
建立全局偏移表(GOT)。
* R_386_GOTPC
这种重定位类型类似于 R_386_PC32 ,不同的是它在计算中使用全局偏移表。
这种重定位中引用的符号通常是 _GLOBAL_OFFSET_TABLE_ ,该符号通知了
链接器建立全局偏移表(GOT)。
________________________________________________________________
2. PROGRAM LOADING AND DYNAMIC LINKING
程序装入和动态链接
________________________________________________________________
======================== Introduction(介绍) =========================
第二部分描述了 object file 信息和创建运行程序的系统行为。其中部分信息
适合所有的系统,其他信息是和特定处理器相关的。
可执行和共享的 object file 静态的描绘了程序。为了执行这样的程序,系统
用这些文件创建动态的程序表现,或进程映像。一个进程映像有用于保存其代码、
数据、堆栈等等的段。这个部分的主要章节讨论如下的内容。
* 程序头(Program header)。该章节补充第一部分,描述和程序运行相关的
object file 结构。即文件中主要的数据结构、程序头表、定位段映像,也
包含了为该程序创建内存映像所需要的信息。
* 载入程序(Program loading)。在给定一个 object file 时,系统为了
让它运行必须将它载入内存。
* 动态链接(Dynamic linking)。在载入了程序之后,系统必须通过解决组
成该进程的 object file之间的符号引用问题来完成进程映像的过程。
注意:指定了处理器范围的 ELF 常量是有命名约定的。比如,DT_ , PT_ ,
用于特定处理器扩展名,组合了处理器的名称(如 DT_M32_SPECIAL )。
没有使用这种约定但是预先存在的处理器扩展名是允许的。
Pre-existing Extensions
(预先存在的扩展名)
=======================
DT_JMP_REL
====================== Program Header(程序头) ======================
一个可执行的或共享的 object file 的程序头表是一个结构数组,每一个
结构描述一个段或其他系统准备执行该程序所需要的信息。一个 object file
段包含一个或多个部分(就象下面的“段目录”所描述的那样)。程序头仅仅对于
可执行或共享的 object file 有意义。一个文件使用 ELF 头的 e_phentsize
和 e_phnum 成员来指定其拥有的程序头大小。[参阅 第一部分中的 “ELF 头”]
+ Figure 2-1: Program Header
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
* p_type
该成员指出了这个数组的元素描述了什么类型的段,或怎样解释该数组元素的信息。
类型值和含义如下所述。
* p_offset
该成员给出了该段的驻留位置相对于文件开始处的偏移。
* p_vaddr
该成员给出了该段在内存中的首字节地址。
* p_paddr
在物理地址定位有关联的系统中,该成员是为该段的物理地址而保留的。由于
System V 忽略了应用程序的物理地址定位,该成员对于可执行文件和共享的
object 而言是未指定内容的。
* p_filesz
该成员给出了文件映像中该段的字节数;它可能是 0 。
* p_memsz
该成员给出了内存映像中该段的字节数;它可能是 0 。
* p_flags
该成员给出了和该段相关的标志。定义的标志值如下所述。
* p_align
就象在后面“载入程序”部分中所说的那样,可载入的进程段必须有合适的
p_vaddr 、p_offset 值,取页面大小的模。该成员给出了该段在内存和
文件中排列值。 0 和 1 表示不需要排列。否则, p_align 必须为正的 2 的幂,
并且 p_vaddr 应当等于 p_offset 模 p_align 。
某些入口描述了进程段;其他的则提供补充信息并且无益于进程映像。已经
定义的入口可以以任何顺序出现,除非是下面明确声明的。后面是段类型值;
其他的值保留以便将来用于其他用途。
+ Figure 2-2: Segment Types, p_type
Name Value
==== =====
PT_NULL 0
PT_LOAD 1
PT_DYNAMIC 2
PT_INTERP3
PT_NOTE 4
PT_SHLIB 5
PT_PHDR 6
PT_LOPROC 0x70000000
PT_HIPROC 0x7fffffff
* PT_NULL
该数组元素未使用;其他的成员值是未定义的。这种类型让程序头表忽略入口。
* PT_LOAD
该数组元素指定一个可载入的段,由 p_filesz 和 p_memsz 描述。文件中
字节被映射到内存段中。如果该段的内存大小( p_memsz )比文件大小( p_filesz )
要大,则多出的字节将象段初始化区域那样保持为 0 。文件的大小不会比内存大小值大。
在程序头表中,可载入段入口是以 p_vaddr 的升序排列的。
* PT_DYNAMIC
该数组元素指定动态链接信息。参阅 后面的“动态部分”以获得更多信息。
* PT_INTERP
该数组元素指定一个 null-terminated 路径名的位置和大小(作为解释程序)。
这种段类型仅仅对可执行文件有意义(尽管它可能发生在一个共享 object 上);
它在一个文件中只能出现一次。如果它出现,它必须先于任何一个可载入段入口。
参阅 后面的“程序解释器”(Program Interpreter)以获得更多的信息。
* PT_NOTE
该数组元素指定辅助信息的位置和大小。参阅 后面的“注意部分”以获得细节。
* PT_SHLIB
该段类型保留且具有未指定的语义。具有一个这种类型数组元素的程序并不
遵守 ABI 。
* PT_PHDR
该数组元素(如果出现),指定了程序头表本身的位置和大小(包括在文件中
和在该程序的内存映像中)。更进一步来说,它仅仅在该程序头表是程序内存映像
的一部分时才有效。如果它出现,它必须先于任何可载入段入口。参阅 后面的
“程序解释器”(Program Interpreter)以获得更多的信息。
* PT_LOPROC through PT_HIPROC
该范围中的值保留用于特定处理器的语义。
注意:除非在别处的特殊要求,所有的程序头的段类型是可选的。也就是说,
一个文件的程序头表也许仅仅包含和其内容相关的元素。
Base Address(基地址)
可执行和共享的 object file 有一个基地址,该基地址是与程序的 object file
在内存中映像相关的最低虚拟地址。基地址的用途之一是在动态链接过程中重定位
该程序的内存映像。
一个可执行的 object file 或 一个共享的 object file 的基地址是在
执行的时候从三个值计算而来的:内存载入地址、页面大小的最大值 和 程序可
载入段的最低虚拟地址。就象在“程序载入”中所描述的那样,程序头中的虚拟地址
也许和程序的内存映像中实际的虚拟地址并不相同。为了计算基地址,必须确定与
PT_LOAD 段 p_vaddr 的最小值相关的内存地址。获得基地址的方法是将内存
地址截去最大页面大小的最接近的整数倍。由于依赖载入内存中的文件类型,
该内存地址和 p_vaddr 值可能匹配也可能不匹配。
就象在第一部分中 “Section” 中描述的那样, .bss section 具有 SHT_NOBITS
的类型。尽管在文件中不占用空间,它在段的内存映像中起作用。通常,没有初始化
的数据驻留在段尾,因此使得在相关的程序头元素中的 p_memsz 比 p_filesz 大。
Note Section(注解部分)
有的时候供应商或系统设计者需要用特定的信息标记一个
object file 以便其他程序检查其兼容的一致性,等等此类。 SHT_NOTE
类型的 section 和 PT_NOTE 类型的程序头元素能够被用于此目的。 section
和程序头中的注解信息包含了任意数目的入口,每一个入口的格式都是对应于特定
处理器格式的 4-字节数组。下面的标签有助于解释注释信息的组织形式,但是这些
标签不是规格说明的一部分。
+ Figure 2-3: Note Information
namesz
descsz
type
name ...
desc ...
* namesz and name
名字中 namesz 的第一个字节包含了一个 null-terminated 字符
表达了该入口的拥有者或始发者。没有正式的机制来避免名字冲突。从
惯例来说,供应商使用他们自己的名称,比如 “XYZ Computer Company” ,
作为标志。如果没有提供名字, namesz 值为 0 。 如果有必要,确定
描述信息4-字节对齐。 这样的填充信息并不包含在namesz 中。
* descsz and desc
desc 中 descsz 的首字节包含了注解描述符。ABI 不会在一个描述符内容中
放入任何系统参数。如果没有描述符, descsz 将为 0 。 如果有必要,确定
描述信息4-字节对齐。 这样的填充信息并不包含在descsz中。
* type
该 word 给出了描述符的解释。每一个创造着(originator) 控制着自己的类型;
对于单单一个类型值的多种解释是可能存在的。因此,一个程序必须辨认出该名字
和其类型以便理解一个描述符。这个时候的类型必须是非负的。ABI 没有定义
描述符的含义。
为了举例说明,下面的解释段包含两个入口。
+ Figure 2-4: Example Note Segment
+0 +1 +2 +3
-------------------
namesz 7
descsz 0 No descriptor
type 1
name X Y Z spc
C o pad
namesz 7
descsz 8
type 3
name X Y Z spc
C o pad
desc word0
word1
注意:系统保留的注解信息没有名字 (namesz==0) ,有一个零长度的名字
(name[0]==‘‘) 现在还没有类型为其定义。所有其他的名字必须至少有
一个非空的字符。
注意:注解信息是可选的。注解信息的出现并不影响一个程序的 ABI 一致性,
前提是该信息不影响程序的执行行为。否则,该程序将不遵循 ABI 并将出现
未定义的行为。
===================== Program Loading(程序载入) =====================
当创建或增加一个进程映像的时候,系统在理论上将拷贝一个文件的段到一个虚拟
的内存段。系统什么时候实际地读文件依赖于程序的执行行为,系统载入等等。一个
进程仅仅在执行时需要引用逻辑页面的时候才需要一个物理页面,实际上进程通常会
留下许多未引用的页面。因此推迟物理上的读取常常可以避免这些情况,改良系统的
特性。为了在实践中达到这种效果,可执行的和共享的 object file 必须具有
合适于页面大小取模值的文件偏移和虚拟地址这样条件的段映像。
虚拟地址和文件偏移在 SYSTEM V 结构的段中是模 4KB(0x1000) 或大的 2 的幂。
由于 4KB 是最大的页面大小,因此无论物理页面大小是多少,文件必须去适合页面。
+ Figure 2-5: Executable File
File Offset FileVirtual Address
=========== ===================
0 ELF header
Program header table
Other information
0x100 Text segment 0x8048100
...
0x2be00 bytes 0x8073eff
0x2bf00 Data segment 0x8074f00
...
0x4e00 bytes 0x8079cff
0x30d00 Other information
...
+ Figure 2-6: Program Header Segments(程序头段)
Member Text Data
====== ==== ====
p_type PT_LOADPT_LOAD
p_offset 0x100 0x2bf00
p_vaddr 0x8048100 0x8074f00
p_paddr unspecified unspecified
p_filesz 0x2be00 0x4e00
p_memsz 0x2be00 0x5e24
p_flags PF_R+PF_X PF_R+PF_W+PF_X
p_align 0x1000 0x1000
尽管示例中的文件偏移和虚拟地址在文本和数据两方面都适合模 4KB ,但是还有
4 个文件页面混合了代码和数据(依赖于页面大小和文件系统块的大小)。
* 第一个文本页面包含了 ELF 头、程序头以及其他信息。
* 最后的文本页包含了一个数据开始的拷贝。
* 第一个数据页面有一个文本结束的拷贝。
* 最后的数据页面也许会包含与正在运行的进程无关的文件信息。
理论上,系统强制内存中段的区别;段地址被调整为适应每一个逻辑页面在地址空间
中有一个简单的准许集合。在上面的示例中,包含文本结束和数据开始的文件区域将
被映射两次:在一个虚拟地址上为文本而另一个虚拟地址上为数据。
数据段的结束处需要对未初始化的数据进行特殊处理(系统定义的以 0 值开始)。
因此如果一个文件包含信息的最后一个数据页面不在逻辑内存页面中,则无关的
数据应当被置为 0 (这里不是指未知的可执行文件的内容)。在其他三个页面中
“Impurities” 理论上并不是进程映像的一部分;系统是否擦掉它们是未指定的。
下面程序的内存映像假设了 4KB 的页面。
+ Figure 2-7: Process Image Segments(进程映像段)
Virtual Address ContentsSegment
=============== ===============
0x8048000 Header paddingText
0x100 bytes
0x8048100 Text segment
...
0x2be00 bytes
0x8073f00 Data padding
0x100 bytes
0x8074000 Text padding Data
0xf00 bytes
0x8074f00 Data segment
...
0x4e00 bytes
0x8079d00 Uninitialized data
0x1024 zero bytes
0x807ad24 Page padding
0x2dc zero bytes
可执行文件和共享文件在段载入方面有所不同。典型地,可执行文件段包含了
绝对代码。为了让进程正确执行,这些段必须驻留在建立可执行文件的虚拟地址
处。因此系统使用不变的 p_vaddr 作为虚拟地址。
另一方面,共享文件段包含与位置无关的代码。这让不同进程的相应段虚拟地址
各不相同,且不影响执行。虽然系统为各个进程选择虚拟地址,它还要维护各个
段的相对位置。因为位置无关的代码在段间使用相对定址,故而内存中的虚拟地址
的不同必须符合文件中虚拟地址的不同。下表给出了几个进程可能的共享对象虚拟
地址的分配,演示了不变的相对定位。该表同时演示了基地址的计算。
+ Figure 2-8: Example Shared Object Segment Addresses
Sourc Text Data Base Address
===== ==== ==== ============
File 0x200 0x2a400 0x0
Process 1 0x80000200 0x8002a400 0x80000000
Process 2 0x80081200 0x800ab400 0x80081000
Process 3 0x900c0200 0x900ea400 0x900c0000
Process 4 0x900c6200 0x900f0400 0x900c6000
相关文章:
写景黄山飞来石 写景黄山字5篇(优质)01-20
TCP协议疑难杂症全景解析01-20
最新中学生感恩英文演讲稿三分钟 初中英语感恩演讲稿(4篇)01-20
网络商家服务协议01-20
小学生英语演讲稿分钟 小学生英语演讲稿和8篇(通用)01-20
《综合应用能力》真题与解析01-20
浅析工业原料气净化与绿色化工相关问题01-20
卫星网络协议01-20
学校网络接入协议01-20
网络通信协议01-20