Skip to content

Commit 0c24d67

Browse files
committed
Add Relocation information for Mach-O AArch64.
1 parent a5a4c29 commit 0c24d67

File tree

3 files changed

+212
-89
lines changed

3 files changed

+212
-89
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: 142 additions & 70 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 its 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+
// reverse arguments since want the addend kind first
66+
return Boolean.compare(q.isAddendKind(), p.isAddendKind());
5867
}
5968

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

128+
interface MachORelocationType {
129+
boolean isPCRelative();
130+
131+
int getValue();
132+
}
133+
119134
/**
120-
* These are defined as an enum in
121-
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/x86_64/reloc.h#L173
135+
* These are defined as an enum in <a href=
136+
* "https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/x86_64/reloc.h#L173">EXTERNAL_HEADERS/mach-o/x86_64/reloc.h#L173</a>
122137
* which we reproduce. Of course, take care to preserve the order!
123138
*
124-
* For examples of how these symbols are used, see the linked file above and
125-
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h.
139+
* For examples of how these symbols are used, see the linked file above and <a href=
140+
* "https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h">EXTERNAL_HEADERS/mach-o/reloc.h</a>.
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, true), // for signed 32-bit displacement with a -1 addend
150+
SIGNED_2(7, true), // for signed 32-bit displacement with a -2 addend
151+
SIGNED_4(8, true), // 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

144178
/**
145-
* These are defined as an enum in
146-
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm64/reloc.h#L26,
179+
* These are defined as an enum in <a href=
180+
* "https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm64/reloc.h#L26">EXTERNAL_HEADERS/mach-o/arm64/reloc.h#L26</a>,
147181
* which we reproduce. Of course, take care to preserve the order!
148182
*
149-
* For examples of how these symbols are used, see
150-
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm/reloc.h
151-
* (for AArch32 information, but does provide some insight) and
152-
* https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h.
183+
* For examples of how these symbols are used, see <a href=
184+
* "https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/arm/reloc.h">EXTERNAL_HEADERS/mach-o/arm/reloc.h</a>
185+
* (for AArch32 information, but does provide some insight) and <a href=
186+
* "https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/EXTERNAL_HEADERS/mach-o/reloc.h">EXTERNAL_HEADERS/mach-o/reloc.h</a>.
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,8 @@ 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, int addend) {
193248
this.containingElement = containingElement;
194249
this.relocatedSection = relocatedSection;
195250
this.sectionOffset = offset; // gets turned into a vaddr on write-out
@@ -215,6 +270,20 @@ final class MachORelocationInfo implements RelocationRecord, RelocationMethod {
215270
// if the symbol is defined in the same file, i.e. locally, we have a target section
216271
assert !asLocalReloc || this.sym.isDefined();
217272
this.targetSection = asLocalReloc ? (MachOSection) this.sym.getDefinedSection() : null;
273+
this.addend = addend;
274+
}
275+
276+
/* Creates an ARM64_RELOC_ADDEND relocation type. */
277+
static MachORelocationInfo createARM64RelocAddend(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, String symbolName, long addend) {
278+
int length = 4; // This relocation record holds the addend for a 4-byte AArch64 instruction
279+
return new MachORelocationInfo(containingElement, relocatedSection, offset, length, ARM64Reloc.ADDEND, symbolName, false, Math.toIntExact(addend));
280+
}
281+
282+
static MachORelocationInfo createRelocation(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, RelocationKind kind, String symbolName) {
283+
int length = ObjectFile.RelocationKind.getRelocationSize(kind);
284+
MachORelocationType type = getMachORelocationType(relocatedSection, kind);
285+
return new MachORelocationInfo(containingElement, relocatedSection, offset, length, type, symbolName, false, 0);
286+
218287
}
219288

220289
public static int getEncodedSize() {
@@ -225,7 +294,12 @@ public void write(OutputAssembler oa, @SuppressWarnings("unused") Map<Element, L
225294
/* We need to convert in-section offsets to vaddrs if we are writing dynamic object. */
226295
// "extern" means symbolNum is a symbol not a section number
227296
int symbolNum;
228-
if (isExtern()) {
297+
if (isAddendKind()) {
298+
assert !isExtern() : "addend must be encoded as a local";
299+
assert NumUtil.isSignedNbit(24, addend);
300+
// store addend as symbolnum
301+
symbolNum = addend;
302+
} else if (isExtern()) {
229303
// we're non-local, so use a symbol
230304
symbolNum = relocatedSection.getOwner().getSymbolTable().indexOf(sym);
231305
} else {
@@ -249,11 +323,11 @@ public void write(OutputAssembler oa, @SuppressWarnings("unused") Map<Element, L
249323
*/
250324
int remainingWord = 0;
251325
//@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;
326+
remainingWord |= symbolNum & 0x00ffffff;
327+
remainingWord |= (kind.isPCRelative() ? 1 : 0) << 24;
328+
remainingWord |= (log2length & 0x3) << 25;
329+
remainingWord |= (isExtern() ? 1 : 0) << 27;
330+
remainingWord |= (kind.getValue() & 0xf) << 28;
257331
//@formatter:on
258332
oa.write4Byte(remainingWord);
259333
assert oa.pos() - startPos == 8; // check we wrote how much we expected
@@ -271,42 +345,41 @@ public Symbol getReferencedSymbol() {
271345
return sym;
272346
}
273347

348+
public boolean isAddendKind() {
349+
return kind == ARM64Reloc.ADDEND;
350+
}
351+
352+
public long getAddend() {
353+
return addend;
354+
}
355+
274356
public MachOSection getRelocatedSection() {
275357
return relocatedSection;
276358
}
277359

278360
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-
}
361+
/*
362+
* We record localness by grabbing the target section (see constructor). Note that the
363+
* addend kind is not considered an extern.
364+
*/
365+
366+
return targetSection == null && !isAddendKind();
294367
}
295368

296-
private int getMachORelocationType() {
297-
switch (getRelocatedSection().getOwner().cpuType) {
369+
private static MachORelocationType getMachORelocationType(MachOSection relocatedSection, RelocationKind kind) {
370+
switch (relocatedSection.getOwner().cpuType) {
298371
case X86_64:
299372
switch (kind) {
300373
case DIRECT_1:
301374
case DIRECT_2:
302375
case DIRECT_4:
303376
case DIRECT_8:
304-
return X86_64Reloc.UNSIGNED.getValue();
377+
return X86_64Reloc.UNSIGNED;
305378
case PC_RELATIVE_1:
306379
case PC_RELATIVE_2:
307380
case PC_RELATIVE_4:
308381
case PC_RELATIVE_8:
309-
return X86_64Reloc.SIGNED.getValue();
382+
return X86_64Reloc.SIGNED;
310383
default:
311384
case UNKNOWN:
312385
throw new IllegalArgumentException("unknown relocation kind: " + kind);
@@ -317,15 +390,15 @@ private int getMachORelocationType() {
317390
case DIRECT_2:
318391
case DIRECT_4:
319392
case DIRECT_8:
320-
return ARM64Reloc.UNSIGNED.getValue();
393+
return ARM64Reloc.UNSIGNED;
321394
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
322-
return ARM64Reloc.PAGE21.getValue();
395+
return ARM64Reloc.PAGE21;
323396
case AARCH64_R_AARCH64_LDST64_ABS_LO12_NC:
324397
case AARCH64_R_AARCH64_LDST32_ABS_LO12_NC:
325398
case AARCH64_R_AARCH64_LDST16_ABS_LO12_NC:
326399
case AARCH64_R_AARCH64_LDST8_ABS_LO12_NC:
327400
case AARCH64_R_AARCH64_ADD_ABS_LO12_NC:
328-
return ARM64Reloc.PAGEOFF12.getValue();
401+
return ARM64Reloc.PAGEOFF12;
329402
default:
330403
case UNKNOWN:
331404
throw new IllegalArgumentException("unknown relocation kind: " + kind);
@@ -342,7 +415,7 @@ public boolean equals(Object obj) {
342415
}
343416
if (obj != null && getClass() == obj.getClass()) {
344417
MachORelocationInfo other = (MachORelocationInfo) obj;
345-
return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) &&
418+
return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) && addend == other.addend &&
346419
Objects.equals(getRelocatedSection(), other.getRelocatedSection()) && kind == other.kind &&
347420
Objects.equals(sym, other.sym) && Objects.equals(targetSection, other.targetSection);
348421
}
@@ -351,7 +424,6 @@ public boolean equals(Object obj) {
351424

352425
@Override
353426
public int hashCode() {
354-
return (((((containingElement.hashCode() * 31 + relocatedSection.hashCode()) * 31 + kind.hashCode()) * 31 +
355-
sectionOffset) * 31 + sym.hashCode()) * 31 + targetSection.hashCode()) * 31 + log2length;
427+
return Objects.hash(containingElement, relocatedSection, kind, sectionOffset, sym, targetSection, log2length, addend);
356428
}
357429
}

0 commit comments

Comments
 (0)