Skip to content

Commit a6671ac

Browse files
committed
Add Relocation information for Mach-O AArch64.
1 parent 200ca30 commit a6671ac

File tree

3 files changed

+203
-79
lines changed

3 files changed

+203
-79
lines changed

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ public enum RelocationKind {
274274
PC_RELATIVE_2,
275275
PC_RELATIVE_4,
276276
PC_RELATIVE_8,
277+
/**
278+
* AArch64-specific relocation types.
279+
*/
277280
AARCH64_R_MOVW_UABS_G0,
278281
AARCH64_R_MOVW_UABS_G0_NC,
279282
AARCH64_R_MOVW_UABS_G1,
@@ -345,6 +348,14 @@ public static int getRelocationSize(RelocationKind kind) {
345348
case PC_RELATIVE_4:
346349
case SECREL_4:
347350
return 4;
351+
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
352+
case AARCH64_R_AARCH64_LDST64_ABS_LO12_NC:
353+
case AARCH64_R_AARCH64_LDST32_ABS_LO12_NC:
354+
case AARCH64_R_AARCH64_LDST16_ABS_LO12_NC:
355+
case AARCH64_R_AARCH64_LDST8_ABS_LO12_NC:
356+
case AARCH64_R_AARCH64_ADD_ABS_LO12_NC:
357+
// AArch64 instructions are 4 bytes
358+
return 4;
348359
case DIRECT_8:
349360
case PC_RELATIVE_8:
350361
return 8;

substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/macho/MachORelocationElement.java

Lines changed: 133 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.util.Set;
3131
import java.util.TreeMap;
3232

33+
import org.graalvm.compiler.core.common.NumUtil;
34+
3335
import com.oracle.objectfile.BuildDependency;
3436
import com.oracle.objectfile.LayoutDecisionMap;
3537
import com.oracle.objectfile.ObjectFile;
@@ -47,14 +49,21 @@
4749
class MachORelocationElement extends MachOObjectFile.LinkEditElement {
4850
/*
4951
* We are a bunch of RelocationInfo.Structs grouped by relocated section, ordered by the offset
50-
* within the section.
52+
* within the section. Note also that, when present, an explicit addend for a given offset must
53+
* be stored immediately before is corresponding record
5154
*/
5255

5356
private static int compareSectionThenOffset(MachORelocationInfo p, MachORelocationInfo q) {
5457
if (!p.getRelocatedSection().equals(q.getRelocatedSection())) {
5558
return p.getRelocatedSection().hashCode() - q.getRelocatedSection().hashCode();
5659
}
57-
return Math.toIntExact(p.getOffset() - q.getOffset());
60+
if (p.getOffset() != q.getOffset()) {
61+
return Math.toIntExact(p.getOffset() - q.getOffset());
62+
}
63+
64+
assert !(p.isAddendKind() && q.isAddendKind()) : "two addends for same relocation";
65+
// want the addend kind first
66+
return -Boolean.compare(p.isAddendKind(), q.isAddendKind());
5867
}
5968

6069
private Map<MachORelocationInfo, MachORelocationInfo> infos = new TreeMap<>(MachORelocationElement::compareSectionThenOffset);
@@ -116,6 +125,12 @@ public int countFor(MachOSection s) {
116125
}
117126
}
118127

128+
interface MachORelocationType {
129+
boolean isPCRelative();
130+
131+
int getValue();
132+
}
133+
119134
/**
120135
* These are defined as an enum in
121136
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/x86_64/reloc.h#L173
@@ -124,20 +139,39 @@ public int countFor(MachOSection s) {
124139
* For examples of how these symbols are used, see the linked file above and
125140
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h.
126141
*/
127-
enum X86_64Reloc {
128-
UNSIGNED, // for absolute addresses
129-
SIGNED, // for signed 32-bit displacement
130-
BRANCH, // a CALL/JMP instruction with 32-bit displacement
131-
GOT_LOAD, // a MOVQ load of a GOT entry
132-
GOT, // other GOT references
133-
SUBTRACTOR, // must be followed by a X86_64_RELOC_UNSIGNED
134-
SIGNED_1, // for signed 32-bit displacement with a -1 addend
135-
SIGNED_2, // for signed 32-bit displacement with a -2 addend
136-
SIGNED_4, // for signed 32-bit displacement with a -4 addend
137-
TLV; // for thread local variables
142+
enum X86_64Reloc implements MachORelocationType {
143+
UNSIGNED(0), // for absolute addresses
144+
SIGNED(1, true), // for signed 32-bit displacement
145+
BRANCH(2), // a CALL/JMP instruction with 32-bit displacement
146+
GOT_LOAD(3), // a MOVQ load of a GOT entry
147+
GOT(4), // other GOT references
148+
SUBTRACTOR(5), // must be followed by a X86_64_RELOC_UNSIGNED
149+
SIGNED_1(6), // for signed 32-bit displacement with a -1 addend
150+
SIGNED_2(7), // for signed 32-bit displacement with a -2 addend
151+
SIGNED_4(8), // for signed 32-bit displacement with a -4 addend
152+
TLV(9); // for thread local variables
153+
154+
private final boolean pcRelative;
155+
private final int value;
138156

157+
X86_64Reloc(int value) {
158+
this.value = value;
159+
pcRelative = false;
160+
}
161+
162+
X86_64Reloc(int value, boolean pcRelative) {
163+
this.value = value;
164+
this.pcRelative = pcRelative;
165+
}
166+
167+
@Override
168+
public boolean isPCRelative() {
169+
return pcRelative;
170+
}
171+
172+
@Override
139173
public int getValue() {
140-
return ordinal();
174+
return value;
141175
}
142176
}
143177

@@ -151,33 +185,53 @@ public int getValue() {
151185
* (for AArch32 information, but does provide some insight) and
152186
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h.
153187
*/
154-
enum ARM64Reloc {
155-
UNSIGNED, // for pointers
156-
SUBTRACTOR, // must be followed by a ARM64_RELOC_UNSIGNED
157-
BRANCH26, // a B/BL instruction with 26-bit displacement
158-
PAGE21, // pc-rel distance to page of target
159-
PAGEOFF12, // offset within page, scaled by r_length
160-
GOT_LOAD_PAGE21, // pc-rel distance to page of GOT slot
161-
GOT_LOAD_PAGEOFF12, // offset within page of GOT slot, scaled by r_length
162-
POINTER_TO_GOT, // for pointers to GOT slots
163-
TLVP_LOAD_PAGE21, // pc-rel distance to page of TLVP slot
164-
TLVP_LOAD_PAGEOFF12, // offset within page of TLVP slot, scaled by r_length
165-
ADDEND; // must be followed by PAGE21 or PAGEOFF12
188+
enum ARM64Reloc implements MachORelocationType {
189+
UNSIGNED(0), // for pointers
190+
SUBTRACTOR(1), // must be followed by a ARM64_RELOC_UNSIGNED
191+
BRANCH26(2), // a B/BL instruction with 26-bit displacement
192+
PAGE21(3, true), // pc-rel distance to page of target
193+
PAGEOFF12(4), // offset within page, scaled by r_length
194+
GOT_LOAD_PAGE21(5, true), // pc-rel distance to page of GOT slot
195+
GOT_LOAD_PAGEOFF12(6), // offset within page of GOT slot, scaled by r_length
196+
POINTER_TO_GOT(7), // for pointers to GOT slots
197+
TLVP_LOAD_PAGE21(8, true), // pc-rel distance to page of TLVP slot
198+
TLVP_LOAD_PAGEOFF12(9), // offset within page of TLVP slot, scaled by r_length
199+
ADDEND(10); // must be followed by PAGE21 or PAGEOFF12
200+
201+
private final boolean pcRelative;
202+
private final int value;
203+
204+
ARM64Reloc(int value) {
205+
this.value = value;
206+
pcRelative = false;
207+
}
208+
209+
ARM64Reloc(int value, boolean pcRelative) {
210+
this.value = value;
211+
this.pcRelative = pcRelative;
212+
}
166213

214+
@Override
215+
public boolean isPCRelative() {
216+
return pcRelative;
217+
}
218+
219+
@Override
167220
public int getValue() {
168-
return ordinal();
221+
return value;
169222
}
170223
}
171224

172225
final class MachORelocationInfo implements RelocationRecord, RelocationMethod {
173226

174227
private final MachORelocationElement containingElement;
175228
private final MachOSection relocatedSection;
176-
private final RelocationKind kind;
229+
private final MachORelocationType kind;
177230
private final int sectionOffset;
178231
private final Symbol sym;
179232
private final MachOSection targetSection;
180233
private final byte log2length;
234+
private final int addend;
181235

182236
/**
183237
* Construct a relocation record.
@@ -189,7 +243,9 @@ final class MachORelocationInfo implements RelocationRecord, RelocationMethod {
189243
* @param kind the kind of relocation to perform at the relocation site
190244
* @param symbolName the symbol against which to relocate
191245
*/
192-
MachORelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, RelocationKind kind, String symbolName, boolean asLocalReloc) {
246+
private MachORelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, MachORelocationType kind, String symbolName,
247+
boolean asLocalReloc,
248+
int addend) {
193249
this.containingElement = containingElement;
194250
this.relocatedSection = relocatedSection;
195251
this.sectionOffset = offset; // gets turned into a vaddr on write-out
@@ -215,6 +271,20 @@ final class MachORelocationInfo implements RelocationRecord, RelocationMethod {
215271
// if the symbol is defined in the same file, i.e. locally, we have a target section
216272
assert !asLocalReloc || this.sym.isDefined();
217273
this.targetSection = asLocalReloc ? (MachOSection) this.sym.getDefinedSection() : null;
274+
this.addend = addend;
275+
}
276+
277+
/* Creates an ARM64_RELOC_ADDEND relocation type. */
278+
static MachORelocationInfo createARM64RelocAddend(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, String symbolName, long addend) {
279+
int length = 4; // This relocation record holds the addend for a 4-byte AArch64 instruction
280+
return new MachORelocationInfo(containingElement, relocatedSection, offset, length, ARM64Reloc.ADDEND, symbolName, false, Math.toIntExact(addend));
281+
}
282+
283+
static MachORelocationInfo createRelocation(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, RelocationKind kind, String symbolName) {
284+
int length = ObjectFile.RelocationKind.getRelocationSize(kind);
285+
MachORelocationType type = getMachORelocationType(relocatedSection, kind);
286+
return new MachORelocationInfo(containingElement, relocatedSection, offset, length, type, symbolName, false, 0);
287+
218288
}
219289

220290
public static int getEncodedSize() {
@@ -225,7 +295,12 @@ public void write(OutputAssembler oa, @SuppressWarnings("unused") Map<Element, L
225295
/* We need to convert in-section offsets to vaddrs if we are writing dynamic object. */
226296
// "extern" means symbolNum is a symbol not a section number
227297
int symbolNum;
228-
if (isExtern()) {
298+
if (isAddendKind()) {
299+
assert !isExtern() : "addend must be encoded as a local";
300+
assert NumUtil.isSignedNbit(24, addend);
301+
// store addend as symbolnum
302+
symbolNum = addend;
303+
} else if (isExtern()) {
229304
// we're non-local, so use a symbol
230305
symbolNum = relocatedSection.getOwner().getSymbolTable().indexOf(sym);
231306
} else {
@@ -249,11 +324,11 @@ public void write(OutputAssembler oa, @SuppressWarnings("unused") Map<Element, L
249324
*/
250325
int remainingWord = 0;
251326
//@formatter:off
252-
remainingWord |= symbolNum & 0x00ffffff;
253-
remainingWord |= isPCRelative() ? (1 << 24) : 0;
254-
remainingWord |= (log2length & 0x3) << 25;
255-
remainingWord |= isExtern() ? (1 << 27) : 0;
256-
remainingWord |= (getMachORelocationType() & 0xf) << 28;
327+
remainingWord |= symbolNum & 0x00ffffff;
328+
remainingWord |= (kind.isPCRelative() ? 1 : 0) << 24;
329+
remainingWord |= (log2length & 0x3) << 25;
330+
remainingWord |= (isExtern() ? 1 : 0) << 27;
331+
remainingWord |= (kind.getValue() & 0xf) << 28;
257332
//@formatter:on
258333
oa.write4Byte(remainingWord);
259334
assert oa.pos() - startPos == 8; // check we wrote how much we expected
@@ -271,42 +346,41 @@ public Symbol getReferencedSymbol() {
271346
return sym;
272347
}
273348

349+
public boolean isAddendKind() {
350+
return kind == ARM64Reloc.ADDEND;
351+
}
352+
353+
public long getAddend() {
354+
return addend;
355+
}
356+
274357
public MachOSection getRelocatedSection() {
275358
return relocatedSection;
276359
}
277360

278361
private boolean isExtern() {
279-
// we record localness by grabbing the target section (see constructor)
280-
return targetSection == null;
281-
}
282-
283-
private boolean isPCRelative() {
284-
switch (kind) {
285-
case PC_RELATIVE_1:
286-
case PC_RELATIVE_2:
287-
case PC_RELATIVE_4:
288-
case PC_RELATIVE_8:
289-
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
290-
return true;
291-
default:
292-
return false;
293-
}
362+
/*
363+
* We record localness by grabbing the target section (see constructor). Note that the
364+
* addend kind is not considered an extern.
365+
*/
366+
367+
return targetSection == null && !isAddendKind();
294368
}
295369

296-
private int getMachORelocationType() {
297-
switch (getRelocatedSection().getOwner().cpuType) {
370+
private static MachORelocationType getMachORelocationType(MachOSection relocatedSection, RelocationKind kind) {
371+
switch (relocatedSection.getOwner().cpuType) {
298372
case X86_64:
299373
switch (kind) {
300374
case DIRECT_1:
301375
case DIRECT_2:
302376
case DIRECT_4:
303377
case DIRECT_8:
304-
return X86_64Reloc.UNSIGNED.getValue();
378+
return X86_64Reloc.UNSIGNED;
305379
case PC_RELATIVE_1:
306380
case PC_RELATIVE_2:
307381
case PC_RELATIVE_4:
308382
case PC_RELATIVE_8:
309-
return X86_64Reloc.SIGNED.getValue();
383+
return X86_64Reloc.SIGNED;
310384
default:
311385
case UNKNOWN:
312386
throw new IllegalArgumentException("unknown relocation kind: " + kind);
@@ -317,15 +391,15 @@ private int getMachORelocationType() {
317391
case DIRECT_2:
318392
case DIRECT_4:
319393
case DIRECT_8:
320-
return ARM64Reloc.UNSIGNED.getValue();
394+
return ARM64Reloc.UNSIGNED;
321395
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
322-
return ARM64Reloc.PAGE21.getValue();
396+
return ARM64Reloc.PAGE21;
323397
case AARCH64_R_AARCH64_LDST64_ABS_LO12_NC:
324398
case AARCH64_R_AARCH64_LDST32_ABS_LO12_NC:
325399
case AARCH64_R_AARCH64_LDST16_ABS_LO12_NC:
326400
case AARCH64_R_AARCH64_LDST8_ABS_LO12_NC:
327401
case AARCH64_R_AARCH64_ADD_ABS_LO12_NC:
328-
return ARM64Reloc.PAGEOFF12.getValue();
402+
return ARM64Reloc.PAGEOFF12;
329403
default:
330404
case UNKNOWN:
331405
throw new IllegalArgumentException("unknown relocation kind: " + kind);
@@ -342,7 +416,7 @@ public boolean equals(Object obj) {
342416
}
343417
if (obj != null && getClass() == obj.getClass()) {
344418
MachORelocationInfo other = (MachORelocationInfo) obj;
345-
return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) &&
419+
return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) && addend == other.addend &&
346420
Objects.equals(getRelocatedSection(), other.getRelocatedSection()) && kind == other.kind &&
347421
Objects.equals(sym, other.sym) && Objects.equals(targetSection, other.targetSection);
348422
}
@@ -351,7 +425,6 @@ public boolean equals(Object obj) {
351425

352426
@Override
353427
public int hashCode() {
354-
return (((((containingElement.hashCode() * 31 + relocatedSection.hashCode()) * 31 + kind.hashCode()) * 31 +
355-
sectionOffset) * 31 + sym.hashCode()) * 31 + targetSection.hashCode()) * 31 + log2length;
428+
return Objects.hash(containingElement, relocatedSection, kind, sectionOffset, sym, targetSection, log2length, addend);
356429
}
357430
}

0 commit comments

Comments
 (0)