[llvm-dev] How LLD should create segments when linkerscript is used ?

George Rimar via llvm-dev llvm-dev at lists.llvm.org
Fri Aug 12 10:24:33 PDT 2016


I wonder what is correct way to create PT_LOADs when linkerscript is used ?
Currently we create new one for each section that changes access flags. But ld seems to do different thing.

Imagine we have next sections:
.section .AX.1,"ax"
.quad 1
.section .A.1,"a"
.quad 2
.section .AW.1,"aw"
.quad 3

And script:
SECTIONS { 
. = ALIGN(CONSTANT (MAXPAGESIZE));
.AX : { *(.AX.*) }
. = ALIGN(CONSTANT (MAXPAGESIZE));
.A : { *(.A.*) }
. = ALIGN(CONSTANT (MAXPAGESIZE));
.AW : { *(.AW.*) }
}

ld creates 2 segments here:
  LOAD           0x0000000000200000 0x0000000000000000 0x0000000000000000
                 0x0000000000200008 0x0000000000200008  R E    200000
  LOAD           0x0000000000600000 0x0000000000400000 0x0000000000400000
                 0x0000000000000008 0x0000000000000008  RW     200000
 Section to Segment mapping:
  Segment Sections...
   00     .AX .text .A 
   01     .AW 

And if I change script in the next way:
SECTIONS { 
. = ALIGN(CONSTANT (MAXPAGESIZE));
.AX : { *(.AX.*) }
. = ALIGN(CONSTANT (MAXPAGESIZE));
.A : { *(.A.*) }
.AW : { *(.AW.*) }
}

It will create single segment, combining access attributes:
 LOAD           0x0000000000200000 0x0000000000000000 0x0000000000000000
                 0x0000000000200010 0x0000000000200010  RWE    200000

So looks like its behavior is to combine all sections before writable ones to single segment
and create writable segment for others if possible, but if not it will create single segment for everything.
I think FreeBSD script relies on this behavior. When linking with ld It has 2 PT_LOADS (RE + RW) when LLD creates 4 (R RE R RW),
and since we do not align sections to the page boundary manually or in script, it will not work I think.

Below is lld output of FreeBSD kernel (notice that RE and R loads are not aligned):
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0xffffffff80001040 0xffffffff80001040
                 0x00000000000001f8 0x00000000000001f8  R      8
  INTERP         0x0000000000000238 0xffffffff80001238 0xffffffff80001238
                 0x000000000000000d 0x000000000000000d  R      1
      [Requesting program interpreter: /red/herring]
  LOAD           0x0000000000000000 0xffffffff80001000 0xffffffff80001000
                 0x00000000000e410e 0x00000000000e410e  R      1000
  LOAD           0x00000000000e4110 0xffffffff800e5110 0xffffffff800e5110
                 0x0000000000ba2b0c 0x0000000000ba2b0c  R E    1000
  LOAD           0x0000000000c86c20 0xffffffff80c87c20 0xffffffff80c87c20
                 0x000000000038ab28 0x000000000038ab28  R      1000
  LOAD           0x0000000001012000 0xffffffff81013000 0xffffffff81013000
                 0x000000000012ae30 0x0000000000331e30  RW     1000
  DYNAMIC        0x0000000001012000 0xffffffff81013000 0xffffffff81013000
                 0x0000000000000080 0x0000000000000080  RW     8
  GNU_RELRO      0x0000000001012000 0xffffffff81013000 0xffffffff81013000
                 0x0000000000000080 0x0000000000000080  R      1
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0

ld output of the same:
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0xffffffff80200040 0xffffffff80200040
                 0x0000000000000150 0x0000000000000150  R E    8
  INTERP         0x0000000000000190 0xffffffff80200190 0xffffffff80200190
                 0x000000000000000d 0x000000000000000d  R      1
      [Requesting program interpreter: /red/herring]
  LOAD           0x0000000000000000 0xffffffff80200000 0xffffffff80200000
                 0x0000000000fe2de8 0x0000000000fe2de8  R E    200000
  LOAD           0x0000000000fe3000 0xffffffff813e3000 0xffffffff813e3000
                 0x0000000000129430 0x00000000003313c0  RW     200000
  DYNAMIC        0x0000000000fe3000 0xffffffff813e3000 0xffffffff813e3000
                 0x00000000000000d0 0x00000000000000d0  RW     8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RWE    8


So see next possible solutions:
1) Align first sections of each segment to the page boundary like we do for non-script case.
2) Implement the described ld behavior.

Thoughts ?




More information about the llvm-dev mailing list