From: Daniel Bertalan Date: Sat, 3 Sep 2022 17:21:12 +0000 (+0200) Subject: [lld-macho] Diagnose unaligned arm64 PAGEOFF12 relocations X-Git-Tag: upstream/17.0.6~34376 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1b65d20961d3f7c30fe2fc75aac0e924e902cca3;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp index 27fdf4b..45cf0ea 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(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/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h index 6bd0039..31b4b51 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 +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(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 6f4b00c..9e5ac69 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 04ef420..d0eba46 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 0000000..60e89f3 --- /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 index 46e8e3a..6f32c1f 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@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 @@ L34: ldr x17, [x17, _after_far@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