[llvm] 06d0d44 - [COFF] [ARM64] Create symbols with regular intervals for relocations against temporary symbols

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 23 00:39:27 PST 2021


Author: Martin Storsjö
Date: 2021-11-23T10:12:41+02:00
New Revision: 06d0d449d8555ae5f1ac33e8d4bb4ae40eb080d3

URL: https://github.com/llvm/llvm-project/commit/06d0d449d8555ae5f1ac33e8d4bb4ae40eb080d3
DIFF: https://github.com/llvm/llvm-project/commit/06d0d449d8555ae5f1ac33e8d4bb4ae40eb080d3.diff

LOG: [COFF] [ARM64] Create symbols with regular intervals for relocations against temporary symbols

For relocations against temporary symbols (that don't persist in
the object file), we normally adjust them to reference the start of
the section.

For adrp relocations, the immediate offset from the referenced
symbol is stored in the opcode as the 21 bit signed immediate; this
means that the symbol referenced must be within +/- 1 MB from the
referenced symbol.

Create label symbols with regular intervals (1 MB intervals). For
relocations against temporary symbols, pick the preceding added
offset symbol and make the relocation against that instead of
against the start of the section.

This should fix the root issue behind
https://bugs.llvm.org/show_bug.cgi?id=52378.

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

Added: 
    llvm/test/MC/AArch64/coff-relocations-offset.s

Modified: 
    llvm/lib/MC/WinCOFFObjectWriter.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
index 646f416821aea..73c687331d300 100644
--- a/llvm/lib/MC/WinCOFFObjectWriter.cpp
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -56,6 +56,8 @@ using llvm::support::endian::write32le;
 
 namespace {
 
+constexpr int OffsetLabelIntervalBits = 20;
+
 using name = SmallString<COFF::NameSize>;
 
 enum AuxiliaryType {
@@ -120,6 +122,8 @@ class COFFSection {
   relocations Relocations;
 
   COFFSection(StringRef Name) : Name(std::string(Name)) {}
+
+  SmallVector<COFFSymbol *, 1> OffsetSymbols;
 };
 
 class WinCOFFObjectWriter : public MCObjectWriter {
@@ -149,6 +153,7 @@ class WinCOFFObjectWriter : public MCObjectWriter {
   symbol_list WeakDefaults;
 
   bool UseBigObj;
+  bool UseOffsetLabels = false;
 
   bool EmitAddrsigSection = false;
   MCSectionCOFF *AddrsigSection;
@@ -174,7 +179,7 @@ class WinCOFFObjectWriter : public MCObjectWriter {
   COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol *Symbol);
   COFFSection *createSection(StringRef Name);
 
-  void defineSection(MCSectionCOFF const &Sec);
+  void defineSection(MCSectionCOFF const &Sec, const MCAsmLayout &Layout);
 
   COFFSymbol *getLinkedSymbol(const MCSymbol &Symbol);
   void DefineSymbol(const MCSymbol &Symbol, MCAssembler &Assembler,
@@ -244,6 +249,11 @@ WinCOFFObjectWriter::WinCOFFObjectWriter(
     std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
     : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {
   Header.Machine = TargetObjectWriter->getMachine();
+  // Some relocations on ARM64 (the 21 bit ADRP relocations) have a slightly
+  // limited range for the immediate offset (+/- 1 MB); create extra offset
+  // label symbols with regular intervals to allow referencing a
+  // non-temporary symbol that is close enough.
+  UseOffsetLabels = Header.Machine == COFF::IMAGE_FILE_MACHINE_ARM64;
 }
 
 COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) {
@@ -299,7 +309,8 @@ static uint32_t getAlignment(const MCSectionCOFF &Sec) {
 
 /// This function takes a section data object from the assembler
 /// and creates the associated COFF section staging object.
-void WinCOFFObjectWriter::defineSection(const MCSectionCOFF &MCSec) {
+void WinCOFFObjectWriter::defineSection(const MCSectionCOFF &MCSec,
+                                        const MCAsmLayout &Layout) {
   COFFSection *Section = createSection(MCSec.getName());
   COFFSymbol *Symbol = createSymbol(MCSec.getName());
   Section->Symbol = Symbol;
@@ -329,6 +340,20 @@ void WinCOFFObjectWriter::defineSection(const MCSectionCOFF &MCSec) {
   // Bind internal COFF section to MC section.
   Section->MCSection = &MCSec;
   SectionMap[&MCSec] = Section;
+
+  if (UseOffsetLabels && !MCSec.getFragmentList().empty()) {
+    const uint32_t Interval = 1 << OffsetLabelIntervalBits;
+    uint32_t N = 1;
+    for (uint32_t Off = Interval, E = Layout.getSectionAddressSize(&MCSec);
+         Off < E; Off += Interval) {
+      auto Name = ("$L" + MCSec.getName() + "_" + Twine(N++)).str();
+      COFFSymbol *Label = createSymbol(Name);
+      Label->Section = Section;
+      Label->Data.StorageClass = COFF::IMAGE_SYM_CLASS_LABEL;
+      Label->Data.Value = Off;
+      Section->OffsetSymbols.push_back(Label);
+    }
+  }
 }
 
 static uint64_t getSymbolValue(const MCSymbol &Symbol,
@@ -688,7 +713,7 @@ void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
   // "Define" each section & symbol. This creates section & symbol
   // entries in the staging area.
   for (const auto &Section : Asm)
-    defineSection(static_cast<const MCSectionCOFF &>(Section));
+    defineSection(static_cast<const MCSectionCOFF &>(Section), Layout);
 
   for (const MCSymbol &Symbol : Asm.symbols())
     if (!Symbol.isTemporary())
@@ -774,8 +799,23 @@ void WinCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
     assert(
         SectionMap.find(TargetSection) != SectionMap.end() &&
         "Section must already have been defined in executePostLayoutBinding!");
-    Reloc.Symb = SectionMap[TargetSection]->Symbol;
+    COFFSection *Section = SectionMap[TargetSection];
+    Reloc.Symb = Section->Symbol;
     FixedValue += Layout.getSymbolOffset(A);
+    // Technically, we should do the final adjustments of FixedValue (below)
+    // before picking an offset symbol, otherwise we might choose one which
+    // is slightly too far away. The relocations where it really matters
+    // (arm64 adrp relocations) don't get any offset though.
+    if (UseOffsetLabels && !Section->OffsetSymbols.empty()) {
+      uint64_t LabelIndex = FixedValue >> OffsetLabelIntervalBits;
+      if (LabelIndex > 0) {
+        if (LabelIndex <= Section->OffsetSymbols.size())
+          Reloc.Symb = Section->OffsetSymbols[LabelIndex - 1];
+        else
+          Reloc.Symb = Section->OffsetSymbols.back();
+        FixedValue -= Reloc.Symb->Data.Value;
+      }
+    }
   } else {
     assert(
         SymbolMap.find(&A) != SymbolMap.end() &&

diff  --git a/llvm/test/MC/AArch64/coff-relocations-offset.s b/llvm/test/MC/AArch64/coff-relocations-offset.s
new file mode 100644
index 0000000000000..c16b445e9006a
--- /dev/null
+++ b/llvm/test/MC/AArch64/coff-relocations-offset.s
@@ -0,0 +1,49 @@
+// RUN: llvm-mc -triple aarch64-windows -filetype obj -o %t.obj %s
+// RUN: llvm-objdump -d -r %t.obj | FileCheck %s
+// RUN: llvm-readobj --syms %t.obj | FileCheck %s --check-prefix=SYMBOLS
+
+    .text
+main:
+    adrp x0, .Ltmp0
+    adrp x0, .Ltmp1
+    adrp x0, .Ltmp2+8
+
+    .section .rdata
+    .word 1
+.Ltmp0:
+    .word 2
+    .fill 1048576
+.Ltmp1: // 1 MB + 8 bytes
+    .fill (1048576-8-4)
+.Ltmp2: // 2 MB - 4 bytes
+    .word 3
+    // 2 MB here
+    .word 4
+    // .Ltmp2+8 points here
+    .word 5
+
+// CHECK:      0: 20 00 00 90   adrp    x0, 0x4000
+// CHECK-NEXT:          0000000000000000:  IMAGE_REL_ARM64_PAGEBASE_REL21       .rdata
+// CHECK-NEXT: 4: 40 00 00 90   adrp    x0, 0x8000
+// CHECK-NEXT:          0000000000000004:  IMAGE_REL_ARM64_PAGEBASE_REL21       $L.rdata_1
+// CHECK-NEXT: 8: 20 00 00 90   adrp    x0, 0x4000
+// CHECK-NEXT:          0000000000000008:  IMAGE_REL_ARM64_PAGEBASE_REL21       $L.rdata_2
+
+// SYMBOLS:      Symbol {
+// SYMBOLS:        Name: $L.rdata_1
+// SYMBOLS-NEXT:   Value: 1048576
+// SYMBOLS-NEXT:   Section: .rdata (4)
+// SYMBOLS-NEXT:   BaseType: Null (0x0)
+// SYMBOLS-NEXT:   ComplexType: Null (0x0)
+// SYMBOLS-NEXT:   StorageClass: Label (0x6)
+// SYMBOLS-NEXT:   AuxSymbolCount: 0
+// SYMBOLS-NEXT: }
+// SYMBOLS-NEXT: Symbol {
+// SYMBOLS-NEXT:   Name: $L.rdata_2
+// SYMBOLS-NEXT:   Value: 2097152
+// SYMBOLS-NEXT:   Section: .rdata (4)
+// SYMBOLS-NEXT:   BaseType: Null (0x0)
+// SYMBOLS-NEXT:   ComplexType: Null (0x0)
+// SYMBOLS-NEXT:   StorageClass: Label (0x6)
+// SYMBOLS-NEXT:   AuxSymbolCount: 0
+// SYMBOLS-NEXT: }


        


More information about the llvm-commits mailing list