Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@ public static int getRelocationSize(RelocationKind kind) {
case DIRECT_4:
case PC_RELATIVE_4:
case SECREL_4:
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
case AARCH64_R_AARCH64_LDST64_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST32_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST16_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST8_ABS_LO12_NC:
case AARCH64_R_AARCH64_ADD_ABS_LO12_NC:
return 4;
case DIRECT_8:
case PC_RELATIVE_8:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ private static int compareSectionThenOffset(RelocationInfo p, RelocationInfo q)
if (!p.getRelocatedSection().equals(q.getRelocatedSection())) {
return p.getRelocatedSection().hashCode() - q.getRelocatedSection().hashCode();
}
return Math.toIntExact(p.getOffset() - q.getOffset());
if (p.getOffset() != q.getOffset()) {
return Math.toIntExact(p.getOffset() - q.getOffset());
}

if (Objects.equals(p.getAddend(), q.getAddend())) {
return 0;
} else if (p.getAddend() == null) {
return 1;
} else {
return -1;
}
}

private Map<RelocationInfo, RelocationInfo> infos = new TreeMap<>(MachORelocationElement::compareSectionThenOffset);
Expand Down Expand Up @@ -168,21 +178,21 @@ final class RelocationInfo implements RelocationRecord, RelocationMethod {
private final Symbol sym;
private final MachOSection targetSection;
private final byte log2length;
private final Long addend; // `null` for kinds other than ADDEND

/**
* Construct a relocation record.
* Construct a relocation record for ARM64_RELOC_ADDEND.
*
* @param containingElement the containing relocation element
* @param relocatedSection the section being relocated
* @param offset the offset, within the relocated section, of the relocation site
* @param requestedLength the length of the relocation site
* @param kind the kind of relocation to perform at the relocation site
* @param symbolName the symbol against which to relocate
* @param addend the addend to be encoded
*/
RelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, RelocationKind kind, String symbolName, boolean asLocalReloc) {
this.containingElement = containingElement;
this.relocatedSection = relocatedSection;
this.sectionOffset = offset; // gets turned into a vaddr on write-out
public static RelocationInfo newAddend(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, long addend) {
return new RelocationInfo(containingElement, relocatedSection, offset, requestedLength, addend);
}

private static byte encodeRequestedLength(int requestedLength) {
/*
* NOTE: the Mach-O spec claims that r_length == 3 means a 4-byte length and not an 8-byte
* length. But it doesn't say how to encode an 8-bytes-long relocation site. And the
Expand All @@ -196,7 +206,43 @@ final class RelocationInfo implements RelocationRecord, RelocationMethod {
if (requestedLength != 8 && requestedLength != 4 && requestedLength != 2 && requestedLength != 1) {
throw new IllegalArgumentException("Mach-O cannot represent relocation lengths other than {1,2,4,8} bytes");
}
this.log2length = (byte) ((requestedLength == 8) ? 3 : (requestedLength == 4) ? 2 : (requestedLength == 2) ? 1 : 0);
return (byte) ((requestedLength == 8) ? 3 : (requestedLength == 4) ? 2 : (requestedLength == 2) ? 1 : 0);
}

/**
* Construct a relocation record for ARM64_RELOC_ADDEND.
*
* @param containingElement the containing relocation element
* @param relocatedSection the section being relocated
* @param offset the offset, within the relocated section, of the relocation site
* @param addend the addend to be encoded
*/
private RelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, long addend) {
this.containingElement = containingElement;
this.relocatedSection = relocatedSection;
this.sectionOffset = offset; // gets turned into a vaddr on write-out
this.log2length = encodeRequestedLength(requestedLength);
this.kind = RelocationKind.UNKNOWN; // Placeholder
this.targetSection = null;
this.sym = null;
this.addend = addend;
}

/**
* Construct a relocation record.
*
* @param containingElement the containing relocation element
* @param relocatedSection the section being relocated
* @param offset the offset, within the relocated section, of the relocation site
* @param requestedLength the length of the relocation site
* @param kind the kind of relocation to perform at the relocation site
* @param symbolName the symbol against which to relocate
*/
RelocationInfo(MachORelocationElement containingElement, MachOSection relocatedSection, int offset, int requestedLength, RelocationKind kind, String symbolName, boolean asLocalReloc) {
this.containingElement = containingElement;
this.relocatedSection = relocatedSection;
this.sectionOffset = offset; // gets turned into a vaddr on write-out
this.log2length = encodeRequestedLength(requestedLength);
this.kind = kind;
SymbolTable symtab = relocatedSection.getOwner().getSymbolTable();
// FIXME: also allow section numbers here, for non-extern symbols
Expand All @@ -205,6 +251,7 @@ final class RelocationInfo implements RelocationRecord, RelocationMethod {
// if the symbol is defined in the same file, i.e. locally, we have a target section
assert !asLocalReloc || this.sym.isDefined();
this.targetSection = asLocalReloc ? (MachOSection) this.sym.getDefinedSection() : null;
this.addend = null;
}

public static int getEncodedSize() {
Expand All @@ -216,12 +263,18 @@ public void write(OutputAssembler oa, @SuppressWarnings("unused") Map<Element, L
// "extern" means symbolNum is a symbol not a section number
int symbolNum;
if (isExtern()) {
assert addend == null;
// we're non-local, so use a symbol
symbolNum = relocatedSection.getOwner().getSymbolTable().indexOf(sym);
} else {
// we're local, so use the section
symbolNum = relocatedSection.getOwner().getSections().indexOf(sym.getDefinedSection());
assert sym.getDefinedOffset() == 0 : "Relocation for non-external symbol with section base offset != 0 not supported";
if (addend == null) {
// we're local, so use the section
symbolNum = relocatedSection.getOwner().getSections().indexOf(sym.getDefinedSection());
assert sym.getDefinedOffset() == 0 : "Relocation for non-external symbol with section base offset != 0 not supported";
} else {
// Use addend as symbolnum
symbolNum = Math.toIntExact(addend);
}
}
if (log2length < 0 || log2length >= 4) {
throw new IllegalArgumentException("length must be in {1,2,4,8} bytes, so log2length must be in [0,3]");
Expand Down Expand Up @@ -275,9 +328,13 @@ public MachOSection getRelocatedSection() {
return relocatedSection;
}

public Long getAddend() {
return addend;
}

private boolean isExtern() {
// we record localness by grabbing the target section (see constructor)
return targetSection == null;
return targetSection == null && addend == null;
}

private boolean isPCRelative() {
Expand Down Expand Up @@ -312,6 +369,9 @@ private int getMachORelocationType() {
throw new IllegalArgumentException("unknown relocation kind: " + kind);
}
case ARM64:
if (addend != null) {
return ARM64Reloc.ADDEND.getValue();
}
switch (kind) {
case DIRECT_1:
case DIRECT_2:
Expand Down Expand Up @@ -344,7 +404,8 @@ public boolean equals(Object obj) {
RelocationInfo other = (RelocationInfo) obj;
return sectionOffset == other.sectionOffset && log2length == other.log2length && Objects.equals(containingElement, other.containingElement) &&
Objects.equals(getRelocatedSection(), other.getRelocatedSection()) && kind == other.kind &&
Objects.equals(sym, other.sym) && Objects.equals(targetSection, other.targetSection);
Objects.equals(sym, other.sym) && Objects.equals(targetSection, other.targetSection) &&
Objects.equals(addend, other.addend);
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.oracle.objectfile.macho.MachOObjectFile.SectionFlag;
import com.oracle.objectfile.macho.MachOObjectFile.SectionType;
import com.oracle.objectfile.macho.MachOObjectFile.Segment64Command;
import org.graalvm.compiler.debug.GraalError;

/**
* @see com.oracle.objectfile.elf.ELFUserDefinedSection
Expand Down Expand Up @@ -164,42 +165,75 @@ public void markRelocationSite(int offset, ByteBuffer bb, RelocationKind k, Stri
AssemblyBuffer sbb = new AssemblyBuffer(bb);
sbb.setByteOrder(getOwner().getByteOrder());
sbb.pushSeek(offset);
/*
* NOTE: Mach-O does not support explicit addends, and inline addends are applied even
* during dynamic linking. So if the caller supplies an explicit addend, we turn it into an
* implicit one by updating our content.
*/

int length = ObjectFile.RelocationKind.getRelocationSize(k);
long currentInlineAddendValue = sbb.readTruncatedLong(length);
long desiredInlineAddendValue;
if (explicitAddend != null) {

if (getOwner().cpuType == MachOCpuType.X86_64) {
/*
* This assertion is conservatively disallowing double-addend (could
* "add currentValue to explicitAddend"), because that seems more likely to be a bug
* than a feature.
* NOTE: X86_64 Mach-O does not support explicit addends, and inline addends are applied
* even during dynamic linking. So if the caller supplies an explicit addend, we turn it
* into an implicit one by updating our content.
*/
assert currentInlineAddendValue == 0;
desiredInlineAddendValue = explicitAddend;
} else {
desiredInlineAddendValue = currentInlineAddendValue;
}
long currentInlineAddendValue = sbb.readTruncatedLong(length);
long desiredInlineAddendValue;
if (explicitAddend != null) {
/*
* This assertion is conservatively disallowing double-addend (could
* "add currentValue to explicitAddend"), because that seems more likely to be a bug
* than a feature.
*/
assert currentInlineAddendValue == 0;
desiredInlineAddendValue = explicitAddend;
} else {
desiredInlineAddendValue = currentInlineAddendValue;
}

/*
* One more complication: for PC-relative relocation, at least on x86-64, Mach-O linkers
* (both AOT ld and dyld) adjust the calculation to compensate for the fact that it's the
* *next* instruction that the PC-relative reference gets resolved against. Note that ELF
* doesn't do this compensation. Our interface duplicates the ELF behaviour, so we have to
* act against this Mach-O-specific fixup here, by *adding* a little to the addend. The
* amount we add is always the length in bytes of the relocation site (since on x86-64 the
* reference is always the last field in a PC-relative instruction).
*/
if (RelocationKind.isPCRelative(k)) {
desiredInlineAddendValue += length;
}
/*
* One more complication: for PC-relative relocation, at least on x86-64, Mach-O linkers
* (both AOT ld and dyld) adjust the calculation to compensate for the fact that it's
* the *next* instruction that the PC-relative reference gets resolved against. Note
* that ELF doesn't do this compensation. Our interface duplicates the ELF behaviour, so
* we have to act against this Mach-O-specific fixup here, by *adding* a little to the
* addend. The amount we add is always the length in bytes of the relocation site (since
* on x86-64 the reference is always the last field in a PC-relative instruction).
*/
if (RelocationKind.isPCRelative(k)) {
desiredInlineAddendValue += length;
}

// Write the inline addend back to the buffer.
sbb.seek(offset);
sbb.writeTruncatedLong(desiredInlineAddendValue, length);
// Write the inline addend back to the buffer.
sbb.seek(offset);
sbb.writeTruncatedLong(desiredInlineAddendValue, length);
} else {
switch (k) {
case DIRECT_4:
case DIRECT_8:
sbb.writeTruncatedLong(explicitAddend, length);
break;
case AARCH64_R_AARCH64_ADR_PREL_PG_HI21:
case AARCH64_R_AARCH64_LDST64_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST32_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST16_ABS_LO12_NC:
case AARCH64_R_AARCH64_LDST8_ABS_LO12_NC:
case AARCH64_R_AARCH64_ADD_ABS_LO12_NC:
if (explicitAddend != 0) {
/*
* These relocations should use an explicit addend reloc record instead of
* an embedded addend, according to the Mach-O ld code at
* https://opensource.apple.com/source/ld64/ld64-274.2/src/ld/parsers/
* macho_relocatable_file.cpp.auto.html
*
* > xxxx instruction at xxxx has embedded addend. ARM64_RELOC_ADDEND should
* be used instead
*/
RelocationInfo addend = RelocationInfo.newAddend(el, this, offset, length, explicitAddend);
el.add(addend);
}
break;
default:
GraalError.shouldNotReachHere();
}
}

// set section flag to note that we have relocations
assert symbolName != null;
Expand Down