Skip to content

Commit 86f7a56

Browse files
int3dvbuka
authored andcommitted
[lld][macho] Support 1-byte branch relocs for x86_64 (llvm#164439)
1 parent bf08836 commit 86f7a56

File tree

5 files changed

+54
-29
lines changed

5 files changed

+54
-29
lines changed

lld/MachO/Arch/X86_64.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ struct X86_64 : TargetInfo {
5151

5252
static constexpr std::array<RelocAttrs, 10> relocAttrsArray{{
5353
#define B(x) RelocAttrBits::x
54-
{"UNSIGNED",
55-
B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE4) | B(BYTE8)},
54+
{"UNSIGNED", B(UNSIGNED) | B(ABSOLUTE) | B(EXTERN) | B(LOCAL) | B(BYTE1) |
55+
B(BYTE4) | B(BYTE8)},
5656
{"SIGNED", B(PCREL) | B(EXTERN) | B(LOCAL) | B(BYTE4)},
57-
{"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE4)},
57+
{"BRANCH", B(PCREL) | B(EXTERN) | B(BRANCH) | B(BYTE1) | B(BYTE4)},
5858
{"GOT_LOAD", B(PCREL) | B(EXTERN) | B(GOT) | B(LOAD) | B(BYTE4)},
5959
{"GOT", B(PCREL) | B(EXTERN) | B(GOT) | B(POINTER) | B(BYTE4)},
6060
{"SUBTRACTOR", B(SUBTRAHEND) | B(EXTERN) | B(BYTE4) | B(BYTE8)},
@@ -82,25 +82,40 @@ int64_t X86_64::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
8282
relocation_info rel) const {
8383
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
8484
const uint8_t *loc = buf + offset + rel.r_address;
85+
int64_t addend;
8586

8687
switch (rel.r_length) {
88+
case 0:
89+
addend = static_cast<int8_t>(*loc);
90+
break;
8791
case 2:
88-
return static_cast<int32_t>(read32le(loc)) + pcrelOffset(rel.r_type);
92+
addend = static_cast<int32_t>(read32le(loc));
93+
break;
8994
case 3:
90-
return read64le(loc) + pcrelOffset(rel.r_type);
95+
addend = read64le(loc);
96+
break;
9197
default:
9298
llvm_unreachable("invalid r_length");
9399
}
100+
101+
return addend + pcrelOffset(rel.r_type);
94102
}
95103

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

103111
switch (r.length) {
112+
case 0:
113+
if (r.type == X86_64_RELOC_UNSIGNED)
114+
checkUInt(loc, r, value, 8);
115+
else
116+
checkInt(loc, r, value, 8);
117+
*loc = value;
118+
break;
104119
case 2:
105120
if (r.type == X86_64_RELOC_UNSIGNED)
106121
checkUInt(loc, r, value, 32);

lld/MachO/InputFiles.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,8 @@ static bool validateRelocationInfo(InputFile *file, const SectionHeader &sec,
516516
if (isThreadLocalVariables(sec.flags) &&
517517
!relocAttrs.hasAttr(RelocAttrBits::UNSIGNED))
518518
error(message("not allowed in thread-local section, must be UNSIGNED"));
519-
if (rel.r_length < 2 || rel.r_length > 3 ||
520-
!relocAttrs.hasAttr(static_cast<RelocAttrBits>(1 << rel.r_length))) {
521-
static SmallVector<StringRef, 4> widths{"0", "4", "8", "4 or 8"};
522-
error(message("has width " + std::to_string(1 << rel.r_length) +
523-
" bytes, but must be " +
524-
widths[(static_cast<int>(relocAttrs.bits) >> 2) & 3] +
519+
if (!relocAttrs.hasAttr(static_cast<RelocAttrBits>(1 << rel.r_length))) {
520+
error(message("has invalid width of " + std::to_string(1 << rel.r_length) +
525521
" bytes"));
526522
}
527523
return valid;

lld/MachO/Relocations.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,23 @@ class InputSection;
2525

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

lld/test/MachO/invalid/invalid-relocation-length.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# RUN: yaml2obj %s -o %t.o
33
# RUN: not %lld -o %t %t.o 2>&1 | FileCheck %s -DFILE=%t.o
44
#
5-
# CHECK: error: UNSIGNED relocation has width 2 bytes, but must be 4 or 8 bytes at offset 1 of __TEXT,__text in [[FILE]]
5+
# CHECK: error: UNSIGNED relocation has invalid width of 2 bytes at offset 1 of __TEXT,__text in [[FILE]]
66

77
!mach-o
88
FileHeader:

lld/test/MachO/x86-64-relocs.s

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
# CHECK: __data {{[0-9a-z]+}} [[#%x, DATA_ADDR:]]
88

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

1213
# CHECK-LABEL: <_main>:
1314
## Test X86_64_RELOC_BRANCH
1415
# CHECK: callq 0x[[#%x, F_ADDR]] <_f>
16+
# CHECK: jrcxz 0x[[#%x, F_ADDR]] <_f>
17+
# CHECK: callq 0x[[#%x, G_ADDR]] <_g>
18+
# CHECK: jrcxz 0x[[#%x, G_ADDR]] <_g>
1519
## Test extern (symbol) X86_64_RELOC_SIGNED
1620
# CHECK: leaq [[#%u, LOCAL_OFF:]](%rip), %rsi
1721
# CHECK-NEXT: [[#%x, DATA_ADDR - LOCAL_OFF]]
@@ -24,12 +28,20 @@
2428
# NONPCREL-NEXT: 100001000 08200000 01000000 08200000 01000000
2529

2630
.section __TEXT,__text
27-
.globl _main, _f
31+
.globl _main, _f, _g
32+
2833
_main:
29-
callq _f # X86_64_RELOC_BRANCH
34+
callq _f # X86_64_RELOC_BRANCH with r_length=2
35+
jrcxz _f # X86_64_RELOC_BRANCH with r_length=0
36+
# test negative addends
37+
callq _f - 1
38+
jrcxz _f - 1
3039
mov $0, %rax
3140
ret
3241

42+
_g:
43+
.byte 0x0
44+
3345
_f:
3446
leaq _local(%rip), %rsi # Generates a X86_64_RELOC_SIGNED pcrel symbol relocation
3547
leaq L_.private(%rip), %rsi # Generates a X86_64_RELOC_SIGNED pcrel section relocation

0 commit comments

Comments
 (0)