linux-kernel - 代码(.text)不是只执行? .rodata 是可执行的吗?

标签 linux-kernel elf

我试图了解 ELF 段是如何进行内存映射的。我注意到各个部分都映射到同一个 ELF 段。例如,.rodata 映射到与 .text 相同的段。

为什么会这样?为什么不将 .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 ,但最重要的是有两个位控制允许访问的类型:
  • Bit 1 (R/W):0 表示只读,1 表示读写。
  • Bit 63 (XD):0 表示可执行,1 表示不可执行。

  • 不可能用这些标志指示可执行-无读-无写组合。如果该页完全存在于内存映射中,则它必须是可读的。
    英特尔最新的微架构 Skylake 正在快速推出一个解决方案,该架构将允许只执行内存:它是经过洗礼的 MPK ( memory protection keys ) 功能,在最近发布的 Linux 内核 4.6 中提供了支持。键占据页表条目的 62:59 的四位,内存区域可以用一个键标记,指示执行-不读-不写访问。

    关于linux-kernel - 代码(.text)不是只执行? .rodata 是可执行的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37311863/

    相关文章:

    linux - 无法理解为什么不应该使用/usr/src/linux 进行内核开发

    linux -/lib/modules/<version>/build/不存在

    linux - 从剥离的 ELF 二进制文件估计编译器(GCC 或 LLVM-clang)版本

    c - 使用 memfd_create 和 fexecve 从内存运行 ELF

    linux - 如何从 ELF 文件中禁用地址随机化 (ASLR)?

    c - kmalloc 分配实际上不是连续的吗?

    c - Linux 内核中的内存映射 - vamlloc() 和 kmalloc() 的使用

    c++ - shell 如何管理子进程?

    android - 在 Android 6.0 上读取 Elf32 的 PT_DYNAMIC 条目时出现内存访问错误

    elf - 如何解释elf符号表部分的st_info字段