自定义链接二进制含RWX权限LOAD段,如何修改linker script?
解决链接脚本中权限不同段合并为单一LOAD段的问题
你遇到的问题是链接器默认会把连续、权限兼容的段合并成一个LOAD程序头,导致.text、.rodata、.data、.bss被打包成了带RWX权限的LOAD段,既触发新版本GCC警告,也没法给内存页表设置正确的权限(比如.text不可写、.data不可执行)。要解决这个问题,需要用PHDRS显式定义不同权限的程序头,把每个段绑定到对应的LOAD段上,修改后的链接脚本如下:
ENTRY(kmain) OUTPUT_FORMAT(elf64-x86-64) // 显式定义各个权限的程序头,每个对应一个独立LOAD段 PHDRS { text PT_LOAD FLAGS(5); // 5 = 读+执行(RX)权限 rodata PT_LOAD FLAGS(4); // 4 = 只读(R)权限 data PT_LOAD FLAGS(6); // 6 = 读+写(RW)权限 eh_frame PT_LOAD FLAGS(4); // .eh_frame 设为只读权限 } SECTIONS { . = 0xFFFFFFFF80000000; // .text段绑定到text程序头,RX权限 .text ALIGN(4K) : { *(.text) } :text // 强制跳过一页,避免链接器因地址连续尝试合并不同权限的段 . += 4K; // .rodata段绑定到rodata程序头,R权限 .rodata ALIGN(4K) : { *(.rodata) } :rodata . += 4K; // .data段绑定到data程序头,RW权限 .data ALIGN(4K) : { *(.data) } :data // .bss和.data权限一致,绑定到同一个data程序头 .bss ALIGN(4K) : { *(.bss) } :data . += 4K; // .eh_frame绑定到独立的eh_frame程序头,R权限 .eh_frame ALIGN(4K) : { *(.eh_frame) } :eh_frame }
关键修改说明
- PHDRS定义:用
PHDRS块声明每个LOAD段的类型和权限,FLAGS参数对应ELF的权限位:5代表RX、4代表R、6代表RW,明确区分不同权限的LOAD段。 - 段与程序头绑定:每个section定义末尾加上
:<程序头名称>,把该段关联到对应的LOAD段,告诉链接器不要把它和其他权限的段合并。 - 强制地址间隔:在不同权限的段之间加上
. += 4K;,让段地址不连续,避免部分链接器因地址连续而错误合并不同权限的LOAD段。 - 同权限段合并:.bss和.data都是RW权限,绑定到同一个data程序头,这样它们会被合并到同一个RW权限的LOAD段,符合内存权限规划。
修改完成后,你可以用readelf -l <你的二进制文件>查看程序头,应该能看到四个独立的LOAD段,分别对应RX、R、RW、R权限,每个段对应正确的代码/数据段。
内容的提问来源于stack exchange,提问作者Hayden
相关产品推荐
相关产品推荐

