ld 创建具有错误权限的 elf 段

jos*_*ecm 5 linker elf ld

我正在编写一个裸机 aarch64 程序(工具链 aarch64-unknown-elf-),我使用以下链接器脚本构建该程序:

SECTIONS {
    .text :  {
        *(.text*)
    }

    .rodata ALIGN(CONSTANT(COMMONPAGESIZE)) :  {
        *(.rodata*)
    }

    .data ALIGN(CONSTANT(COMMONPAGESIZE)) : {
        *(.data .data.*)
    }

    .bss (NOLOAD) :  {  
        __bss_start = .;
        *(.bss*) 
        *(COMMON)   
        __bss_end = .;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 readelf 分析最终的可执行文件,我得到以下部分和段(即程序头):

There are 19 section headers, starting at offset 0xa4f58:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000000000 010000 00f600 00  AX  0   0 2048
  [ 2] .rodata           PROGBITS        0000000000010000 020000 0079f9 00   A  0   0 4096
  [ 3] .data             PROGBITS        0000000000018000 028000 001160 00  WA  0   0  8
  [ 4] .bss              NOBITS          0000000000019160 029160 002320 00  WA  0   0  8
  [ 5] .debug_info       PROGBITS        0000000000000000 029160 02d080 00      0   0  1
  [ 6] .debug_abbrev     PROGBITS        0000000000000000 0561e0 009f28 00      0   0  1
  [ 7] .debug_loclists   PROGBITS        0000000000000000 060108 016841 00      0   0  1
  [ 8] .debug_aranges    PROGBITS        0000000000000000 076950 0013c0 00      0   0 16
  [ 9] .debug_macro      PROGBITS        0000000000000000 077d10 003b67 00      0   0  1
  [10] .debug_line       PROGBITS        0000000000000000 07b877 00f6be 00      0   0  1
  [11] .debug_str        PROGBITS        0000000000000000 08af35 00eaeb 01  MS  0   0  1
  [12] .debug_line_str   PROGBITS        0000000000000000 099a20 0027db 01  MS  0   0  1
  [13] .comment          PROGBITS        0000000000000000 09c1fb 000057 01  MS  0   0  1
  [14] .debug_frame      PROGBITS        0000000000000000 09c258 002a40 00      0   0  8
  [15] .debug_rnglists   PROGBITS        0000000000000000 09ec98 0016a0 00      0   0  1
  [16] .symtab           SYMTAB          0000000000000000 0a0338 003a80 18     17 372  8
  [17] .strtab           STRTAB          0000000000000000 0a3db8 0010d5 00      0   0  1
  [18] .shstrtab         STRTAB          0000000000000000 0a4e8d 0000c7 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x0
There is 1 program header, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x010000 0x0000000000000000 0x0000000000000000 0x019160 0x01b480 RWE 0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata .data .bss 
Run Code Online (Sandbox Code Playgroud)

我的问题是,链接器正在将具有不同权限的部分合并到具有所有权限的单个段中,即使我保证数据部分位于单独的页面中(通过相应地对齐它们)。

我使用大页(2MiB)尝试了不同大小的数据部分对齐。在这里,我已经获得了具有正确权限的三个段:

There are 19 section headers, starting at offset 0xacf58:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000000000 010000 00f600 00  AX  0   0 2048
  [ 2] .rodata           PROGBITS        0000000000200000 020000 0079f9 00   A  0   0 4096
  [ 3] .data             PROGBITS        0000000000400000 030000 001160 00  WA  0   0  8
  [ 4] .bss              NOBITS          0000000000401160 031160 002320 00  WA  0   0  8
  [ 5] .debug_info       PROGBITS        0000000000000000 031160 02d080 00      0   0  1
  [ 6] .debug_abbrev     PROGBITS        0000000000000000 05e1e0 009f28 00      0   0  1
  [ 7] .debug_loclists   PROGBITS        0000000000000000 068108 016841 00      0   0  1
  [ 8] .debug_aranges    PROGBITS        0000000000000000 07e950 0013c0 00      0   0 16
  [ 9] .debug_macro      PROGBITS        0000000000000000 07fd10 003b67 00      0   0  1
  [10] .debug_line       PROGBITS        0000000000000000 083877 00f6be 00      0   0  1
  [11] .debug_str        PROGBITS        0000000000000000 092f35 00eaeb 01  MS  0   0  1
  [12] .debug_line_str   PROGBITS        0000000000000000 0a1a20 0027db 01  MS  0   0  1
  [13] .comment          PROGBITS        0000000000000000 0a41fb 000057 01  MS  0   0  1
  [14] .debug_frame      PROGBITS        0000000000000000 0a4258 002a40 00      0   0  8
  [15] .debug_rnglists   PROGBITS        0000000000000000 0a6c98 0016a0 00      0   0  1
  [16] .symtab           SYMTAB          0000000000000000 0a8338 003a80 18     17 372  8
  [17] .strtab           STRTAB          0000000000000000 0abdb8 0010d5 00      0   0  1
  [18] .shstrtab         STRTAB          0000000000000000 0ace8d 0000c7 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x0
There are 3 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  LOAD           0x010000 0x0000000000000000 0x0000000000000000 0x00f600 0x00f600 R E 0x10000
  LOAD           0x020000 0x0000000000200000 0x0000000000200000 0x0079f9 0x0079f9 R   0x10000
  LOAD           0x030000 0x0000000000400000 0x0000000000400000 0x001160 0x003480 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .rodata 
   02     .data .bss 
Run Code Online (Sandbox Code Playgroud)

我的主要问题是 ld 决定何时创建不同部分的规则或启发法是什么?我的想法是保护的粒度(即页面大小)和权限,但也许我错了。我试图深入研究一下代码,但它有点超出了我的理解范围。加载器不就是利用段信息来加载和设置权限的吗?如果是这样,这可能会导致设置错误的权限(在页表或其他内容中)。