为什么会这样?为什么不将.rodata映射到单独的只读且不可执行的段?
此外,将.text部分映射到“仅执行”段(不可读)需要什么?是否存在可能阻碍此问题的内核/硬件限制?
编辑:
我还可以补充说我正在使用GNU链接器,如果这有所不同.
解决方法
在包括x86-64在内的多种计算机体系结构中,将内存标记为可执行但不可读是不可能的.
虽然x86 16位和32位确实允许在传统模式中进行分段,并且理论上可以使用内存段将内存标记为仅可执行文件,但是平面地址空间的优势非常大,以至于x86-64现在为mostly ignores its segments registers:
3.2.4 Segmentation in IA-32e Mode
In IA-32e mode of Intel 64 architecture,the effects of segmentation depend on whether the processor is running in compatibility mode or 64-bit mode. In compatibility mode,segmentation functions just as it does using legacy 16-bit or 32-bit protected mode semantics.
In 64-bit mode,segmentation is generally (but not completely) disabled,creating a flat 64-bit linear-address space. The processor treats the segment base of CS,DS,ES,SS as zero,creating a linear address that is equal to the effective address. The FS and GS segments are exceptions. These segment registers (which hold the segment base) can be used as additional base registers in linear address calculations. They facilitate addressing local data and certain operating system data structures.
Note that the processor does not perform segment limit checks at runtime in 64-bit mode.
因此,内核只是将它们的段设置为覆盖整个地址空间,而不依赖于分段来实现内存保护.
他们使用的是页表的属性.进程内存映射中存在的每个页面都有一个页表条目,用于控制对它的访问.可以在here中看到它们的格式概述,但最重要的是有两个位控制允许的访问类型:
>位1(R / W):0表示只读,1表示读写.
>位63(XD):0表示可执行,1表示不可执行.
无法使用这些标志指示可执行文件 – noread-nowrite组合.如果页面完全存在于内存映射中,则它必须是可读的.
英特尔最新的微体系结构Skylake正在快速实现解决方案,该解决方案将允许只执行内存:它是受洗的功能MPK(memory protection keys),支持最近发布的Linux内核4.6.密钥占用页表条目的四位62:59,并且内存区域可以用指示execute-noread-nowrite访问的键标记.