内存共享 - mmap

共享内存映射通信

函数

#include<sys/mman.h>

/* 申请内存并映射 */
void mmap(void *addr, size_t len, int prot,int flags, int fildes, off_t off)
/* 同步数据 */
int msync(void *addr, size_t len, int flags);
/* 解除映射,并释放内存 */
int munmap(void *addr, size_t len);
/* 参数:
  fd:为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间进行通信)。
  len:是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。
  prot:指定空想内存的访问权限。可取如下几个值的或:PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)、PROT_NONE(不可访问)。
  flag:由以下几个常值指定:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
  offset:一般设为0,表示从文件头开始映射。
  addr:指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。
*/
/* 返回值:
    成功:文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。
    失败:(void*)-1
*/

匿名映射实现父子进程通信

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

/* 定义共享内存块的数据结构 */
struct data
{
    int num;
    char str[64];
};

int main()
{
    /* 匿名映射,创建一块内存共父子进程通信 */
    struct data* exam = mmap(NULL,sizeof(struct data),PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1,0);

    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if(pid == 0)
    {
        for(int i = 0; i<5; i++)
        {   /* 子进程循环写五次 */
            exam->num = i;
            strcpy(exam->str,"Hello world!");
            sleep(1);
        }
    }
    else
    {   /* 父进程循环读取五次 */
        for(int i = 0; i < 5; i++)
        {
            printf("%d:%s\n",exam->num,exam->str);
            sleep(1);
        }
    }
}
╭─lingyun@manjaro ~/Document/codes  
╰─➤  gcc forblog.c
╭─lingyun@manjaro ~/Document/codes  
╰─➤  ./a.out    
0:Hello world!
0:Hello world!
1:Hello world!
2:Hello world!
4:Hello world!
╭─lingyun@manjaro ~/Document/codes  

共享内存映射实现两个进程之间的通信 

/* 写进程: forblog.c */
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>

struct data
{
    int num;
    char str[64];
};

int main()
{
    int fd = open("./hello", O_RDWR | O_CREAT,0777);
    if(fd < 0)
    {
        perror("open");
        exit(-1);
    }

    /* 扩展文件大小,否则会出现总线错误 */
    lseek(fd,sizeof(struct data),SEEK_SET);
    write(fd,"\0",1);

    /* 创建一块内存供进程通信 */
    struct data* exam = mmap(NULL,sizeof(struct data),PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(exam == (void*)-1)
    {
        perror("mmap");
        exit(-1);
    }

    for(int i = 0; i<5; i++)
    {   /* 循环写五次 */
        exam->num = i;
        strcpy(exam->str,"Hello world!");
        sleep(1);
    }
    munmap(exam,sizeof(struct data));
    close(fd);
    return 0;
}
/* 读进程: forblog2.c */
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

struct data
{
    int num;
    char str[64];
};

int main()
{
    int fd = open("./hello", O_RDWR | O_CREAT,0777);
    if(fd < 0)
    {
        perror("open");
        exit(-1);
    }

    /* 创建一块内存供进程通信 */
    struct data* exam = mmap(NULL,sizeof(struct data),PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    if(exam == (void*)-1)
    {
        perror("mmap");
        exit(-1);
    }

    for(int i = 0; i<5; i++)
    {   /* 循环读五次 */
        printf("%d:%s\n",exam->num,exam->str);
        sleep(1);
    }
    munmap(exam,sizeof(struct data));
    close(fd);
    return 0;
}
╭─lingyun@manjaro ~  
╰─➤  gcc forblog.c -o write
╭─lingyun@manjaro ~/Document/codes  
╰─➤  ./write
╭─lingyun@manjaro ~  
╰─➤  gcc forblog2.c -o read
╭─lingyun@manjaro ~/Document/codes  
╰─➤  ./read
1:Hello world!
2:Hello world!
3:Hello world!
4:Hello world!
4:Hello world!
╭─lingyun@manjaro ~/Document/codes 

 

### 解决 `syscall-mmap undefined` 错误 当遇到 `syscall-mmap undefined` 的错误时,通常是因为链接器无法找到与 `mmap` 系统调用相关的定义。这可能是由于缺少必要的库文件或者编译选项不正确引起的。 以下是可能的原因以及解决方案: #### 原因分析 1. **未链接正确的库** 如果程序依赖于某些特定的 C 库函数(如 `mmap`),但在编译或链接阶段没有指定这些库,则可能会导致此类错误。例如,在 Linux 下使用 GCC 编译时,默认情况下会链接标准 C 库 (`libc`) 和其他必要库[^1]。 2. **目标平台差异** 不同的操作系统或架构对系统调用的支持有所不同。如果程序是在一种平台上开发并试图运行到另一种平台上,可能导致兼容性问题。 3. **汇编代码中的直接调用** 若程序中有手写的汇编部分直接调用了 `syscall` 指令而未提供完整的参数列表或上下文环境设置不当,也可能引发此问题。 #### 解决策略 ##### 方法一:确认是否遗漏了 `-lc` 参数 在大多数现代 UNIX/Linux 平台上,GCC 默认已经包含了标准C库(`-lc`)。但如果手动指定了较低级别的链接方式(比如仅通过ld),则需显式加入该标志来确保能够访问像 mmap 这样的基本功能。 ```bash gcc your_program.c -o output_binary -lc ``` ##### 方法二:检查 NASM/YASM 组装语法 如果是基于 x86/x86_64 架构下编写的手动嵌入式汇编代码片段,请注意不同版本之间可能存在细微差别;另外还需保证寄存器分配合理且遵循 ABI(Application Binary Interface)规范。 对于 64-bit Linux 上实现 mmap 调用的一个简单例子如下所示: ```nasm section .data ; 数据区声明... section .bss buf resq 1 ; 预留空间用于存储返回地址 section .text global _start ; 入口标签名 _start: mov rax, 9 ; 设置rax=9 表示我们要执行的是第9号系统调用即mmap() xor edi,edi ; 地址设为空(NULL),让内核决定映射位置 mov esi,4096 ; 映射大小为一页(通常是4KB) mov edx,PROT_READ|PROT_WRITE ; 访问权限读写模式 mov ecx,MAP_PRIVATE|MAP_ANONYMOUS ; 文件描述符fd=-1匿名内存区域flag xor r8d,r8d ; fd=-1表示不需要关联任何实际存在的文件对象 xor eax,eax ; offset=0偏移量起点处开始计算长度 syscall ; 发起真正的系统请求操作 test rax,rax ; 测试结果状态码正负情况判断成功与否 js error ; 如果失败跳转至error处理流程分支去打印消息退出进程等动作... success: ; 成功后的逻辑继续往下走即可省略具体细节说明啦~ ... error: lea rdi,[rel msg_fail] call printf mov eax,60 ; exit() system call number. xor edi,edi ; status code to return upon termination. syscall ; invoke operating-system service. msg_fail db 'System Call Failed!',0xA,0xD ``` ##### 方法三:更新工具链版本 有时旧版编译器或连接器内部存在 bug 导致无法正常解析新特性支持状况下的某些指令集扩展形式表达含义。因此建议尝试升级整个开发套件集合直至最新稳定发行版本为止再重新构建项目工程试试看效果如何变化吧! --- ### 提供的相关调试技巧补充材料 上述提到 gdb 工具可以用来逐步跟踪程序崩溃前的状态信息以便定位根本原因所在之处。下面给出一段关于如何利用它查看全局变量表(_GLOBAL_OFFSET_TABLE_)及其附近内存布局结构的小教程作为参考资料学习之用: 假设我们有一个简单的 ELF 可执行文件名为 a.out ,现在想探究其中某个符号的实际物理存放基址是多少可以通过以下命令序列完成查询过程: ```plaintext (gdb) file ./a.out # 加载待测应用程序镜像副本进入调试环境当中加载起来准备就绪等待进一步指示行动方案制定完毕之后就可以正式开始了哦小伙伴们加油干吧!!! Reading symbols from /path/to/a.out...done. (gdb) info functions @got.plt # 列举所有已知导入外部共享动态链接库所导出公开接口成员清单一览表出来看看有没有我们需要的那个家伙呢?? All defined functions matching regular expression "@got\.plt": Non-debugging symbols: 0x0000000000400410 __libc_start_main@plt 0x0000000000400420 puts@plt ...(此处省略其余无关紧要的部分内容)... (gdb)x/10gx &_GLOBAL_OFFSET_TABLE_[0] # 查阅_GOT_首项往后连续十个单元格字节级分布形态特征图谱展示给大家欣赏一下咯嘿嘿嘿😄😄😄 ``` 以上就是针对您提出的有关解决 `syscall-mmap undefined` 问题的一些见解分享希望能帮得到忙😊😊😊
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值