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

2024-05-27 15:32

本文主要是介绍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 调用了 swi2. 硬件会置pc到异常向量表svc3. 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 100int 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

这篇关于OK6410A 开发板 (八) 97 linux-5.11 OK6410A glibc提供的mmap的四种用途的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007874

相关文章

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

java中ssh2执行多条命令的四种方法

《java中ssh2执行多条命令的四种方法》本文主要介绍了java中ssh2执行多条命令的四种方法,包括分号分隔、管道分隔、EOF块、脚本调用,可确保环境配置生效,提升操作效率,具有一定的参考价值,感... 目录1 使用分号隔开2 使用管道符号隔开3 使用写EOF的方式4 使用脚本的方式大家平时有没有遇到自

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal