[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