[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