[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