diff --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h --- a/lld/MachO/Arch/ARM64Common.h +++ b/lld/MachO/Arch/ARM64Common.h @@ -75,18 +75,26 @@ 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 +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 @@ const macho::Symbol &sym) { auto *buf32 = reinterpret_cast(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 @@ 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 @@ 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/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp --- a/lld/MachO/Arch/ARM64Common.cpp +++ b/lld/MachO/Arch/ARM64Common.cpp @@ -84,7 +84,7 @@ 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 @@ 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(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()); +} + +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/Relocations.h b/lld/MachO/Relocations.h --- a/lld/MachO/Relocations.h +++ b/lld/MachO/Relocations.h @@ -121,6 +121,8 @@ } } +InputSection *offsetToInputSection(uint64_t *); + extern const RelocAttrs invalidRelocAttrs; } // namespace lld::Macho diff --git a/lld/MachO/Relocations.cpp b/lld/MachO/Relocations.cpp --- a/lld/MachO/Relocations.cpp +++ b/lld/MachO/Relocations.cpp @@ -52,7 +52,7 @@ // 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/test/MachO/invalid/arm64-unaligned-load.s b/lld/test/MachO/invalid/arm64-unaligned-load.s new file mode 100644 --- /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@PAGE + ldrh w0, [x0, _half@PAGEOFF] + + adrp x1, _word@PAGE + ldr w1, [x1, _word@PAGEOFF] + + adrp x2, _double@PAGE + ldr x2, [x2, _double@PAGEOFF] + + adrp x3, _quad@PAGE + ldr q0, [x3, _quad@PAGEOFF] + + adrp x4, _byte@PAGE + ldrb w4, [x4, _byte@PAGEOFF] + + adrp x5, _correct@PAGE + ldr x5, [x5, _correct@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 --- a/lld/test/MachO/loh-adrp-ldr.s +++ b/lld/test/MachO/loh-adrp-ldr.s @@ -52,12 +52,6 @@ # CHECK-NEXT: adrp x6 # CHECK-NEXT: ldr x6, #0 -## Target is not aligned to 4 bytes -L13: adrp x7, _after_unaligned@PAGE -L14: ldr x7, [x7, _after_unaligned@PAGEOFF] -# CHECK-NEXT: adrp x7 -# CHECK-NEXT: ldr x7 - ## Byte load, unsupported L15: adrp x8, _after_near@PAGE L16: ldr b8, [x8, _after_near@PAGEOFF] @@ -123,9 +117,7 @@ _after_near: .quad 0 .quad 0 - .byte 0 -_after_unaligned: -.space 1048575 +.space 1048576 _after_far: .quad 0 @@ -136,7 +128,6 @@ .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