linux 系统编程学习笔记三

来源:互联网 发布:如何登陆淘宝账号 编辑:程序博客网 时间:2024/05/19 13:45
mmap
可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址
对文件的读写可以直接用指针来作,不需要read/write函数


#include <sys/mman.h>
/*如果addr参数为NULL,内核会在进程地址空间中选择合适的地址建立映射
  如果不为空,则指定从什么地址开始映射
  len 指定文件的映射长度
  off 是指从文件的什么位置开始映射,是页大小的整倍数(32位体系结构通常是4k)
  filedes 是文件的描述符
  prot 有四种取值:
       PROT_EXEC 表示映射的这一段可执行,如映射共享库
       PROT_READ 表示映射的这一段可读
       PROT_WRITE 表示映射的这一段可写出
       PROT_NONE 表示映射的这一段不可访问
 flag 的常用的两种取值
      MAP_SHARED 多个进程对同一个文件的映射是共享的
      MAP_PRIVATE 多个进程对同一个文件的映射是不共享的 
 */
/*
  如果映射成功则返回首地址   
  出错返回MAP_FAILED
  当进程终止时,映射内存会自动解除,也可以调用munmap解除映射
 */
void *mmap(void *addr,size_t len, int prot,int flag,int filedes,off_t off);
int munmap(void *addr,size_t len);




实例代码:
yuezhenhua@ubuntu:/opt/sdk/tc/mmap$ vi hello
内容为(hello)
yuezhenhua@ubuntu:/opt/sdk/tc/mmap$ od -tx1 -tc hello
0000000  68  65  6c  6c  6f  0a
          h   e   l   l   o  \n
0000006


 #include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>


int main(void){
int *p;
int fd=fopen("hello",O_RDWR);
if(fd<0){
perror("open hello");
exit(1);
}
p=mmap(NULL,6,PROT_WRITE,MAP_SHARED,fd,0);
if(p==MAP_FAILED){
perror("mmap");
exit(1);
}
close();
p[0]=0x30313233;
munmap(p,6);
return 0;
}


运行以上程序后再查看文件的内容
od -tx1 -tc hello
0000000  68  65  6c  6c  6f  0a
          3   2   1   0   o  \n
0000006




示例代码如下:
#include <stdio.h>


int main(void){
printf("hello world\n");
return 0;
}


编译
yuezhenhua@ubuntu:/opt/sdk/tc/mmap$ gcc helloworld.c
跟踪程序执行过程中用到的所有系统调用及返回值:
yuezhenhua@ubuntu:/opt/sdk/tc/mmap$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 45 vars */]) = 0
brk(0)                                  = 0x82b4000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 


0xb77fb000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=63389, ...}) = 0
mmap2(NULL, 63389, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77eb000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
/*这个程序要映射共享库/lib/i386-linux-gnu/libc.so.6*/
open("/lib/i386-linux-gnu/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\0p\222\1\0004\0\0\0"..., 


512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1552584, ...}) = 0
mmap2(NULL, 1563160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 


0x4f7000
mmap2(0x66f000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 


3, 0x178) = 0x66f000
mmap2(0x672000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, 


-1, 0) = 0x672000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 


0xb77ea000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77ea8d0, limit:1048575, 


seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, 


useable:1}) = 0
mprotect(0x66f000, 8192, PROT_READ)     = 0
mprotect(0x8049000, 4096, PROT_READ)    = 0
mprotect(0x8fb000, 4096, PROT_READ)     = 0
munmap(0xb77eb000, 63389)               = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 


0xb77fa000
/*printf函数底层调用的是write*/
write(1, "hello world\n", 12hello world
)           = 12
exit_group(0)                           = ?