glibc提供的mmap简介
用户空间用的mmap函数,是glibc 提供的
声明通过 man mmap 查找
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
我们可以直接用mmap函数,也可以用封装mmap的函数
但总来的来说,mmap 有四个用途
共享文件映射
一个应用场景就是两个进程共同读写一个文本文件,比如你用vim编辑保存后,再用cat命令查看
私有文件映射
最典型的应用就是进程对动态链接库(比如libc.so)的使用
共享匿名映射
一个典型应用是作为进程间通信机制的POSIX共享内存
私有匿名映射
用来实现glibc中的malloc
共享 私有 文件 匿名 是指的 我们最终调用 mmap 时传入的参数
共享 私有 是根据 mmap 的 第 4 个参数 定的, int flags
共享 : MAP_SHARED
私有 : MAP_PRIVATE
文件 匿名 是根据 mmap 的 第 5 个参数 定的, int fd
文件 : fd(fd>0)
匿名 : -1
我们分别 以 四种用途 实现 4个 demo
- glibc提供的mmap与linux中的 sys_mmap 有什么关系
在arm中
1. glibc提供的mmap 调用了 swi
2. 硬件会置pc到异常向量表svc
3. svc 异常处理函数中会调用 sys_mmap
1.共享文件映射
一个应用场景就是两个进程共同读写一个文本文件,比如你用vim编辑保存后,再用cat命令查看
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
int main(int argc, char **argv)
{
int fd;
struct stat sb;
char *mapped;
char a = 'a';
if ((fd = open(argv[1], O_RDWR)) < 0) {
perror("open");
}
if ((fstat(fd, &sb)) == -1) {
perror("fstat");
}
if ((mapped = (char *)mmap(NULL, sb.st_size, PROT_READ
|PROT_WRITE,MAP_SHARED, fd, 0)) == (void*)-1) {
perror("mmap");
}
close(fd);
while(1){
mapped[0] = a;
printf("chang to %c\n",a);
a++;
sleep(2);
}
return 0;
}
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
int main(int argc, char **argv)
{
int fd, nread;
struct stat sb;
char *mapped;
if ((fd = open(argv[1], O_RDWR)) < 0) {
perror("open");
}
if ((fstat(fd, &sb)) == -1) {
perror("fstat");
}
if ((mapped = (char *)mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void *)-1) {
perror("mmap");
}
close(fd);
while (1) {
printf("%s\n", mapped);
sleep(2);
}
return 0;
}
echo 1111111111111 > test.txt
一个终端下 ./mmap_read test.txt
另个终端下 ./mmap_write test.txt
2.私有文件映射_TODO
最典型的应用就是进程对动态链接库(比如libc.so)的使用
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\t\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1868984, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe7b0821000
----------------------------------------------------------
mmap(NULL, 3971488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe7b024e000
----------------------------------------------------------
mprotect(0x7fe7b040e000, 2097152, PROT_NONE) = 0
----------------------------------------------------------
mmap(0x7fe7b060e000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c0000) = 0x7fe7b060e000
----------------------------------------------------------
mmap(0x7fe7b0614000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe7b0614000
close(3) = 0
3.共享匿名映射
一个典型应用是作为进程间通信机制的POSIX共享内存
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUF_SIZE 100
int main(int argc, char** argv)
{
char *p_map;
p_map = (char *)mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(fork() == 0) {
sleep(1);
printf("child got a message: %s\n", p_map);
sprintf(p_map, "%s", "hi, dad, this is son");
munmap(p_map, BUF_SIZE);
exit(0);
}
sprintf(p_map, "%s", "hi, this is father");
sleep(2);
printf("parent got a message: %s\n", p_map);
return 0;
}
4.私有匿名映射_TODO
用来实现glibc中的malloc
#include <stdio.h>
int main(void){
char * p;
p = malloc(256*1024);
free(p);
return 0;
}
execve("./malloc_big", ["./malloc_big"], 0x7ffc3396b2e0 ) = 0
brk(NULL) = 0x12d5000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=108218, ...}) = 0
mmap(NULL, 108218, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fbbca09e000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260A\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbbca09c000
mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fbbc9edb000
mprotect(0x7fbbc9efd000, 1658880, PROT_NONE) = 0
mmap(0x7fbbc9efd000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7fbbc9efd000
mmap(0x7fbbca045000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7fbbca045000
mmap(0x7fbbca092000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7fbbca092000
mmap(0x7fbbca098000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fbbca098000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7fbbca09d500) = 0
mprotect(0x7fbbca092000, 16384, PROT_READ) = 0
mprotect(0x403000, 4096, PROT_READ) = 0
mprotect(0x7fbbca0e0000, 4096, PROT_READ) = 0
munmap(0x7fbbca09e000, 108218) = 0
brk(NULL) = 0x12d5000
brk(0x12f6000) = 0x12f6000
-------------------------------------------------------------
mmap(NULL, 266240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbbc9e9a000
-------------------------------------------------------------
munmap(0x7fbbc9e9a000, 266240) = 0
exit_group(0) = ?
+++ exited with 0 +++
266240/1024=260
260=256+4
可见,多申请了4KB