Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions lld/MachO/Arch/X86_64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ struct X86_64 : TargetInfo {

static constexpr std::array<RelocAttrs, 10> relocAttrsArray{{
#define B(x) RelocAttrBits::x
{"UNSIGNED",
B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4) | B(BYTE8)},
{"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE1) |
B(BYTE4) | B(BYTE8)},
{"SIGNED", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
{"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
{"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE1) | B(BYTE4)},
{"GOT_LOAD", B(PCREL) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},
{"GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},
{"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)},
Expand Down Expand Up @@ -82,25 +82,40 @@ int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
relocation_info rel) const {
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
const uint8_t *loc = buf + offset + rel.r_address;
int64_t addend;

switch (rel.r_length) {
case 0:
addend = static_cast<int8_t>(*loc);
break;
case 2:
return static_cast<int32_t>(read32le(loc)) + pcrelOffset(rel.r_type);
addend = static_cast<int32_t>(read32le(loc));
break;
case 3:
return read64le(loc) + pcrelOffset(rel.r_type);
addend = read64le(loc);
break;
default:
llvm_unreachable("invalid r_length");
}

return addend + pcrelOffset(rel.r_type);
}

void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
uint64_t relocVA) const {
if (r.pcrel) {
uint64_t pc = relocVA + 4 + pcrelOffset(r.type);
uint64_t pc = relocVA + (1 << r.length) + pcrelOffset(r.type);
value -= pc;
}

switch (r.length) {
case 0:
if (r.type == X86_64_RELOC_UNSIGNED)
checkUInt(loc, r, value, 8);
else
checkInt(loc, r, value, 8);
*loc = value;
break;
case 2:
if (r.type == X86_64_RELOC_UNSIGNED)
checkUInt(loc, r, value, 32);
Expand Down
8 changes: 2 additions & 6 deletions lld/MachO/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,8 @@ static bool validateRelocationInfo(InputFile *file, const SectionHeader &sec,
if (isThreadLocalVariables(sec.flags) &&
!relocAttrs.hasAttr(RelocAttrBits::UNSIGNED))
error(message("not allowed in thread-local section, must be UNSIGNED"));
if (rel.r_length < 2 || rel.r_length > 3 ||
!relocAttrs.hasAttr(static_cast<RelocAttrBits>(1 << rel.r_length))) {
static SmallVector<StringRef, 4> widths{"0", "4", "8", "4 or 8"};
error(message("has width " + std::to_string(1 << rel.r_length) +
" bytes, but must be " +
widths[(static_cast<int>(relocAttrs.bits) >> 2) & 3] +
if (!relocAttrs.hasAttr(static_cast<RelocAttrBits>(1 << rel.r_length))) {
error(message("has invalid width of " + std::to_string(1 << rel.r_length) +
" bytes"));
}
return valid;
Expand Down
28 changes: 15 additions & 13 deletions lld/MachO/Relocations.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,23 @@ class InputSection;

enum class RelocAttrBits {
_0 = 0, // invalid
PCREL = 1 << 0, // Value is PC-relative offset
ABSOLUTE = 1 << 1, // Value is an absolute address or fixed offset
BYTE1 = 1 << 0, // 1 byte datum
BYTE2 = 1 << 1, // 2 byte datum
BYTE4 = 1 << 2, // 4 byte datum
BYTE8 = 1 << 3, // 8 byte datum
EXTERN = 1 << 4, // Can have an external symbol
LOCAL = 1 << 5, // Can have a local symbol
ADDEND = 1 << 6, // *_ADDEND paired prefix reloc
SUBTRAHEND = 1 << 7, // *_SUBTRACTOR paired prefix reloc
BRANCH = 1 << 8, // Value is branch target
GOT = 1 << 9, // References a symbol in the Global Offset Table
TLV = 1 << 10, // References a thread-local symbol
LOAD = 1 << 11, // Relaxable indirect load
POINTER = 1 << 12, // Non-relaxable indirect load (pointer is taken)
UNSIGNED = 1 << 13, // *_UNSIGNED relocs
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 14) - 1),
PCREL = 1 << 4, // Value is PC-relative offset
ABSOLUTE = 1 << 5, // Value is an absolute address or fixed offset
EXTERN = 1 << 6, // Can have an external symbol
LOCAL = 1 << 7, // Can have a local symbol
ADDEND = 1 << 8, // *_ADDEND paired prefix reloc
SUBTRAHEND = 1 << 9, // *_SUBTRACTOR paired prefix reloc
BRANCH = 1 << 10, // Value is branch target
GOT = 1 << 11, // References a symbol in the Global Offset Table
TLV = 1 << 12, // References a thread-local symbol
LOAD = 1 << 13, // Relaxable indirect load
POINTER = 1 << 14, // Non-relaxable indirect load (pointer is taken)
UNSIGNED = 1 << 15, // *_UNSIGNED relocs
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ (1 << 16) - 1),
};
// Note: SUBTRACTOR always pairs with UNSIGNED (a delta between two symbols).

Expand Down
2 changes: 1 addition & 1 deletion lld/test/MachO/invalid/invalid-relocation-length.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# RUN: yaml2obj %s -o %t.o
# RUN: not %lld -o %t %t.o 2>&1 | FileCheck %s -DFILE=%t.o
#
# CHECK: error: UNSIGNED relocation has width 2 bytes, but must be 4 or 8 bytes at offset 1 of __TEXT,__text in [[FILE]]
# CHECK: error: UNSIGNED relocation has invalid width of 2 bytes at offset 1 of __TEXT,__text in [[FILE]]

!mach-o
FileHeader:
Expand Down
18 changes: 15 additions & 3 deletions lld/test/MachO/x86-64-relocs.s
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
# CHECK: __data {{[0-9a-z]+}} [[#%x, DATA_ADDR:]]

# CHECK-LABEL: SYMBOL TABLE:
# CHECK: [[#%x, F_ADDR:]] {{.*}} _f
# CHECK-DAG: [[#%x, F_ADDR:]] {{.*}} _f
# CHECK-DAG: [[#%x, G_ADDR:]] {{.*}} _g

# CHECK-LABEL: <_main>:
## Test X86_64_RELOC_BRANCH
# CHECK: callq 0x[[#%x, F_ADDR]] <_f>
# CHECK: jrcxz 0x[[#%x, F_ADDR]] <_f>
# CHECK: callq 0x[[#%x, G_ADDR]] <_g>
# CHECK: jrcxz 0x[[#%x, G_ADDR]] <_g>
## Test extern (symbol) X86_64_RELOC_SIGNED
# CHECK: leaq [[#%u, LOCAL_OFF:]](%rip), %rsi
# CHECK-NEXT: [[#%x, DATA_ADDR - LOCAL_OFF]]
Expand All @@ -24,12 +28,20 @@
# NONPCREL-NEXT: 100001000 08200000 01000000 08200000 01000000

.section __TEXT,__text
.globl _main, _f
.globl _main, _f, _g

_main:
callq _f # X86_64_RELOC_BRANCH
callq _f # X86_64_RELOC_BRANCH with r_length=2
jrcxz _f # X86_64_RELOC_BRANCH with r_length=0
# test negative addends
callq _f - 1
jrcxz _f - 1
mov $0, %rax
ret

_g:
.byte 0x0

_f:
leaq _local(%rip), %rsi # Generates a X86_64_RELOC_SIGNED pcrel symbol relocation
leaq L_.private(%rip), %rsi # Generates a X86_64_RELOC_SIGNED pcrel section relocation
Expand Down