- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
在尝试测试时 Is it allowed to access memory that spans the zero boundary in x86?在 Linux 的用户空间中,我编写了一个 32 位测试程序,试图映射 32 位虚拟地址空间的低页和高页。
在 echo 0 | 之后sudo tee/proc/sys/vm/mmap_min_addr
,我可以映射零页,但是我不知道为什么我不能映射-4096
,即(void *)0xfffff000
,最高页。 为什么 mmap2((void*)-4096)
返回 -ENOMEM
?
strace ./a.out
execve("./a.out", ["./a.out"], 0x7ffe08827c10 /* 65 vars */) = 0
strace: [ Process PID=1407 runs in 32 bit mode. ]
....
mmap2(0xfffff000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0
此外,在 linux/mm/mmap.c
中哪些支票拒绝了它,为什么这样设计?这部分是为了确保创建一个指向过去一个对象的指针不会 wrap around and break pointer comparisons ,因为 ISO C 和 C++ 允许创建指向尾后一位的指针,但除此之外不允许创建对象外部的指针。
我在 64 位内核(Arch Linux 上的 4.12.8-2-ARCH)下运行,因此 32 位用户空间有整个 4GiB 可用。 (不同于 64 位内核上的 64 位代码,或 32 位内核,其中 2:2 或 3:1 用户/内核拆分将使高页面成为内核地址。)
我没有尝试使用最小的静态可执行文件(没有 CRT 启动或 libc,只有 asm),因为我认为这不会有什么不同。 CRT 启动系统调用看起来都不是可疑的。
在断点处停止时,我检查了/proc/PID/maps
。首页尚未使用。堆栈包括第二高的页面,但顶部页面未映射。
00000000-00001000 rw-p 00000000 00:00 0 ### the mmap(0) result
08048000-08049000 r-xp 00000000 00:15 3120510 /home/peter/src/SO/a.out
08049000-0804a000 r--p 00000000 00:15 3120510 /home/peter/src/SO/a.out
0804a000-0804b000 rw-p 00001000 00:15 3120510 /home/peter/src/SO/a.out
f7d81000-f7f3a000 r-xp 00000000 00:15 1511498 /usr/lib32/libc-2.25.so
f7f3a000-f7f3c000 r--p 001b8000 00:15 1511498 /usr/lib32/libc-2.25.so
f7f3c000-f7f3d000 rw-p 001ba000 00:15 1511498 /usr/lib32/libc-2.25.so
f7f3d000-f7f40000 rw-p 00000000 00:00 0
f7f7c000-f7f7e000 rw-p 00000000 00:00 0
f7f7e000-f7f81000 r--p 00000000 00:00 0 [vvar]
f7f81000-f7f83000 r-xp 00000000 00:00 0 [vdso]
f7f83000-f7fa6000 r-xp 00000000 00:15 1511499 /usr/lib32/ld-2.25.so
f7fa6000-f7fa7000 r--p 00022000 00:15 1511499 /usr/lib32/ld-2.25.so
f7fa7000-f7fa8000 rw-p 00023000 00:15 1511499 /usr/lib32/ld-2.25.so
fffdd000-ffffe000 rw-p 00000000 00:00 0 [stack]
maps
中是否没有显示 VMA 区域,但仍然说服内核拒绝该地址?我查看了 linux/mm/mmapc.
中出现的 ENOMEM
,但要阅读的代码太多,所以我可能错过了一些东西。保留一些高地址范围的东西,还是因为它在堆栈旁边?
以其他顺序进行系统调用没有帮助(但是 PAGE_ALIGN 和类似的宏被仔细编写以避免在屏蔽之前环绕,所以无论如何这不太可能。)
完整源代码,使用 gcc -O3 -fno-pie -no-pie -m32 address-wrap.c
编译:
#include <sys/mman.h>
//void *mmap(void *addr, size_t len, int prot, int flags,
// int fildes, off_t off);
int main(void) {
volatile unsigned *high =
mmap((void*)-4096L, 4096, PROT_READ | PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
volatile unsigned *zeropage =
mmap((void*)0, 4096, PROT_READ | PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0);
return (high == MAP_FAILED) ? 2 : *high;
}
(我省略了试图取消引用 (int*)-2
的部分,因为它只是在 mmap 失败时出现段错误。)
最佳答案
mmap 函数最终调用 do_mmap或 do_brk_flags它完成满足内存分配请求的实际工作。这些函数依次调用 get_unmapped_area .正是在该函数中进行检查以确保不能分配超出用户地址空间限制的内存,该限制由 TASK_SIZE 定义。 .我引用代码:
* There are a few constraints that determine this:
*
* On Intel CPUs, if a SYSCALL instruction is at the highest canonical
* address, then that syscall will enter the kernel with a
* non-canonical return address, and SYSRET will explode dangerously.
* We avoid this particular problem by preventing anything executable
* from being mapped at the maximum canonical address.
*
* On AMD CPUs in the Ryzen family, there's a nasty bug in which the
* CPUs malfunction if they execute code from the highest canonical page.
* They'll speculate right off the end of the canonical space, and
* bad things happen. This is worked around in the same way as the
* Intel problem.
#define TASK_SIZE_MAX ((1UL << __VIRTUAL_MASK_SHIFT) - PAGE_SIZE)
#define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? \
0xc0000000 : 0xFFFFe000)
#define TASK_SIZE (test_thread_flag(TIF_ADDR32) ? \
IA32_PAGE_OFFSET : TASK_SIZE_MAX)
在具有 48 位虚拟地址空间的处理器上,__VIRTUAL_MASK_SHIFT
为 47。
请注意,TASK_SIZE
的指定取决于当前进程在 32 位上是 32 位,在 64 位上是 32 位,在 64 位上是 64 位。对于 32 位进程,保留两个页面;一个用于 vsyscall page另一个用作保护页。本质上,vsyscall 页面无法取消映射,因此用户地址空间的最高地址实际上是 0xFFFFe000。对于 64 位进程,保留一个保护页。这些页面仅在 64 位 Intel 和 AMD 处理器上保留,因为仅在这些处理器上使用 SYSCALL
机制。
这是在 get_unmapped_area
中执行的检查:
if (addr > TASK_SIZE - len)
return -ENOMEM;
关于linux - 为什么我不能在 64 位内核上 mmap(MAP_FIXED) 32 位 Linux 进程中的最高虚拟页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47712502/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
Linux 管道可以缓冲多少数据?这是可配置的吗? 如果管道的两端在同一个进程中,但线程不同,这会有什么不同吗? 请注意:这个“同一个进程,两个线程”的问题是理论上的边栏,真正的问题是关于缓冲的。 最
我找到了here [最后一页] 一种有趣的通过 Linux 启动 Linux 的方法。不幸的是,它只是被提及,我在网上找不到任何有用的链接。那么有人听说过一种避免引导加载程序而使用 Linux 的方法
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我试图了解 ld-linux.so 如何在 Linux 上解析对版本化符号的引用。我有以下文件: 测试.c: void f(); int main() { f(); } a.c 和 b.c:
与 RetroPie 的工作原理类似,我可以使用 Linux 应用程序作为我的桌面环境吗?我实际上并不需要像实际桌面和安装应用程序这样的东西。我只需要一种干净简单的方法来在 RaspberryPi 上
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
有什么方法可以覆盖现有的源代码,我应该用 PyQt、PyGTK、Java 等从头开始构建吗? 最佳答案 如果您指的是软件本身而不是它所连接的存储库,那么自定义应用程序的方法就是 fork 项目。据我所
我的情况是:我在一个磁盘上安装了两个 linux。我将第一个安装在/dev/sda1 中,然后在/dev/sda2 中安装第二个然后我运行第一个系统,我写了一个脚本来在第一个系统运行时更新它。
我在 i2c-0 总线上使用地址为 0x3f 的系统监视器设备。该设备在设备树中配置有 pmbus 驱动程序。 问题是,加载 linux 内核时,这个“Sysmon”设备没有供电。因此,当我在总线 0
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
我正试图在 linux 模块中分配一大块内存,而 kalloc 做不到。 我知道唯一的方法是使用 alloc_bootmem(unsigned long size) 但我只能从 linux 内核而不是
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有 .sh 文件来运行应用程序。在该文件中,我想动态设置服务器名称,而不是每次都配置。 我尝试了以下方法,它在 CentOS 中运行良好。 nohup /voip/java/jdk1.8.0_71/
我是在 Linux 上开发嵌入式 C++ 程序的新手。我有我的 Debian 操作系统,我在其中开发和编译了我的 C++ 项目(一个简单的控制台进程)。 我想将我的应用程序放到另一个 Debian 操
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我使用4.19.78版本的稳定内核,我想找到带有企鹅二进制数据的C数组。系统启动时显示。我需要在哪里搜索该内容? 我在 include/linux/linux_logo.h 文件中只找到了一些 Log
我知道可以使用 gdb 的服务器模式远程调试代码,我知道可以调试针对另一种架构交叉编译的代码,但是是否可以更进一步,从远程调试 Linux 应用程序OS X 使用 gdbserver? 最佳答案 当然
是否有任何可能的方法来运行在另一个 Linux 上编译的二进制文件?我知道当然最简单的是在另一台机器上重建它,但假设我们唯一能得到的是一个二进制文件,那么这可能与否? (我知道这可能并不容易,但我只是
我是一名优秀的程序员,十分优秀!