32位兼容模式下的sizeof(int *)

时间:2015-06-30 12:32:46

标签: c malloc x86-64 backwards-compatibility

在使用gcc -m32

编译的Linux x86-64上运行以下命令
#include <stdio.h>
#include <limits.h>

int main() {
    int a = 4;
    int* ptr = &a;

    printf("int* is %d bits in size\n", CHAR_BIT * sizeof(ptr));
    return 0;
}

结果

int* is 32 bits in size

为什么我说服自己它应该是64位(在执行之前):因为它在64位计算机上运行以便寻址内存,所以我们需要64位。由于&amp; a是存储值4的地址,因此它应该是64位。编译器可以通过为所有指针提供相同的偏移量来实现技巧,因为它在兼容模式下运行,但是在多次调用malloc之后它不能保证全等数据。这是错的。为什么呢?

3 个答案:

答案 0 :(得分:3)

在硬件级别上,典型的x86-64处理器具有32位兼容模式,其行为类似于x86处理器。这意味着使用4个字节寻址存储器,因此指针是32位。

在软件级别,64位内核允许在此兼容模式下运行32位进程。

这是'旧的'32位程序可以在64位机器上运行的方式。

编译器,尤其是-m32标志,为x86寻址写入代码,这就是为什么int*也是32位。

答案 1 :(得分:1)

现代CPU有memory management unit,每个程序都有自己的地址空间。你甚至可以使用相同的地址有两个不同的程序。该单元也可以检测分段故障(访问冲突)。这样,程序使用的地址与连接CPU和包括RAM的外围设备的地址总线上的地址不同,因此操作系统为程序分配32位地址没有问题。

答案 2 :(得分:0)

运行64位操作系统的x86-64计算机以“compat”模式运行32位进程,这与“传统”模式不同。在compat模式下,用户空间(即32位程序的观点)与传统模式下的系统(32位一切)的工作方式相同。

但是,内核仍然是64位,并且可以在物理地址空间的任何地方映射compat-mode进程的虚拟地址空间。 (因此两个不同的32b进程每个都可以使用4GB的RAM。)IDK如果compat进程的页表需要与64位进程不同。我找到了http://wiki.osdev.org/Setting_Up_Long_Mode,它有一些东西,但没有回答这个问题。

在compat模式下,系统调用将CPU切换到64b长模式,并从系统调用返回切换回来。将用户空间指针作为参数的内核函数需要简单的包装器来执行从内核空间获取适当地址所需的任何内容。

高级答案是,所有compat模式的硬件支持都需要与传统模式(32位内核)一样快。

IIRC,32位虚拟地址由MMU硬件零扩展到64位,因此内核只是相应地设置页表。

如果在64位代码中使用地址大小覆盖前缀,则所涉及的32位寄存器形成的32位地址将进行零扩展。 (对于不需要超过4GB RAM的代码,有一个x32 ABI,并且会受益于更小的指针,但仍然需要更多寄存器的性能优势,并使它们为64b。)