diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp --- a/lld/MachO/Arch/X86_64.cpp +++ b/lld/MachO/Arch/X86_64.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -25,7 +26,8 @@ X86_64(); uint64_t getImplicitAddend(const uint8_t *loc, uint8_t type) const override; - void relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const override; + void relocateOne(const InputSection &, const Reloc &, uint8_t *loc, + uint64_t val) const override; void writeStub(uint8_t *buf, const DylibSymbol &) const override; void writeStubHelperHeader(uint8_t *buf) const override; @@ -55,19 +57,47 @@ } } -void X86_64::relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const { - switch (type) { +// Slow! Do not call in any hot path (all error message generation should be on +// cold paths anyway.) +static std::string getErrorLocation(const InputSection &isec, + const Reloc &rel) { + InputFile *file = isec.file; + std::string prefix = + "invalid type " + std::to_string(rel.type) + " relocation at offset "; + + for (const SubsectionMap &subsectionMap : file->subsections) { + for (auto &p : subsectionMap) { + uint32_t subsecOff = p.first; + const InputSection *subsection = p.second; + if (subsection == &isec) + return (prefix + std::to_string(subsecOff + rel.offset) + " of " + + isec.segname + "," + isec.name + " in " + file->getName()) + .str(); + } + } + llvm_unreachable("could not find input section"); +} + +void X86_64::relocateOne(const InputSection &isec, const Reloc &rel, + uint8_t *loc, uint64_t val) const { + switch (rel.type) { case X86_64_RELOC_BRANCH: case X86_64_RELOC_SIGNED: case X86_64_RELOC_SIGNED_1: case X86_64_RELOC_SIGNED_2: case X86_64_RELOC_SIGNED_4: case X86_64_RELOC_GOT_LOAD: + if (!rel.pcrel) + fatal(getErrorLocation(isec, rel) + ": type " + std::to_string(rel.type) + + " relocations must be pcrel"); // These types are only used for pc-relative relocations, so offset by 4 // since the RIP has advanced by 4 at this point. write32le(loc, val - 4); break; case X86_64_RELOC_UNSIGNED: + if (rel.pcrel) + fatal(getErrorLocation(isec, rel) + ": type " + std::to_string(rel.type) + + " relocations must not be pcrel"); write64le(loc, val); break; default: diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -46,6 +46,6 @@ uint64_t val = va + addend; if (r.pcrel) val -= getVA() + r.offset; - target->relocateOne(buf + r.offset, r.type, val); + target->relocateOne(*this, r, buf + r.offset, val); } } diff --git a/lld/MachO/Target.h b/lld/MachO/Target.h --- a/lld/MachO/Target.h +++ b/lld/MachO/Target.h @@ -16,6 +16,8 @@ namespace macho { class DylibSymbol; +class InputSection; +struct Reloc; enum { // We are currently only supporting 64-bit targets since macOS and iOS are @@ -32,7 +34,8 @@ virtual uint64_t getImplicitAddend(const uint8_t *loc, uint8_t type) const = 0; - virtual void relocateOne(uint8_t *loc, uint8_t type, uint64_t val) const = 0; + virtual void relocateOne(const InputSection &, const Reloc &, uint8_t *loc, + uint64_t val) const = 0; // Write code for lazy binding. See the comments on StubsSection for more // details. diff --git a/lld/test/MachO/invalid/invalid-relocation.yaml b/lld/test/MachO/invalid/invalid-relocation.yaml new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid/invalid-relocation.yaml @@ -0,0 +1,99 @@ +# REQUIRES: x86 +# RUN: yaml2obj %s -o %t.o +# RUN: not lld -flavor darwinnew -o %t %t.o 2>&1 | FileCheck %s -DFILE=%t.o +# +# CHECK: error: invalid type 0 relocation at offset 1 of __TEXT,__text in [[FILE]]: type 0 relocations must not be pcrel + +!mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 280 + flags: 0x00000000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: '' + vmaddr: 0 + vmsize: 9 + fileoff: 312 + filesize: 9 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 9 + offset: 0x00000138 + align: 0 + reloff: 0x00000144 + nreloc: 1 + flags: 0x80000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '000000000000000000' + relocations: + - address: 0x00000001 + symbolnum: 1 + pcrel: true + length: 3 + extern: true + type: 0 + scattered: false + value: 0 + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 659200 + sdk: 0 + ntools: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 332 + nsyms: 2 + stroff: 364 + strsize: 12 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 2 + iundefsym: 2 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 1 + - n_strx: 6 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 9 + StringTable: + - '' + - _foo + - _main