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线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

linux解压缩 xxx.jar文件进行内部操作过程

《linux解压缩xxx.jar文件进行内部操作过程》:本文主要介绍linux解压缩xxx.jar文件进行内部操作,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、解压文件二、压缩文件总结一、解压文件1、把 xxx.jar 文件放在服务器上,并进入当前目录#

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

在Linux中改变echo输出颜色的实现方法

《在Linux中改变echo输出颜色的实现方法》在Linux系统的命令行环境下,为了使输出信息更加清晰、突出,便于用户快速识别和区分不同类型的信息,常常需要改变echo命令的输出颜色,所以本文给大家介... 目python录在linux中改变echo输出颜色的方法技术背景实现步骤使用ANSI转义码使用tpu

linux hostname设置全过程

《linuxhostname设置全过程》:本文主要介绍linuxhostname设置全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录查询hostname设置步骤其它相关点hostid/etc/hostsEDChina编程A工具license破解注意事项总结以RHE

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S