diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp index f8fdd76ff50f4..e836f4d799623 100644 --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -134,6 +134,7 @@ InputFile::parseSections(ArrayRef sections) { 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,14 @@ void InputFile::parseRelocations(const section_64 &sec, 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 { + if (rel.r_symbolnum == 0 || rel.r_symbolnum > sections.size()) + fatal("invalid section index in relocation for offset " + + std::to_string(r.offset) + " in section " + sec.sectname + + " of " + getName()); + r.target = sections[rel.r_symbolnum - 1]; } } relocs.push_back(r); diff --git a/lld/MachO/InputSection.cpp b/lld/MachO/InputSection.cpp index cfc6050cb90c7..ace30c8c41dce 100644 --- a/lld/MachO/InputSection.cpp +++ b/lld/MachO/InputSection.cpp @@ -32,6 +32,7 @@ void InputSection::writeTo(uint8_t *buf) { 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); @@ -40,11 +41,15 @@ void InputSection::writeTo(uint8_t *buf) { } } else if (auto *isec = r.target.dyn_cast()) { va = isec->getVA(); - } 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 target section. + // TODO: Figure out what to do for non-pcrel section relocations. + // TODO: The offset of 4 is probably not right for ARM64. + addend -= isec->header->addr - (header->addr + r.offset + 4); } - uint64_t val = va + r.addend; + uint64_t val = va + addend; if (1) // TODO: handle non-pcrel relocations val -= getVA() + r.offset; target->relocateOne(buf + r.offset, r.type, val); diff --git a/lld/MachO/InputSection.h b/lld/MachO/InputSection.h index a945b79ad3a0d..908f09e6d29dd 100644 --- a/lld/MachO/InputSection.h +++ b/lld/MachO/InputSection.h @@ -42,6 +42,8 @@ class InputSection { InputFile *file = nullptr; StringRef name; StringRef segname; + // This provides access to the address of the section in the input file. + const llvm::MachO::section_64 *header; OutputSection *parent = nullptr; uint64_t outSecOff = 0; diff --git a/lld/test/MachO/relocations.s b/lld/test/MachO/relocations.s index 7f41a6c93283f..b1c828d4d4698 100644 --- 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 @@ _main: _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" diff --git a/lld/test/MachO/x86-64-reloc-signed.s b/lld/test/MachO/x86-64-reloc-signed.s index 9ff91567d7641..079ea7d1e96ff 100644 --- a/lld/test/MachO/x86-64-reloc-signed.s +++ b/lld/test/MachO/x86-64-reloc-signed.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o # RUN: lld -flavor darwinnew -o %t %t.o -# RUN: llvm-objdump -d %t | FileCheck %s +# RUN: llvm-objdump -D %t | FileCheck %s # CHECK: <_main>: # CHECK-NEXT: movl {{.*}} # 2000 <_s> @@ -10,10 +10,18 @@ # CHECK-NEXT: callq {{.*}} # CHECK-NEXT: movb {{.*}} # 2000 <_s> # CHECK-NEXT: callq {{.*}} +# CHECK: <__not_text>: +# CHECK-NEXT: movl {{.*}} # 2005 +# CHECK-NEXT: callq {{.*}} +# CHECK-NEXT: movl {{.*}} # 2007 +# CHECK-NEXT: callq {{.*}} +# CHECK-NEXT: movb {{.*}} # 2005 +# CHECK-NEXT: callq {{.*}} .section __TEXT,__text .globl _main _main: + ## Symbol relocations movl $0x434241, _s(%rip) # X86_64_RELOC_SIGNED_4 callq _f movl $0x44, _s+2(%rip) # X86_64_RELOC_SIGNED_2 @@ -31,7 +39,26 @@ _f: syscall ret +.section __TEXT,__not_text + ## Section relocations. We intentionally put them in a separate section since + ## the __text section typically starts at an address of zero in object files, + ## and so does not fully exercise the relocation logic. + movl $0x434241, L._s(%rip) # X86_64_RELOC_SIGNED_4 + callq _f + movl $0x44, L._s+2(%rip) # X86_64_RELOC_SIGNED_2 + callq _f + movb $0x45, L._s(%rip) # X86_64_RELOC_SIGNED_1 + callq _f + ret + .section __DATA,__data .globl _s _s: .space 5 + +## Create a new section to force the assembler to use a section relocation for +## the private symbol L._s. Otherwise, it will instead use a nearby non-private +## symbol to create a symbol relocation plus an addend. +.section __DATA,__foo +L._s: + .space 5