[lld-macho] Support pc-relative section relocations
Summary: So far we've only supported symbol relocations. Reviewers: ruiu, pcc, MaskRay, smeenai, alexshap, gkm, Ktwu, christylee Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D79211
This commit is contained in:
		
							parent
							
								
									7bbdbacd00
								
							
						
					
					
						commit
						198b0c57df
					
				| 
						 | 
				
			
			@ -134,6 +134,7 @@ InputFile::parseSections(ArrayRef<section_64> sections) {
 | 
			
		|||
  for (const section_64 &sec : sections) {
 | 
			
		||||
    InputSection *isec = make<InputSection>();
 | 
			
		||||
    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<size_t>(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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<Symbol *>()) {
 | 
			
		||||
      if (auto *dylibSymbol = dyn_cast<DylibSymbol>(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<InputSection *>()) {
 | 
			
		||||
      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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,8 @@ public:
 | 
			
		|||
  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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue