[lld] 8ffb209 - [ELF] Refine LMA offset propagation rule in D76995

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 19 09:12:10 PDT 2020


Author: Fangrui Song
Date: 2020-06-19T09:11:33-07:00
New Revision: 8ffb2097cc1adf5a0f964006a7633ed1ee4f59d3

URL: https://github.com/llvm/llvm-project/commit/8ffb2097cc1adf5a0f964006a7633ed1ee4f59d3
DIFF: https://github.com/llvm/llvm-project/commit/8ffb2097cc1adf5a0f964006a7633ed1ee4f59d3.diff

LOG: [ELF] Refine LMA offset propagation rule in D76995

If neither AT(lma) nor AT>lma_region is specified,
D76995 keeps `lmaOffset` (LMA - VMA) if the previous section is in the
default LMA region.

This patch additionally checks that the two sections are in the same
memory region.

Add a test case derived from https://bugs.llvm.org/show_bug.cgi?id=45313

  .mdata : AT(0xfb01000) { *(.data); } > TCM
  // It is odd to make .bss inherit lmaOffset, because the two sections
  // are in different memory regions.
  .bss : { *(.bss) } > DDR

With this patch, section VMA/LMA match GNU ld. Note, GNU ld supports
out-of-order (w.r.t sh_offset) sections and places .text and .bss in the
same PT_LOAD. We don't have that behavior.

Reviewed By: grimar

Differential Revision: https://reviews.llvm.org/D81986

Added: 
    lld/test/ELF/linkerscript/lma-offset2.s

Modified: 
    lld/ELF/LinkerScript.cpp
    lld/docs/ELF/linker_script.rst

Removed: 
    


################################################################################
diff  --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 5f508cd0d7bd..72e2ebff9b8c 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -851,7 +851,8 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
   if (!(sec->flags & SHF_ALLOC))
     dot = 0;
 
-  bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
+  const bool sameMemRegion = ctx->memRegion == sec->memRegion;
+  const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
   ctx->memRegion = sec->memRegion;
   ctx->lmaRegion = sec->lmaRegion;
   if (ctx->memRegion)
@@ -872,14 +873,15 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
 
   // ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or
   // AT>, recompute ctx->lmaOffset; otherwise, if both previous/current LMA
-  // region is the default, reuse previous lmaOffset; otherwise, reset lmaOffset
-  // to 0. This emulates heuristics described in
+  // region is the default, and the two sections are in the same memory region,
+  // reuse previous lmaOffset; otherwise, reset lmaOffset to 0. This emulates
+  // heuristics described in
   // https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html
   if (sec->lmaExpr)
     ctx->lmaOffset = sec->lmaExpr().getValue() - dot;
   else if (MemoryRegion *mr = sec->lmaRegion)
     ctx->lmaOffset = alignTo(mr->curPos, sec->alignment) - dot;
-  else if (!prevLMARegionIsDefault)
+  else if (!sameMemRegion || !prevLMARegionIsDefault)
     ctx->lmaOffset = 0;
 
   // Propagate ctx->lmaOffset to the first "non-header" section.

diff  --git a/lld/docs/ELF/linker_script.rst b/lld/docs/ELF/linker_script.rst
index c5115c1c9d6f..0f409b2020ac 100644
--- a/lld/docs/ELF/linker_script.rst
+++ b/lld/docs/ELF/linker_script.rst
@@ -71,7 +71,7 @@ The two keywords cannot be specified at the same time.
 
 If neither ``AT(lma)`` nor ``AT>lma_region`` is specified:
 
-- If the previous section is also in the default LMA region, the 
diff erence
-  between the LMA and the VMA is computed to be the same as the previous
-  
diff erence.
+- If the previous section is also in the default LMA region, and the two
+  section have the same memory regions, the 
diff erence between the LMA and the
+  VMA is computed to be the same as the previous 
diff erence.
 - Otherwise, the LMA is set to the VMA.

diff  --git a/lld/test/ELF/linkerscript/lma-offset2.s b/lld/test/ELF/linkerscript/lma-offset2.s
new file mode 100644
index 000000000000..9342739a924e
--- /dev/null
+++ b/lld/test/ELF/linkerscript/lma-offset2.s
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+## If neither AT(lma) nor AT>lma_region is specified, don't propagate
+## lmaOffset if the section and the previous section are in 
diff erent memory
+## regions.
+
+# RUN: echo '.globl _start; _start: ret; \
+# RUN:   .data; .byte 0; \
+# RUN:   .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 -l %t | FileCheck %s
+
+## GNU ld places .text and .bss in the same RWX PT_LOAD.
+# CHECK:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg
+# CHECK-NEXT: LOAD 0x001000 0x000000000fb00000 0x000000000fb00000 0x000001 0x000001 R E
+# CHECK-NEXT: LOAD 0x002000 0x000000001f400000 0x000000000fb01000 0x000001 0x000001 RW
+# CHECK-NEXT: LOAD 0x002001 0x000000000fb00001 0x000000000fb00001 0x000000 0x000001 RW
+
+MEMORY  {
+  DDR : o = 0xfb00000, l = 185M
+  TCM : o = 0x1f400000, l = 128K
+}
+
+SECTIONS {
+  .text : { *(.text) } > DDR
+  .mdata : AT(0xfb01000) { *(.data); } > TCM
+  ## .mdata and .bss are in 
diff erent memory regions. Start a new PT_LOAD for
+  ## .bss, even if .mdata does not set a LMA region.
+  .bss : { *(.bss) } > DDR
+}


        


More information about the llvm-commits mailing list