diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -134,6 +134,7 @@ for (const section_64 &sec : sections) { InputSection *isec = make(); isec->file = this; + isec->header = &sec; isec->name = StringRef(sec.sectname, strnlen(sec.sectname, 16)); isec->segname = StringRef(sec.segname, strnlen(sec.segname, 16)); isec->data = {buf + sec.offset, static_cast(sec.size)}; @@ -165,11 +166,13 @@ r.type = rel.r_type; r.offset = rel.r_address; r.addend = target->getImplicitAddend(buf + sec.offset + r.offset, r.type); - if (rel.r_extern) + if (rel.r_extern) { r.target = symbols[rel.r_symbolnum]; - else { - error("TODO: Non-extern relocations are not supported"); - continue; + } else { + uint32_t sectIdx = rel.r_symbolnum - 1; + if (sectIdx >= sections.size()) + fatal("Relocation section index is greater than number of sections"); + r.target = sections[sectIdx]; } } relocs.push_back(r); diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -46,6 +46,8 @@ StringRef name; StringRef segname; + // This provides access to the address of the section in the input file. + const llvm::MachO::section_64 *header; ArrayRef data; // TODO these properties ought to live in an OutputSection class. diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -30,6 +30,7 @@ for (Reloc &r : relocs) { uint64_t va = 0; + uint64_t addend = r.addend; if (auto *s = r.target.dyn_cast()) { if (auto *dylibSymbol = dyn_cast(s)) { va = target->getDylibSymbolVA(*dylibSymbol, r.type); @@ -38,11 +39,14 @@ } } else if (auto *isec = r.target.dyn_cast()) { va = isec->addr; - } else { - llvm_unreachable("Unknown relocation target"); + // The implicit addend for pcrel section relocations is the pcrel offset + // in terms of the addresses in the input file. Here we adjust it so that + // it describes the offset from the start of the relocated section. + // TODO: Figure out what to do for non-pcrel section relocations. + addend -= isec->header->addr - (r.offset + 4); } - uint64_t val = va + r.addend; + uint64_t val = va + addend; if (1) // TODO: handle non-pcrel relocations val -= addr + r.offset; target->relocateOne(buf + r.offset, r.type, val); diff --git a/lld/test/MachO/relocations.s b/lld/test/MachO/relocations.s --- a/lld/test/MachO/relocations.s +++ b/lld/test/MachO/relocations.s @@ -12,9 +12,12 @@ # CHECK-LABEL: <_main>: ## Test X86_64_RELOC_BRANCH # CHECK: callq 0x[[#%x, F_ADDR]] <_f> -## Test X86_64_RELOC_SIGNED +## Test extern (symbol) X86_64_RELOC_SIGNED # CHECK: leaq [[#%u, STR_OFF:]](%rip), %rsi # CHECK-NEXT: [[#%x, CSTRING_ADDR - STR_OFF]] +## Test non-extern (section) X86_64_RELOC_SIGNED +# CHECK: leaq [[#%u, LSTR_OFF:]](%rip), %rsi +# CHECK-NEXT: [[#%x, CSTRING_ADDR + 22 - LSTR_OFF]] .section __TEXT,__text .globl _main, _f @@ -26,11 +29,21 @@ _f: movl $0x2000004, %eax # write() syscall mov $1, %rdi # stdout - leaq str(%rip), %rsi - mov $13, %rdx # length of str + leaq _str(%rip), %rsi + mov $21, %rdx # length of str + syscall + + movl $0x2000004, %eax # write() syscall + mov $1, %rdi # stdout + leaq L_.str(%rip), %rsi + mov $15, %rdx # length of str syscall ret .section __TEXT,__cstring -str: - .asciz "Hello world!\n" +## References to this generate a symbol relocation +_str: + .asciz "Local defined symbol\n" +## References to this generate a section relocation +L_.str: + .asciz "Private symbol\n"