Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->系统管理 ->正文

Linux 动态函式库解析(四)

来源:Linux-cn.com 作者:Webmaster 时间:2007-05-05 点击: [收藏] [投稿]

  呼叫 open("/lib/libc.so.6", O_RDONLY),开启 libc.so.6。

  呼叫 read(3, "177ELF111331250202"..., 4096) 读取libc.so.6的档头。

  呼叫 mmap(0, 993500, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0),把 libc.so.6 映射到记忆体中,由档头开始映射 993500 bytes,若是使用 RedHat 6.1(或其它版本的 RedHat)的读者或许会好奇 libc.so.6 所 link 到的档案 libc-2.1.2.so 大小不是 4118715 bytes 吗? 其实原本 RedHat 所附的 libc.so.6 动态函式库是没有经过 strip 过的,如果经过 strip 後,大小会变为 1052428 bytes,而 libc.so.6 由档头开始在 993500 bytes 之後都是一些版本的资讯,笔者猜想应该是这样的原因,所以在映射档时,并没有把整个 libc.so.6 档案映射到记忆体中,只映射前面有意义的部分。与映射 ld.so.cache 不同的是,除了 PROT_READ 属性之外,libc.so.6 的属性还多了PROT_EXEC,这代表了所映射的这块记忆体是可读可执行的。在笔者的电脑中,libc.so.6 所映射到的记忆体起始位置为 0x40016000。

  呼叫 mprotect(0x40101000, 30940, PROT_NONE),用来设定记忆体的使用权限,而 PROT_NONE 属性是代表这块记忆体区间(0x40101000—0x401088DC)是不能读取、写入与执行的。

  呼叫 mmap(0x40101000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xea000),映射 libc.so.6 由起始位置 0xea000 映射 16384bytes 到记忆体位置 0x40101000。

  呼叫 mmap(0x40105000, 14556, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0),MAP_ANONYMOUS 表示没有档案被映射,且产生一个初始值全为 0 的记忆体区块。

  呼叫 munmap(0x40013000, 9937),把原本映射到 ld.so.cache 的记忆体解除映射(此时已把执行档所需的动态函式库都映射到记忆体中了)。

  呼叫 personality(0),可以设定目前 Process 的执行区间(execution domain),换个说法就是 Linux 支援了多个执行区间,而我们所设定的执行区间会告诉 Linux 如何去映射我们的讯息号码(signal numbers)到各个不同的讯息动作(signal actions)中。这执行区间的功能,允许 Linux 对其它 Unix-Like 的操作系统,提供有限度的二进位档支援。如这个例子中,personality(0) 的参数为 0,就是指定为 PER_LINUX 的执行区间(execution domain)。


#define PER_MASK (0x00ff) 
#define PER_LINUX (0x0000) 
#define PER_LINUX_32BIT (0x0000 | ADDR_LIMIT_32BIT) 
#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS) 
#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS) 
#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS) 
#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS) 
#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS) 
#define PER_BSD (0x0006) 
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS) 
#define PER_LINUX32 (0x0008) 
#define PER_IRIX32 (0x0009 | STICKY_TIMEOUTS) /* IRIX5 32-bit */ 
#define PER_IRIXN32 (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */ 
#define PER_IRIX64 (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit */ 

  呼叫 getpid(),取得目前 Process 的 Process ID。

  呼叫 mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0),传回值为 0x400130,MAP_ANONYMOUS 表示没有档案被映射,且产生一个初始值全为 0 的记忆体区块。

  呼叫 write(1, " test ", 6),显示字串在画面上。

  呼叫 munmap(0x40013000, 4096),解除记忆体位置0x40013000的记忆体映射。

  呼叫 _exit(6),结束程序执行。

  在这段所举的例子,只用到了一个函式库 libc.so.6,我们可以举像是 RedHat 中 Telnet 指令为例,首先检视他的 ELF Header


==>libncurses.so.4 
tgetent 
==>libc.so.6 
strcpy 
ioctl 
printf 
cfgetospeed 
recv 
connect 
............┅ 
sigsetmask 
__register_frame_info 
close 
free 

  它主要呼叫了函式库 libncurses.so.4 的函式 tgetent,以及函式库 libc.so.6 中为数不少的函式,当然我们也可以去检视它执行的流程,与之前只呼叫了 libc.so.6 的printf 函式来比较,我们可以发现它主要的不同就是去载入了 libncurses.so.4


open("/usr/lib/libncurses.so.4", O_RDONLY) ; 
fstat(3, {st_mode=S_IFREG|0755, st_size=274985, ...}) ; 
read(3, "177ELF111331340335"..., 4096) ; 
mmap(0, 254540, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0); 
mprotect(0x40048000, 49740, PROT_NONE); 
mmap(0x40048000, 36864, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED, 3, 0x31000); 
mmap(0x40051000, 12876, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) ; 
close(3); 



 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:多层次负载平衡之四   下一篇:Linux与FreeBSD共存

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号