[lld] 1b65d20 - [lld-macho] Diagnose unaligned arm64 PAGEOFF12 relocations

Daniel Bertalan via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 5 08:00:37 PDT 2022


Author: Daniel Bertalan
Date: 2022-09-05T16:58:51+02:00
New Revision: 1b65d20961d3f7c30fe2fc75aac0e924e902cca3

URL: https://github.com/llvm/llvm-project/commit/1b65d20961d3f7c30fe2fc75aac0e924e902cca3
DIFF: https://github.com/llvm/llvm-project/commit/1b65d20961d3f7c30fe2fc75aac0e924e902cca3.diff

LOG: [lld-macho] Diagnose unaligned arm64 PAGEOFF12 relocations

The LDR and STR instructions store their immediate offsets as a multiple
of the load/store's size. Therefore, if the target address is not
aligned, the relocation is not representable. We now emit an error if
that happens, similarly to ld64.

This commit removes a test case from loh-adrp-ldr.s that contained an
unaligned LDR.

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

Added: 
    lld/test/MachO/invalid/arm64-unaligned-load.s

Modified: 
    lld/MachO/Arch/ARM64Common.cpp
    lld/MachO/Arch/ARM64Common.h
    lld/MachO/Relocations.cpp
    lld/MachO/Relocations.h
    lld/test/MachO/loh-adrp-ldr.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp
index 27fdf4ba14d93..45cf0eac3c47c 100644
--- a/lld/MachO/Arch/ARM64Common.cpp
+++ b/lld/MachO/Arch/ARM64Common.cpp
@@ -84,7 +84,7 @@ void ARM64Common::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
   case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
   case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
     assert(!r.pcrel);
-    encodePageOff12(loc32, base, value);
+    encodePageOff12(loc32, r, base, value);
     break;
   default:
     llvm_unreachable("unexpected relocation type");
@@ -127,3 +127,26 @@ void ARM64Common::handleDtraceReloc(const Symbol *sym, const Reloc &r,
     error("Unrecognized dtrace symbol prefix: " + toString(*sym));
   }
 }
+
+static void reportUnalignedLdrStr(Twine loc, uint64_t va, int align,
+                                  const Symbol *sym) {
+  std::string symbolHint;
+  if (sym)
+    symbolHint = " (" + toString(*sym) + ")";
+  error(loc + ": " + Twine(8 * align) + "-bit LDR/STR to 0x" +
+        llvm::utohexstr(va) + symbolHint + " is not " + Twine(align) +
+        "-byte aligned");
+}
+
+void macho::reportUnalignedLdrStr(void *loc, const lld::macho::Reloc &r,
+                                  uint64_t va, int align) {
+  uint64_t off = reinterpret_cast<const uint8_t *>(loc) - in.bufferStart;
+  const InputSection *isec = offsetToInputSection(&off);
+  std::string locStr = isec ? isec->getLocation(off) : "(invalid location)";
+  ::reportUnalignedLdrStr(locStr, va, align, r.referent.dyn_cast<Symbol *>());
+}
+
+void macho::reportUnalignedLdrStr(void *loc, lld::macho::SymbolDiagnostic d,
+                                  uint64_t va, int align) {
+  ::reportUnalignedLdrStr(d.reason, va, align, d.symbol);
+}

diff  --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h
index 6bd0039bd9f4b..31b4b5176fdeb 100644
--- a/lld/MachO/Arch/ARM64Common.h
+++ b/lld/MachO/Arch/ARM64Common.h
@@ -75,18 +75,26 @@ inline void encodePage21(uint32_t *loc, SymbolDiagnostic d, uint32_t base,
                                             bitField(va, 14, 19, 5));
 }
 
+void reportUnalignedLdrStr(void *loc, const Reloc &, uint64_t va, int align);
+void reportUnalignedLdrStr(void *loc, SymbolDiagnostic, uint64_t va, int align);
+
 //                      21                   10
 // +-------------------+-----------------------+-------------------+
 // |                   |         imm12         |                   |
 // +-------------------+-----------------------+-------------------+
 
-inline void encodePageOff12(uint32_t *loc, uint32_t base, uint64_t va) {
+template <typename Target>
+inline void encodePageOff12(uint32_t *loc, Target t, uint32_t base,
+                            uint64_t va) {
   int scale = 0;
   if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store
     scale = base >> 30;
     if (scale == 0 && (base & 0x0480'0000) == 0x0480'0000) // 128-bit variant
       scale = 4;
   }
+  const int size = 1 << scale;
+  if ((va & (size - 1)) != 0)
+    reportUnalignedLdrStr(loc, t, va, size);
 
   // TODO(gkm): extract embedded addend and warn if != 0
   // uint64_t addend = ((base & 0x003FFC00) >> 10);
@@ -104,13 +112,13 @@ inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3],
                       const macho::Symbol &sym) {
   auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
   constexpr size_t stubCodeSize = 3 * sizeof(uint32_t);
+  SymbolDiagnostic d = {&sym, "stub"};
   uint64_t pcPageBits =
       pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize);
   uint64_t lazyPointerVA =
       in.lazyPointers->addr + sym.stubsIndex * LP::wordSize;
-  encodePage21(&buf32[0], {&sym, "stub"}, stubCode[0],
-               pageBits(lazyPointerVA) - pcPageBits);
-  encodePageOff12(&buf32[1], stubCode[1], lazyPointerVA);
+  encodePage21(&buf32[0], d, stubCode[0], pageBits(lazyPointerVA) - pcPageBits);
+  encodePageOff12(&buf32[1], d, stubCode[1], lazyPointerVA);
   buf32[2] = stubCode[2];
 }
 
@@ -125,13 +133,13 @@ inline void writeStubHelperHeader(uint8_t *buf8,
   SymbolDiagnostic d = {nullptr, "stub header helper"};
   encodePage21(&buf32[0], d, stubHelperHeaderCode[0],
                pageBits(loaderVA) - pcPageBits(0));
-  encodePageOff12(&buf32[1], stubHelperHeaderCode[1], loaderVA);
+  encodePageOff12(&buf32[1], d, stubHelperHeaderCode[1], loaderVA);
   buf32[2] = stubHelperHeaderCode[2];
   uint64_t binderVA =
       in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize;
   encodePage21(&buf32[3], d, stubHelperHeaderCode[3],
                pageBits(binderVA) - pcPageBits(3));
-  encodePageOff12(&buf32[4], stubHelperHeaderCode[4], binderVA);
+  encodePageOff12(&buf32[4], d, stubHelperHeaderCode[4], binderVA);
   buf32[5] = stubHelperHeaderCode[5];
 }
 
@@ -163,7 +171,8 @@ writeObjCMsgSendStub(uint8_t *buf, const uint32_t objcStubsFastCode[8],
   uint64_t selectorOffset = selectorIndex * LP::wordSize;
   encodePage21(&buf32[0], d, objcStubsFastCode[0],
                pageBits(selrefsVA + selectorOffset) - pcPageBits(0));
-  encodePageOff12(&buf32[1], objcStubsFastCode[1], selrefsVA + selectorOffset);
+  encodePageOff12(&buf32[1], d, objcStubsFastCode[1],
+                  selrefsVA + selectorOffset);
   encodePage21(&buf32[2], d, objcStubsFastCode[2],
                pageBits(gotAddr) - pcPageBits(2));
   encodePage21(&buf32[3], d, objcStubsFastCode[3], msgSendIndex * LP::wordSize);

diff  --git a/lld/MachO/Relocations.cpp b/lld/MachO/Relocations.cpp
index 6f4b00c7acf91..9e5ac69612cfd 100644
--- a/lld/MachO/Relocations.cpp
+++ b/lld/MachO/Relocations.cpp
@@ -52,7 +52,7 @@ bool macho::validateSymbolRelocation(const Symbol *sym,
 // This is implemented as a slow linear search through OutputSegments,
 // OutputSections, and finally the InputSections themselves. However, this
 // function should be called only on error paths, so some overhead is fine.
-static InputSection *offsetToInputSection(uint64_t *off) {
+InputSection *macho::offsetToInputSection(uint64_t *off) {
   for (OutputSegment *seg : outputSegments) {
     if (*off < seg->fileOff || *off >= seg->fileOff + seg->fileSize)
       continue;

diff  --git a/lld/MachO/Relocations.h b/lld/MachO/Relocations.h
index 04ef42035768a..d0eba4643bd07 100644
--- a/lld/MachO/Relocations.h
+++ b/lld/MachO/Relocations.h
@@ -121,6 +121,8 @@ inline void writeAddress(uint8_t *loc, uint64_t addr, uint8_t length) {
   }
 }
 
+InputSection *offsetToInputSection(uint64_t *);
+
 extern const RelocAttrs invalidRelocAttrs;
 
 } // namespace lld::Macho

diff  --git a/lld/test/MachO/invalid/arm64-unaligned-load.s b/lld/test/MachO/invalid/arm64-unaligned-load.s
new file mode 100644
index 0000000000000..60e89f3447525
--- /dev/null
+++ b/lld/test/MachO/invalid/arm64-unaligned-load.s
@@ -0,0 +1,46 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
+# RUN: not %lld -arch arm64 %t.o -o %t 2>&1 | FileCheck %s --implicit-check-not=_byte \
+# RUN:   --implicit-check-not=_correct
+
+# CHECK-DAG: error: {{.*}}:(symbol _main+0x4): 16-bit LDR/STR to 0x[[#%X,]] (_half) is not 2-byte aligned
+# CHECK-DAG: error: {{.*}}:(symbol _main+0xc): 32-bit LDR/STR to 0x[[#%X,]] (_word) is not 4-byte aligned
+# CHECK-DAG: error: {{.*}}:(symbol _main+0x14): 64-bit LDR/STR to 0x[[#%X,]] (_double) is not 8-byte aligned
+# CHECK-DAG: error: {{.*}}:(symbol _main+0x1c): 128-bit LDR/STR to 0x[[#%X,]] (_quad) is not 16-byte aligned
+
+.globl _main
+_main:
+  adrp x0, _half at PAGE
+  ldrh w0, [x0, _half at PAGEOFF]
+
+  adrp x1, _word at PAGE
+  ldr  w1, [x1, _word at PAGEOFF]
+
+  adrp x2, _double at PAGE
+  ldr  x2, [x2, _double at PAGEOFF]
+
+  adrp x3, _quad at PAGE
+  ldr  q0, [x3, _quad at PAGEOFF]
+
+  adrp x4, _byte at PAGE
+  ldrb w4, [x4, _byte at PAGEOFF]
+
+  adrp x5, _correct at PAGE
+  ldr  x5, [x5, _correct at PAGEOFF]
+
+.data
+.p2align 4
+_correct:
+.8byte 0
+.byte 0
+_half:
+.2byte 0
+_word:
+.4byte 0
+_double:
+.8byte 0
+_quad:
+.8byte 0
+.8byte 0
+_byte:
+.byte 0

diff  --git a/lld/test/MachO/loh-adrp-ldr.s b/lld/test/MachO/loh-adrp-ldr.s
index 46e8e3a9d55e5..6f32c1f910326 100644
--- a/lld/test/MachO/loh-adrp-ldr.s
+++ b/lld/test/MachO/loh-adrp-ldr.s
@@ -52,12 +52,6 @@ L12: ldr   x6, 0
 # CHECK-NEXT: adrp x6
 # CHECK-NEXT: ldr x6, #0
 
-## Target is not aligned to 4 bytes
-L13: adrp  x7, _after_unaligned at PAGE
-L14: ldr   x7, [x7, _after_unaligned at PAGEOFF]
-# CHECK-NEXT: adrp x7
-# CHECK-NEXT: ldr x7
-
 ## Byte load, unsupported
 L15: adrp  x8, _after_near at PAGE
 L16: ldr   b8, [x8, _after_near at PAGEOFF]
@@ -123,9 +117,7 @@ L34: ldr   x17, [x17, _after_far at PAGEOFF]
 _after_near:
   .quad 0
   .quad 0
-  .byte 0
-_after_unaligned:
-.space 1048575
+.space 1048576
 
 _after_far:
   .quad 0
@@ -136,7 +128,6 @@ _after_far:
 .loh AdrpLdr L7, L8
 .loh AdrpLdr L9, L10
 .loh AdrpLdr L11, L12
-.loh AdrpLdr L13, L14
 .loh AdrpLdr L15, L16
 .loh AdrpLdr L17, L18
 .loh AdrpLdr L19, L20


        


More information about the llvm-commits mailing list