繁体   English   中英

在Intel(i7)和Arm上是否存在不同的行为?

[英]mmap different behavior on intel (i7) and arm?

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

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

给了我一个指向Ram记忆的指针。 但是,此内存的大小在intel和arm之间有所不同:

在intel上,大小为“长度”,与fildes指向的文件的大小无关。

在ARM上,大小为(大约)fildes指向的文件的大小,而忽略了大小大于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...

关于这一点, mmap官方规范尚不清楚,但请注意以下句子:

在从对象的末尾开始的整个页面中 ,从pa开始到整个页面的 len个字节[,]的地址范围内的[Memory]引用[,]应导致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

(注意,函数report_error (未显示)记录一条错误消息,然后返回NULL。)

好一会儿后我有答案:

  • mmap应该用于遍历文件,因此不应分配比我们要访问的文件大的内存
  • 我意外访问的文件在intel i7系统上的大小不同,因此这是因为它似乎可以在intel上运行。

->解决方案:使用malloc分配大小为“长度”的内存,然后使用“读取”读取文件...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM