与MMAP重叠页面(MAP_FIXED) [英] Overlapping pages with mmap (MAP_FIXED)

查看:1712
本文介绍了与MMAP重叠页面(MAP_FIXED)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于这是不相关的这个问题,一些模糊的原因,我需要求助于以使用MAP_FIXED获得接近页面,在这里生活的libc内存中的文字部分。

阅读的mmap(2)(我应该在第一时间做了),我期待得到一个错误,如果我叫MMAP与MAP_FIXED以及基地址重叠已经映射区域之前。

但是事实并非如此。举例来说,这里是的/ proc的一部分/对某些过程图

  7ffff7299000-7ffff744c000 R-XP 00000000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so

其中,使得下面的mmap调用后...

  MMAP(0x7ffff731b000,
       为getpagesize()
       PROT_READ | PROT_WRITE | PROT_EXEC,
       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
       0,
       0);

...变为:

  7ffff7299000-7ffff731b000 R-XP 00000000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so
7ffff731b000-7ffff731c000 rwxp 00000000 00:00 0
7ffff731c000-7ffff744c000 R-XP 00083000 08:05 654098 /lib/x86_64-linux-gnu/libc-2.15.so

这意味着我已经覆盖献给我自己的页面,libc中的虚拟地址空间的一部分。显然不是我想要什么...

在MMAP的MAP_FIXED部分(2)手册,它明确规定:


  

如果addr和len所指定的内存区域重叠的任何页面
                现有映射(S),那么现有的映射(S)的重叠部分将丢弃


这解释了我所看到的,但我有几个问题:


  1. 有没有一种方法,如果事情已经映射到特定地址来检测?无accesing的/ proc /地图?

  2. 有没有办法强制MMAP找到页面重叠的情况下,失败?


解决方案

  1. 使用页=的sysconf(SC_PAGE_SIZE)来找出页面大小,然后扫描你希望使用的 则msync(地址,页面,0) (以(无符号长)地址%的页面== 0 ,即地址对齐页)。如果返回 1 的errno == ENOMEM ,该页面没有被映射。

    编辑:由于下面FONS评论, 和mincore(地址,页面和放大器;虚拟) 优于则msync()。 (系统调用的实现是在Linux内核源代码的毫米/ mincore.c ,与C库通常提供了一个包装,更新错误号,由于系统调用确实映射检查,确保后立即地址是页对齐的,它是在不映射的情况下,最佳的( ENOMEM )。它确实有些工作如果页面已被映射,所以如果性能是极为重要的,尽量避免检查你知道被映射的页面。

    您必须单独做到这一点,每个单独的每一页,因为多为单页更大的地区, ENOMEM 意味着该区域没有完全映射;它可能仍然可以部分映射。映射总是颗粒状页大小的单位。


  2. 据我所知,是没有办法告诉的mmap()失败,如果该地区已被映射,或者包含已映射的页面。 (同样适用于 mremap(),所以你不能创建一个映射,然后将其移动到所需的区域。)

    这意味着你运行一个竞争条件的风险。这将是最好的自己执行实际的系统调用,而不是C库包装,以防万一他们做​​内存分配或更改内部存储器映射:

     的#define _GNU_SOURCE
    #包括LT&;&unistd.h中GT;
    #包括LT&; SYS / syscall.h>静态页面为size_t = 0;
    静态内联为size_t PAGE_SIZE(无效)
    {
        如果(!页)
            网页=(为size_t)的sysconf(_SC_PAGESIZE);
        返回页面;
    }
    静态内嵌INT raw_msync(void *的地址,为size_t长度,INT标志)
    {
        返回系统调用(SYS_msync,地址,长度,标志);
    }静态内嵌无效* raw_mmap(void *的地址,为size_t长度,PROT INT,INT标志)
    {
        回报(无效*)系统调用(SYS_mmap,地址,长度,PROT,旗帜,-1,(off_t)0);
    }


不过,我怀疑,不管它是你正在尝试做的,你最终需要解析的/ proc /自/图反正。


  • 我建议避免标准I / O stdio.h中共(如不同的操作将动态分配内存,从而改变映射),而是使用较低层次的 unistd.h中接口,这是不太可能影响映射。下面是一组简单,粗糙的功能,你可以用它来找出每个映射区域,并在该区域启用了保护(并丢弃等信息)。在实践中,它使用大约code和更少的比在栈千字节,因此它是即使在有限的架构非常有用的(例如,嵌入式设备)。

     的#include<&unistd.h中GT;
    #包括LT&;&fcntl.h GT;
    #包括LT&;&errno.h中GT;
    #包括LT&;&string.h中GT;的#ifndef INPUT_BUFFER
    #定义INPUT_BUFFER 512
    #ENDIF / * * INPUT_BUFFER /的#ifndef INPUT_EOF
    #定义INPUT_EOF -256
    #ENDIF / * * INPUT_EOF /#定义PERM_PRIVATE 16
    #定义PERM_SHARED 8
    #定义PERM_READ 4
    #定义PERM_WRITE 2
    #定义PERM_EXEC 1typedef结构{
        INT描述;
        INT状态;
        无符号字符*接下来的;
        无符号字符*结束;
        无符号字符缓冲区[INPUT_BUFFER + 16];
    } input_buffer;/ *笔芯输入缓冲区。返回的新的字节数。
     *在EOF设置状态ENODATA。
    * /
    静态为size_t input_refill(input_buffer * const的输入)
    {
        ssiz​​e_t供N;    如果(输入 - >状态)
            回报(为size_t)0;    如果(输入 - >接下来>输入 - >缓冲区){
            如果(输入 - >&结束GT;输入 - >接下来){
                的memmove(输入 - &GT缓冲液,输入 - >接着,
                        (为size_t)(输入 - >末端 - 输入 - >接下来));
                输入 - >结束=输入 - >缓冲区+(为size_t)(输入 - >末端 - 输入 - >接着);
                输入 - >接着=输入 - >缓冲液;
            }其他{
                输入 - >结束=输入 - >缓冲区;
                输入 - >接着=输入 - >缓冲液;
            }
        }    做{
            N =读取(输入 - >描述符,输入 - >末端,
                     INPUT_BUFFER - (为size_t)(输入 - >末端 - 输入 - >缓冲区));
        }而(N ==(ssize_t供)-1放大器;&放大器;错误号== EINTR);
        如果(N>(ssize_t供)0){
            输入 - >两端+ = N;
            返回(为size_t)N;    }其他
        如果(N ==(ssize_t供)0){
            输入 - >状态= ENODATA;
            回报(为size_t)0;
        }    如果(N ==(ssize_t供)-1)
            输入 - >状态=错误号;
        其他
            输入 - >状态= EIO;    回报(为size_t)0;
    }/ *低杆的getchar()等价的。
    * /
    静态内嵌INT input_next(input_buffer * const的输入)
    {
        如果(输入 - >接下来<输入 - >结束)
            返回*(输入 - >接着++);
        其他
        如果(input_refill(输入)大于0)
            返回*(输入 - >接着++);
        其他
            返回INPUT_EOF;
    }/ *低级与ungetc()等价的。
    * /
    静态内嵌INT input_back(input_buffer * const的输入,const int的C)
    {
        如果(C< 0 || C> 255)
            返回INPUT_EOF;
        其他
        如果(输入 - >接下来>输入 - >缓冲区)
            返回*( - 输入 - >下面)= C;
        其他
        如果(输入 - >&结束GT =输入 - >缓冲区+ sizeof的输入 - >缓冲区)
            返回INPUT_EOF;    的memmove(输入 - >接着+ 1,输入 - >接着,(为size_t)(输入 - >结束 - 输入 - >接着));
        输入 - >末端++;
        回*(输入 - >下面)= C;
    }/ *低级fopen()函数相同。
    * /
    静态INT input_open(input_buffer * const的输入,为const char * const的文件名)
    {
        如果(!输入)
            返回的errno = EINVAL;    输入 - >描述= -1;
        输入 - >状态= 0;
        输入 - >接着=输入 - >缓冲液;
        输入 - >结束=输入 - >缓冲区;    如果(!||名!*文件名)
            返回错误号=输入 - >状态= EINVAL;    做{
            输入 - >描述=开放(文件名,O_RDONLY | O_NOCTTY);
        }而(输入 - >描述符== -1放大器;&放大器;错误号== EINTR);
        如果(输入 - >描述符== -1)
            返回输入 - >状态=错误号;    返回0;
    }/ *低级FCLOSE()等价的。
    * /
    静态INT input_close(input_buffer * const的输入)
    {
        INT结果;    如果(!输入)
            返回的errno = EINVAL;    / * EOF不是一个错误;我们使用ENODATA了点。 * /
        如果(输入 - >状态== ENODATA)
            输入 - >状态= 0;    如果(输入 - >描述符!= -1){
            做{
                结果=关闭(输入 - >描述符);
            }而(结果== -1放大器;&放大器;错误号== EINTR);
            如果(结果== -1放大器;&安培;!输入 - >状态)
                输入 - >状态=错误号;
        }    输入 - >描述= -1;
        输入 - >接着=输入 - >缓冲液;
        输入 - >结束=输入 - >缓冲区;    返回错误号=输入 - >现状;
    }/ *读取的/ proc /自/地图,并填写相应的字段数组。
     *该函数将返回映射的数目,即使不是所有被保存。
    * /
    为size_t read_maps(为size_t常量N,
                     无效**常量PTR,为size_t * const的LEN,
                     无符号char * const的模式)
    {
        input_buffer输入;
        为size_t I = 0;
        无符号长curr_start,curr_end;
        unsigned char型curr_mode;
        INT℃;    错误号= 0;    如果(input_open(安培;输入的/ proc /自/图))
            回报(为size_t)0; / *错误号已设置。 * /    C = input_next(安培;输入);
        而(c取代; = 0){        / *跳到领先的控制和空白* /
            而(c取代; = 0&放大器;&放大器;℃下= 32)
                C = input_next(安培;输入);        / * EOF? * /
            如果(C&小于0)
                打破;        curr_start = 0UL;
            curr_end = 0UL;
            curr_mode = 0U;        / *地址范围的开始。 * /
            而(1)
                如果(c取代; ='0'和;&放大器;℃下='9'){
                    curr_start =(16UL * curr_start)+ C - '0';
                    C = input_next(安培;输入);
                }其他
                如果(c基='A'和;&安培; C< ='F'){
                    curr_start =(16UL * curr_start)+ C - 'A'+ 10;
                    C = input_next(安培;输入);
                }其他
                如果(c取代; ='一'和;&放大器;℃下='F​​'){
                    curr_start =(16UL * curr_start)+ C - 'A'+ 10;
                    C = input_next(安培;输入);
                }其他
                    打破;
            如果(C ==' - ')
                C = input_next(安培;输入);
            其他{
                错误号= EIO;
                回报(为size_t)0;
            }        / *地址范围的结束。 * /
            而(1)
                如果(c取代; ='0'和;&放大器;℃下='9'){
                    curr_end =(16UL * curr_end)+ C - '0';
                    C = input_next(安培;输入);
                }其他
                如果(c基='A'和;&安培; C< ='F'){
                    curr_end =(16UL * curr_end)+ C - 'A'+ 10;
                    C = input_next(安培;输入);
                }其他
                如果(c取代; ='一'和;&放大器;℃下='F​​'){
                    curr_end =(16UL * curr_end)+ C - 'A'+ 10;
                    C = input_next(安培;输入);
                }其他
                    打破;
            如果(C =='')
                C = input_next(安培;输入);
            其他{
                错误号= EIO;
                回报(为size_t)0;
            }        / *权限。 * /
            而(1)
                如果(C =='R'){
                    curr_mode | = PERM_READ;
                    C = input_next(安培;输入);
                }其他
                如果(C =='W'){
                    curr_mode | = PERM_WRITE;
                    C = input_next(安培;输入);
                }其他
                如果(C =='X'){
                    curr_mode | = PERM_EXEC;
                    C = input_next(安培;输入);
                }其他
                如果(C =='S'){
                    curr_mode | = PERM_SHARED;
                    C = input_next(安培;输入);
                }其他
                如果(C =='P'){
                    curr_mode | = PERM_PRIVATE;
                    C = input_next(安培;输入);
                }其他
                如果(C ==' - '){
                    C = input_next(安培;输入);
                }其他
                    打破;
            如果(C =='')
                C = input_next(安培;输入);
            其他{
                错误号= EIO;
                回报(为size_t)0;
            }        / *跳到该行的其余部分。 * /
            而(C> = 0&放大器;&安培;!C ='\\ n')
                C = input_next(安培;输入);        / * ...添加到阵列中,如果可能的话。 * /
            如果(ⅰ&下; N){
                如果(PTR)PTR [I] =(无效*)curr_start;
                如果(LEN)LEN [I] =(为size_t)(curr_end - curr_start);
                如果(模式)模式[I] = curr_mode;
            }
            我++;
        }    如果(input_close(安培;输入))
            回报(为size_t)0; / *错误号已设置。 * /    错误号= 0;
        返回我;
    }

    read_maps()函数读取高达 N 区域,起始地址为无效* PTR 阵列,长度到 LEN 阵列和权限到模式阵列,返回地图的总数(可能比 N 以上),或零用错误号如果发生错误设置。

    这是很可能使用系统调用的低级别的I / O上面,这样你不使用任何C库的功能,​​但我不认为这是在所有必要的。 (C库,据我所知,用很简单的包装器,这些实际的系统调用。)


我希望你能找到这个有用。

Due to some obscure reasons which are not relevant for this question, I need to resort to use MAP_FIXED in order to obtain a page close to where the text section of libc lives in memory.

Before reading mmap(2) (which I should had done in the first place), I was expecting to get an error if I called mmap with MAP_FIXED and a base address overlapping an already-mapped area.

However that is not the case. For instance, here is part of /proc/maps for certain process

7ffff7299000-7ffff744c000 r-xp 00000000 08:05 654098                     /lib/x86_64-linux-gnu/libc-2.15.so

Which, after making the following mmap call ...

  mmap(0x7ffff731b000,
       getpagesize(),
       PROT_READ | PROT_WRITE | PROT_EXEC,
       MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
       0,
       0);

... turns into:

7ffff7299000-7ffff731b000 r-xp 00000000 08:05 654098                     /lib/x86_64-linux-gnu/libc-2.15.so
7ffff731b000-7ffff731c000 rwxp 00000000 00:00 0 
7ffff731c000-7ffff744c000 r-xp 00083000 08:05 654098                     /lib/x86_64-linux-gnu/libc-2.15.so

Which means I have overwritten part of the virtual address space dedicated to libc with my own page. Clearly not what I want ...

In the MAP_FIXED part of the mmap(2) manual, it clearly states:

If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded.

Which explains what I am seeing, but I have a couple of questions:

  1. Is there a way to detect if something was already mapped to certain address? without accesing /proc/maps?
  2. Is there a way to force mmap to fail in the case of finding overlapping pages?

解决方案

  1. Use page = sysconf(SC_PAGE_SIZE) to find out the page size, then scan each page-sized block you wish to check using msync(addr, page, 0) (with (unsigned long)addr % page == 0, i.e. addr aligned to pages). If it returns -1 with errno == ENOMEM, that page is not mapped.

    Edited: As fons commented below, mincore(addr,page,&dummy) is superior to msync(). (The implementation of the syscall is in mm/mincore.c in the Linux kernel sources, with C libraries usually providing a wrapper that updates errno. As the syscall does the mapping check immediately after making sure addr is page aligned, it is optimal in the not-mapped case (ENOMEM). It does some work if the page is already mapped, so if performance is paramount, try to avoid checking pages you know are mapped.

    You must do this individually, separately per each page, because for regions larger than a single page, ENOMEM means that the region was not fully mapped; it might still be partially mapped. Mapping is always granular to page-sized units.

  2. As far as I can tell, there is no way to tell mmap() to fail if the region is already mapped, or contains already mapped pages. (The same applies to mremap(), so you cannot create a mapping, then move it to the desired region.)

    This means you run a risk of a race condition. It would be best to execute the actual syscalls yourself, instead of the C library wrappers, just in case they do memory allocation or change memory mappings internally:

    #define _GNU_SOURCE
    #include <unistd.h>
    #include <sys/syscall.h>
    
    static size_t page = 0;
    static inline size_t page_size(void)
    {
        if (!page)
            page = (size_t)sysconf(_SC_PAGESIZE);
        return page;
    }
    
    
    static inline int raw_msync(void *addr, size_t length, int flags)
    {
        return syscall(SYS_msync, addr, length, flags);
    }
    
    static inline void *raw_mmap(void *addr, size_t length, int prot, int flags)
    {
        return (void *)syscall(SYS_mmap, addr, length, prot, flags, -1, (off_t)0);
    }
    

However, I suspect that whatever it is you are trying to do, you eventually need to parse /proc/self/maps anyway.

  • I recommend avoiding standard I/O stdio.h altogether (as the various operations will allocate memory dynamically, and thus change the mappings), and instead use the lower-level unistd.h interfaces, which are much less likely to affect the mappings. Here is a set of simple, crude functions, that you can use to find out each mapped region and the protections enabled in that region (and discard the other info). In practice, it uses about a kilobyte of code and less than that in stack, so it is very useful even on limited architectures (say, embedded devices).

    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <string.h>
    
    #ifndef   INPUT_BUFFER
    #define   INPUT_BUFFER   512
    #endif /* INPUT_BUFFER */
    
    #ifndef   INPUT_EOF
    #define   INPUT_EOF     -256
    #endif /* INPUT_EOF */
    
    #define   PERM_PRIVATE  16
    #define   PERM_SHARED    8
    #define   PERM_READ      4
    #define   PERM_WRITE     2
    #define   PERM_EXEC      1
    
    typedef struct {
        int            descriptor;
        int            status;
        unsigned char *next;
        unsigned char *ends;
        unsigned char  buffer[INPUT_BUFFER + 16];
    } input_buffer;
    
    /* Refill input buffer. Returns the number of new bytes.
     * Sets status to ENODATA at EOF.
    */
    static size_t input_refill(input_buffer *const input)
    {
        ssize_t n;
    
        if (input->status)
            return (size_t)0;
    
        if (input->next > input->buffer) {
            if (input->ends > input->next) {
                memmove(input->buffer, input->next,
                        (size_t)(input->ends - input->next));
                input->ends = input->buffer + (size_t)(input->ends - input->next);
                input->next = input->buffer;
            } else {
                input->ends = input->buffer;
                input->next = input->buffer;
            }
        }
    
        do {
            n = read(input->descriptor, input->ends,
                     INPUT_BUFFER - (size_t)(input->ends - input->buffer));
        } while (n == (ssize_t)-1 && errno == EINTR);
        if (n > (ssize_t)0) {
            input->ends += n;
            return (size_t)n;
    
        } else
        if (n == (ssize_t)0) {
            input->status = ENODATA;
            return (size_t)0;
        }
    
        if (n == (ssize_t)-1)
            input->status = errno;
        else
            input->status = EIO;
    
        return (size_t)0;
    }
    
    /* Low-lever getchar() equivalent.
    */
    static inline int input_next(input_buffer *const input)
    {
        if (input->next < input->ends)
            return *(input->next++);
        else
        if (input_refill(input) > 0)
            return *(input->next++);
        else
            return INPUT_EOF;
    }
    
    /* Low-level ungetc() equivalent.
    */
    static inline int input_back(input_buffer *const input, const int c)
    {
        if (c < 0 || c > 255)
            return INPUT_EOF;
        else
        if (input->next > input->buffer)
            return *(--input->next) = c;
        else
        if (input->ends >= input->buffer + sizeof input->buffer)
            return INPUT_EOF;
    
        memmove(input->next + 1, input->next, (size_t)(input->ends - input->next));
        input->ends++;
        return *(input->next) = c;
    }
    
    /* Low-level fopen() equivalent.
    */
    static int input_open(input_buffer *const input, const char *const filename)
    {
        if (!input)
            return errno = EINVAL;
    
        input->descriptor = -1;
        input->status = 0;
        input->next = input->buffer;
        input->ends = input->buffer;
    
        if (!filename || !*filename)
            return errno = input->status = EINVAL;
    
        do {
            input->descriptor = open(filename, O_RDONLY | O_NOCTTY);
        } while (input->descriptor == -1 && errno == EINTR);
        if (input->descriptor == -1)
            return input->status = errno;
    
        return 0;
    }
    
    /* Low-level fclose() equivalent.
    */
    static int input_close(input_buffer *const input)
    {
        int result;
    
        if (!input)
            return errno = EINVAL;
    
        /* EOF is not an error; we use ENODATA for that. */
        if (input->status == ENODATA)
            input->status = 0;
    
        if (input->descriptor != -1) {
            do {
                result = close(input->descriptor);
            } while (result == -1 && errno == EINTR);
            if (result == -1 && !input->status)
                input->status = errno;
        }
    
        input->descriptor = -1;
        input->next = input->buffer;
        input->ends = input->buffer;
    
        return errno = input->status;
    }
    
    /* Read /proc/self/maps, and fill in the arrays corresponding to the fields.
     * The function will return the number of mappings, even if not all are saved.
    */
    size_t read_maps(size_t const n,
                     void **const ptr, size_t *const len,
                     unsigned char *const mode)
    {
        input_buffer    input;
        size_t          i = 0;
        unsigned long   curr_start, curr_end;
        unsigned char   curr_mode;
        int             c;
    
        errno = 0;
    
        if (input_open(&input, "/proc/self/maps"))
            return (size_t)0; /* errno already set. */
    
        c = input_next(&input);
        while (c >= 0) {
    
            /* Skip leading controls and whitespace */
            while (c >= 0 && c <= 32)
                c = input_next(&input);
    
            /* EOF? */
            if (c < 0)
                break;
    
            curr_start = 0UL;
            curr_end = 0UL;
            curr_mode = 0U;
    
            /* Start of address range. */
            while (1)
                if (c >= '0' && c <= '9') {
                    curr_start = (16UL * curr_start) + c - '0';
                    c = input_next(&input);
                } else
                if (c >= 'A' && c <= 'F') {
                    curr_start = (16UL * curr_start) + c - 'A' + 10;
                    c = input_next(&input);
                } else
                if (c >= 'a' && c <= 'f') {
                    curr_start = (16UL * curr_start) + c - 'a' + 10;
                    c = input_next(&input);
                } else
                    break;
            if (c == '-')
                c = input_next(&input);
            else {
                errno = EIO;
                return (size_t)0;
            }
    
            /* End of address range. */
            while (1)
                if (c >= '0' && c <= '9') {
                    curr_end = (16UL * curr_end) + c - '0';
                    c = input_next(&input);
                } else
                if (c >= 'A' && c <= 'F') {
                    curr_end = (16UL * curr_end) + c - 'A' + 10;
                    c = input_next(&input);
                } else
                if (c >= 'a' && c <= 'f') {
                    curr_end = (16UL * curr_end) + c - 'a' + 10;
                    c = input_next(&input);
                } else
                    break;
            if (c == ' ')
                c = input_next(&input);
            else {
                errno = EIO;
                return (size_t)0;
            }
    
            /* Permissions. */
            while (1)
                if (c == 'r') {
                    curr_mode |= PERM_READ;
                    c = input_next(&input);
                } else
                if (c == 'w') {
                    curr_mode |= PERM_WRITE;
                    c = input_next(&input);
                } else
                if (c == 'x') {
                    curr_mode |= PERM_EXEC;
                    c = input_next(&input);
                } else
                if (c == 's') {
                    curr_mode |= PERM_SHARED;
                    c = input_next(&input);
                } else
                if (c == 'p') {
                    curr_mode |= PERM_PRIVATE;
                    c = input_next(&input);
                } else
                if (c == '-') {
                    c = input_next(&input);
                } else
                    break;
            if (c == ' ')
                c = input_next(&input);
            else {
                errno = EIO;
                return (size_t)0;
            }
    
            /* Skip the rest of the line. */
            while (c >= 0 && c != '\n')
                c = input_next(&input);
    
            /* Add to arrays, if possible. */
            if (i < n) {
                if (ptr) ptr[i] = (void *)curr_start;
                if (len) len[i] = (size_t)(curr_end - curr_start);
                if (mode) mode[i] = curr_mode;
            }
            i++;
        }
    
        if (input_close(&input))
            return (size_t)0; /* errno already set. */
    
        errno = 0;
        return i;
    }
    

    The read_maps() function reads up to n regions, start addresses as void * into the ptr array, lengths into the len array, and permissions into the mode array, returning the total number of maps (may be greater than n), or zero with errno set if an error occurs.

    It is quite possible to use syscalls for the low-level I/O above, so that you don't use any C library features, but I don't think it is at all necessary. (The C libraries, as far as I can tell, use very simple wrappers around the actual syscalls for these.)

I hope you find this useful.

这篇关于与MMAP重叠页面(MAP_FIXED)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆