[lld] 6ed8e20 - [ELF] Ignore the maximum of input section alignments for two cases
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 21 08:12:15 PST 2020
Author: Fangrui Song
Date: 2020-02-21T08:12:00-08:00
New Revision: 6ed8e2014330b6a48d238cdc4357e788cdd6d445
URL: https://github.com/llvm/llvm-project/commit/6ed8e2014330b6a48d238cdc4357e788cdd6d445
DIFF: https://github.com/llvm/llvm-project/commit/6ed8e2014330b6a48d238cdc4357e788cdd6d445.diff
LOG: [ELF] Ignore the maximum of input section alignments for two cases
Follow-up for D74286.
Notations:
* alignExpr: the computed ALIGN value
* max_input_align: the maximum of input section alignments
This patch changes the following two cases to match GNU ld:
* When ALIGN is present, GNU ld sets output sh_addr to alignExpr, while lld use max(alignExpr, max_input_align)
* When addrExpr is specified but alignExpr is not, GNU ld sets output sh_addr to addrExpr, while lld uses `advance(0, max_input_align)`
Note, sh_addralign is still set to max(alignExpr, max_input_align).
lma-align.test is enhanced a bit to check we don't overalign sh_addr.
fixSectionAlignments() sets addrExpr but not alignExpr for the `!hasSectionsCommand` case.
This patch sets alignExpr as well so that max_input_align will be respected.
Reviewed By: grimar
Differential Revision: https://reviews.llvm.org/D74736
Added:
lld/test/ELF/linkerscript/section-align2.test
Modified:
lld/ELF/LinkerScript.cpp
lld/ELF/Writer.cpp
lld/test/ELF/linkerscript/lma-align.test
lld/test/ELF/linkerscript/outsections-addr.s
Removed:
################################################################################
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 9643da2e49e8..8cdb8addd2cd 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -761,9 +761,21 @@ void LinkerScript::output(InputSection *s) {
void LinkerScript::switchTo(OutputSection *sec) {
ctx->outSec = sec;
- uint64_t before = advance(0, 1);
- ctx->outSec->addr = advance(0, ctx->outSec->alignment);
- expandMemoryRegions(ctx->outSec->addr - before);
+ uint64_t pos = advance(0, 1);
+ if (sec->addrExpr && !sec->alignExpr) {
+ // The alignment is ignored.
+ ctx->outSec->addr = pos;
+ } else {
+ // If ALIGN is specified, advance sh_addr according to ALIGN and ignore the
+ // maximum of input section alignments.
+ //
+ // When no SECTIONS command is given, sec->alignExpr is set to the maximum
+ // of input section alignments.
+ uint32_t align =
+ sec->alignExpr ? sec->alignExpr().getValue() : ctx->outSec->alignment;
+ ctx->outSec->addr = advance(0, align);
+ expandMemoryRegions(ctx->outSec->addr - pos);
+ }
}
// This function searches for a memory region to place the given output
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index ee681fa4892e..456c4e7d10d3 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -2236,7 +2236,10 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
const PhdrEntry *prev;
auto pageAlign = [&](const PhdrEntry *p) {
OutputSection *cmd = p->firstSec;
- if (cmd && !cmd->addrExpr) {
+ if (!cmd)
+ return;
+ cmd->alignExpr = [align = cmd->alignment]() { return align; };
+ if (!cmd->addrExpr) {
// Prefer advancing to align(dot, maxPageSize) + dot%maxPageSize to avoid
// padding in the file contents.
//
diff --git a/lld/test/ELF/linkerscript/lma-align.test b/lld/test/ELF/linkerscript/lma-align.test
index 3e0e88d4ad1c..0c03f45f3374 100644
--- a/lld/test/ELF/linkerscript/lma-align.test
+++ b/lld/test/ELF/linkerscript/lma-align.test
@@ -1,5 +1,6 @@
# REQUIRES: x86
-# RUN: echo 'ret; .data.rel.ro; .balign 16; .byte 0; .data; .byte 0; .bss; .byte 0' | \
+# RUN: echo '.globl _start; _start: ret; .data.rel.ro; .balign 16; .byte 0; \
+# RUN: .data; .balign 32; .byte 0; .bss; .byte 0' | \
# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t.o
# RUN: ld.lld -T %s %t.o -o %t
# RUN: llvm-readelf -S -l %t | FileCheck %s
@@ -8,13 +9,13 @@
# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK-NEXT: .text PROGBITS 0000000000001000 001000 000001 00 AX 0 0 4
# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000011000 002000 000001 00 WA 0 0 16
-# CHECK-NEXT: .data PROGBITS 0000000000011010 002010 000001 00 WA 0 0 16
+# CHECK-NEXT: .data PROGBITS 0000000000011010 002010 000011 00 WA 0 0 32
# CHECK-NEXT: .bss NOBITS 0000000000011040 002040 000001 00 WA 0 0 64
# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000
# CHECK-NEXT: LOAD 0x002000 0x0000000000011000 0x0000000000001010 0x000001 0x000001 RW 0x1000
-# CHECK-NEXT: LOAD 0x002010 0x0000000000011010 0x0000000000001020 0x000001 0x000001 RW 0x1000
+# CHECK-NEXT: LOAD 0x002010 0x0000000000011010 0x0000000000001020 0x000011 0x000011 RW 0x1000
# CHECK-NEXT: LOAD 0x002040 0x0000000000011040 0x0000000000011040 0x000000 0x000001 RW 0x1000
MEMORY {
diff --git a/lld/test/ELF/linkerscript/outsections-addr.s b/lld/test/ELF/linkerscript/outsections-addr.s
index a56cfc8a842d..0f4586bcf14a 100644
--- a/lld/test/ELF/linkerscript/outsections-addr.s
+++ b/lld/test/ELF/linkerscript/outsections-addr.s
@@ -83,9 +83,9 @@
#CHECK: Flags [
#CHECK: SHF_ALLOC
#CHECK: ]
-#CHECK: Address: 0x5010
-#CHECK: Offset: 0x4010
-#CHECK: Size: 8
+#CHECK: Address: 0x5001
+#CHECK: Offset: 0x4001
+#CHECK: Size: 23
#CHECK: Link: 0
#CHECK: Info: 0
#CHECK: AddressAlignment: 16
diff --git a/lld/test/ELF/linkerscript/section-align2.test b/lld/test/ELF/linkerscript/section-align2.test
new file mode 100644
index 000000000000..9225cddc3a08
--- /dev/null
+++ b/lld/test/ELF/linkerscript/section-align2.test
@@ -0,0 +1,30 @@
+# REQUIRES: aarch64
+## Test ALIGN and its interaction with explicit output section addresses.
+
+# RUN: echo '.globl _start; _start: ret; .data.rel.ro; .balign 8; .byte 0; .data; .byte 0; \
+# RUN: .section .data2,"aw"; .balign 8; .byte 0; .bss; .balign 32; .byte 0' | \
+# RUN: llvm-mc -filetype=obj -triple=aarch64 - -o %t.o
+# RUN: ld.lld -T %s %t.o -o %t 2>&1 | count 0
+# RUN: llvm-readelf -S %t | FileCheck %s
+
+# CHECK: Name Type Address Off Size ES Flg Lk Inf Al
+# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
+# CHECK-NEXT: .text PROGBITS 0000000000010000 010000 000004 00 AX 0 0 4
+# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000010010 010010 000001 00 WA 0 0 16
+# CHECK-NEXT: .data PROGBITS 0000000000020000 020000 000001 00 WA 0 0 1
+# CHECK-NEXT: .data2 PROGBITS 0000000000020001 020001 000008 00 WA 0 0 8
+# CHECK-NEXT: .bss NOBITS 0000000000020010 020009 000011 00 WA 0 0 32
+
+SECTIONS {
+ .text 0x10000 : { *(.text) }
+ ## sh_addr is aligned to 16.
+ .data.rel.ro . : ALIGN(16) { *(.data.rel.ro) }
+
+ .data 0x20000 : { *(.data) }
+ ## The output section address is set without ALIGN. sh_addr is set to Dot, ignoring alignment.
+ ## sh_addralign is the maximum of input section alignments, 8.
+ .data2 . : { *(.data2) }
+ ## sh_addr is aligned to 16.
+ ## The input section has a larger alignment and is thus preceded by a gap.
+ .bss . : ALIGN(16) { *(.bss) }
+}
More information about the llvm-commits
mailing list