mmap对intel(i7)和arm的不同行为?

时间:2014-02-18 14:16:32

标签: c arm mmap opensuse

我使用带有intel i7处理器的Opensuse 13.1编译的程序。我在qemu(虚拟)环境中编译了相同的程序来模拟带有arm处理器的OpenSuse 13.1。这行代码:

rvp = mmap(rvp, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fildes, 0);

给了我一个指向Ram内存的指针。然而,这种记忆的大小在英特尔和手臂之间有所不同:

intel上的

大小是“长度”,与fildes指向的文件大小无关。

在ARM上,大小(大约)是fildes指向的文件的大小,并忽略了size大于fildes的事实。

我希望分配的内存多于文件...

编辑:我试图通过连续两次调用来解决这个问题......但没有成功:

    rvp = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    unsigned int i;
    for (i = 0; i < length; i += 5000)
            printf("acces buffer at %i --> %u\n", i, rvp[i]);
    rvp = mmap(rvp, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fildes, 0);
    for (i = 0; i < length; i += 5000)
            printf("acces buffer at %i --> %u\n", i, rvp[i]);

作为输出我得到:

access buffer at 0 --> 0
...
access buffer at 90000 -> 0
access buffer at 0 --> 0
...
access buffer at 85000 --> 0
Segmentation fault...

2 个答案:

答案 0 :(得分:1)

official specification of mmap在这一点上并不十分清楚,但请注意句子:

  

[Memory]引用[,]在pa开始的地址范围内,并继续len字节[,]到对象结束后的整个页面导致传递SIGBUS信号。

我坚持使用一些逗号,并强调要更清楚地说明一点:如果你mmap一个大于支持它的文件的区域,操作系统应该来激活一个如果你试图访问超出文件末尾的信号,只要你经过一个页面边界(这个许可证只是因为硬件不允许操作系统在可访问和不可访问的内存之间设置一个不属于页面边界)(SIGBUSSIGSEGV现在被许多操作系统视为可互换的。)

您使用“两个连续呼叫”方法处于正确的轨道上,但由于您对两个呼叫使用了相同的长度,因此无法正常工作。如果您在第二次调用中指定了文件的大小,那么它就可以了。您可以使用系统调用fstat检索文件的实际大小。如果文件更大而不是您想要的分配长度,您需要小心。我就是这样写的:

char *map_file(int fd, size_t len)
{
    struct stat st;
    char *rv;

    if (fstat(fd, &st))
        return report_error("fstat");

    if (st.st_size >= (off_t) len) {
        /* If the file is at least as big as expected, just map the
           chunk we want. */
        rv = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
        if (rv == MAP_FAILED)
            return report_error("mmap");

    } else {
        /* Otherwise, we must allocate anonymous memory to fill in the gap. */
        char *anon;
        anon = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
        if (anon == MAP_FAILED)
            return report_error("mmap (anon)");

        rv = mmap(anon, (size_t) st.st_size, PROT_READ|PROT_WRITE,
                  MAP_PRIVATE|MAP_FIXED, fd, 0);
        if (rv == MAP_FAILED) {
            int save_errno = errno;
            (void) munmap(anon, len);
            errno = save_errno;
            return report_error("mmap");
        }
    }
    return rv;
}

根据您的更大目标,使用ftruncate来放大文件(如果它没有预期的那么大)可能更有意义:

char *map_file(int fd, size_t len)
{
    struct stat st;
    char *rv;

    if (fstat(fd, &st))
        return report_error("fstat");
    /* if the file isn't as big as expected, make it bigger */
    if (st.st_size < (off_t) len)
        if (ftruncate(fd, (off_t) len))
            return report_error("ftruncate");

    rv = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
    if (rv == MAP_FAILED)
        return report_error("mmap");
    return rv;
}

但可能,如果这是您在上下文中想要的,那么您将使用MAP_SHARED代替MAP_PRIVATE

(N.B。未显示的函数report_error记录错误消息,然后返回NULL。)

答案 1 :(得分:0)

好吧,经过一段时间的捣乱我得到了答案:

  • mmap应该用于遍历文件,因此不会设想分配比我们想要访问的文件大小更多的内存
  • 我访问的文件意外地在我的intel i7系统上有不同的大小,所以这就是因为它似乎适用于英特尔。

- &GT;解决方案:使用malloc分配大小为“length”的momory,然后使用“read”读取文件...