使用mmap实现类似cat命令的文件显示功能
文章来源:http://gliethttp.cublog.cn
1.使用vim创建map_cat.c文件 [root@localhost gliethttp]# vim map_cat.c 2.在map_cat.c中录入如下程序 //map_cat.c #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <stdio.h> #include <unistd.h>
int main(int argc,const char *argv[]) {int fd; struct stat sb; void *region; if((fd = open(argv[1],O_RDONLY)) < 0) { perror("open"); return 1; } if(fstat(fd,&sb)) { perror("fstat"); return 1; }
region = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0); /* MAP_FAILED的值就是-1 if(region == ((caddr_t)-1))和if(region == MAP_FAILED)是等效的,不过以代码直观起见,还是使用xiyou说的 if(region == MAP_FAILED)比较好一些,我已经改了, */ //if(region == ((caddr_t)-1)) if(region == MAP_FAILED) { perror("mmap"); return 1; }
close(fd);
if(write(1,region,sb.st_size) != sb.st_size) { perror("write"); return 1; } /* 当程序map_cat自然消亡时,或者显式的调用eixt(0);或者return 0;自动退出,登记链接到current->mm中的各个vma虚拟内存区块的由内核函数pte_alloc_one()申请到的pte页表slab管理结构体所占用的slab对象空间,都会被自动释放掉,归还给页表slab管理器,根据自然老化原理,甚至最后归还到buddy伙伴算法管理的free_area[]中(gliethttp_20071128) 根据本map_cat程序的特点,在这里就直接return 0;退出了,所以此处不加munmap也一样会在程序exit时,mmap申请的映射被系统自动回收,不过为了直观起见,加上之后,更能清楚,我们的用意 */ munmap(region,sb.st_size); return 0; } 3.在vim中使用!符号执行shell命令,编译map_cat.c,具体命令如下: :w 先保存编辑的程序 :!gcc map_cat.c -o map_cat 4.在vim中执行map_cat程序 :pwd 查看vim所在的当前目录,如果和map_cat不再同一个目录,使用 :cd /root/gliethttp 将vim的默认目录改为/root/gliethttp :!./map_cat /etc/profile 执行刚才生成的map_cat程序,将/etc/profile文件打印到屏幕上(gliethttp_20071125)
//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
/*PS:对mmap的粗略追踪*/
[root@localhost gliethttp]# strace ./map_cat ./mm.c execve("./map_cat", ["./map_cat", "./mm.c"], [/* 25 vars */]) = 0 uname({sys="Linux", node="localhost.localdomain", ...}) = 0 brk(0) = 0x804973c old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40016000 open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=60326, ...}) = 0 old_mmap(NULL, 60326, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40017000 close(3) = 0 open("/lib/tls/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`V\1B4\0"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1531064, ...}) = 0 old_mmap(0x42000000, 1257224, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x42000000 old_mmap(0x4212e000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12e000) = 0x4212e000 old_mmap(0x42131000, 7944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x42131000 close(3) = 0 set_thread_area({entry_number:-1 -> 6, base_addr:0x400169e0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 munmap(0x40017000, 60326) = 0 open("./mm.c", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=103, ...}) = 0 mmap2(NULL, 103, PROT_READ, MAP_SHARED, 3, 0) = 0x40017000 close(3) = 0 write(1, "#include \nint main(int "..., 103#include <stdio.h> int main(int argc,const char *argv[]) { printf("hello world!\r\n"); return 0; } ) = 103 exit_group(0) = ? [root@localhost gliethttp]#
在退出之前加入for(;;);让map_cat不退出,观察内存情况: [root@localhost gliethttp]# pidof map_cat 12007 显示map_cat的pid值 [root@localhost gliethttp]# vim /proc/12007/maps 08048000-08049000 r-xp 00000000 08:02 893166 /root/gliethttp/map_cat 08049000-0804a000 rw-p 00000000 08:02 893166 /root/gliethttp/map_cat 40000000-40015000 r-xp 00000000 08:02 453447 /lib/ld-2.3.2.so 40015000-40016000 rw-p 00014000 08:02 453447 /lib/ld-2.3.2.so 40016000-40017000 rw-p 00000000 00:00 0 40017000-40018000 r--s 00000000 08:02 893258 /root/gliethttp/mm.c 这是./map_cat ./mm.c命令所调用的mm.c文件 42000000-4212e000 r-xp 00000000 08:02 340050 /lib/tls/libc-2.3.2.so 4212e000-42131000 rw-p 0012e000 08:02 340050 /lib/tls/libc-2.3.2.so 42131000-42133000 rw-p 00000000 00:00 0 bfffd000-c0000000 rwxp ffffe000 00:00 0
[root@localhost gliethttp]# vim /proc/12020/maps 加入munmap(region,sb.st_size);的效果 08048000-08049000 r-xp 00000000 08:02 893166 /root/gliethttp/map_cat 08049000-0804a000 rw-p 00000000 08:02 893166 /root/gliethttp/map_cat 40000000-40015000 r-xp 00000000 08:02 453447 /lib/ld-2.3.2.so 40015000-40016000 rw-p 00014000 08:02 453447 /lib/ld-2.3.2.so 40016000-40017000 rw-p 00000000 00:00 0 42000000-4212e000 r-xp 00000000 08:02 340050 /lib/tls/libc-2.3.2.so 4212e000-42131000 rw-p 0012e000 08:02 340050 /lib/tls/libc-2.3.2.so 42131000-42133000 rw-p 00000000 00:00 0 bfffd000-c0000000 rwxp ffffe000 00:00 0
不论哪一种情况,当程序map_cat自然消亡时,或者显式的调用eixt(0);或者return 0;自动退出,登记链接到current->mm中的各个vma虚拟内存区块的由内核函数pte_alloc_one()申请到的pte页表slab管理结构体所占用的slab对象空间,都会被自动释放掉,归还给页表slab管理器,根据自然老化原理,甚至最后归还到buddy伙伴算法管理的free_area[]中(gliethttp_20071128)
|