You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何32位程序的栈处于内核虚拟地址空间高地址段?

问题分析与解答

问题背景

你编写了一个简单的C程序,声明了两个局部变量(一个已初始化、一个未初始化):

#include <stdio.h>

int main() {
    int local_var_1 = 0;
    int local_var_2;

    printf("Local var 1 address: %p\n", &local_var_1);
    printf("Local var 2 address: %p\n", &local_var_2);

    return 0;
}

使用以下GCC命令编译为32位程序:

gcc -Wpedantic -m32 -g -fno-stack-protector -no-pie -mpreferred-stack-boundary=2 -static -fno-pic -o test_prog test_prog.c

执行后输出:

Local var 1 address: 0xffffce74
Local var 2 address: 0xffffce70

你发现这些栈变量的地址落在0xC0000000到0xFFFFFFFF区间,和教材中“32位Linux内核占用0xC0000000以上地址”的描述不符,产生困惑。

核心原因

1. 运行环境是x86_64内核下的32位兼容程序

你的系统是x86_64架构的Linux(6.11.2-amd64),-m32选项让GCC编译出32位ELF程序。x86_64内核的虚拟地址空间布局和原生32位内核完全不同:

  • 原生32位Linux内核会占用32位地址空间的高1GB(0xC0000000到0xFFFFFFFF),用户态只能使用低3GB;
  • 但x86_64内核的内核空间位于64位虚拟地址的高区(例如从0xffff800000000000开始),完全不在32位地址范围内。因此,32位兼容进程的整个32位地址空间(0x00000000到0xFFFFFFFF)都属于用户态,0xC0000000到0xFFFFFFFF区间自然可以被用户栈使用。

2. 32位程序的栈地址分配逻辑

Linux中,用户栈默认从用户态地址空间的最高地址向下增长。对于x86_64上的32位程序,用户态地址空间最高到0xFFFFFFFF,所以栈会从接近这个地址的位置开始分配,这就是你看到0xffffce74这类高地址的原因。

3. 编译选项强化了地址固定性

你使用的-no-pie、-static和禁用ASLR的设置,让程序成为非位置无关的静态链接程序,栈地址完全固定,不会被随机化,所以能稳定看到这类高地址。

总结

教材中的虚拟内存布局图针对的是原生32位Linux内核,而你在x86_64内核下运行32位兼容程序,地址空间规则完全不同——32位地址区间全归用户态,内核在64位高地址区,因此栈可以使用0xC0000000到0xFFFFFFFF的区间。

内容的提问来源于stack exchange,提问作者Mason Ticehurst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 09:40:12