OK6410A 开发板 (八) 97 linux-5.11 OK6410A glibc提供的mmap的四种用途

glibc提供的mmap简介
  • 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 的四个用途

但总来的来说,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命令查看
  • mmap_write
#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;
}


  • mmap_read
#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)的使用
// 写一个 hello world 程序, 然后 用strace 去 跟踪, 就会得到如下信息
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共享内存
  • demo
#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
  • 128KB 及 以上的malloc
#include <stdio.h>
int main(void){

    char * p;
    p = malloc(256*1024);
    free(p);
    return 0;
}

execve("./malloc_big", ["./malloc_big"], 0x7ffc3396b2e0 /* 25 vars */) = 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值