diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/RelocationInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/RelocationInfo.java
index 23edcef4c1..9f1c890708 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/RelocationInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/RelocationInfo.java
@@ -31,9 +31,15 @@ public class RelocationInfo implements StructConverter {
/**
* Mask to be applied to the r_address field of a relocation_info structure to tell that it is
- * really a scattered_relocation_info structure
+ * really a scattered_relocation_info structure (little endian)
*/
- private static int R_SCATTERED = 0x80000000;
+ private static int R_SCATTERED_LE = 0x80000000;
+
+ /**
+ * Mask to be applied to the r_address field of a relocation_info structure to tell that it is
+ * really a scattered_relocation_info structure (big endian)
+ */
+ private static int R_SCATTERED_BE = 0x00000001;
/**
* 1=scattered, 0=non-scattered
@@ -76,7 +82,16 @@ public class RelocationInfo implements StructConverter {
int i1 = reader.readNextInt();
int i2 = reader.readNextInt();
- if ((i1 & R_SCATTERED) != 0) {
+ if (reader.isBigEndian() && (i1 & R_SCATTERED_BE) != 0) {
+ r_scattered = 1;
+ r_pcrel = (i1 >> 1) & 0x1;
+ r_length = (i1 >> 2) & 0x3;
+ r_type = (i1 >> 4) & 0xf;
+ r_address = (i1 >> 8) & 0xffffff;
+ r_extern = 1;
+ r_value = i2;
+ }
+ else if ((i1 & R_SCATTERED_LE) != 0) {
r_scattered = 1;
r_extern = 1;
r_address = i1 & 0xffffff;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/SymbolTableCommand.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/SymbolTableCommand.java
index 5ab7c26e56..d69681aa41 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/SymbolTableCommand.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/SymbolTableCommand.java
@@ -31,7 +31,6 @@ import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.ProgramModule;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.Reference;
-import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
@@ -131,7 +130,6 @@ public class SymbolTableCommand extends LoadCommand {
return null;
}
if (index > symbols.size()) {
- Msg.error(this, "Attempt to get symbols at " + Integer.toHexString(index));
return null;
}
return symbols.get(index);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java
index c667d5e3bb..14388515a7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/AbstractClassicProcessor.java
@@ -146,7 +146,7 @@ public abstract class AbstractClassicProcessor {
status = Status.UNSUPPORTED;
}
else {
- status = Status.APPLIED;
+ status = Status.APPLIED_OTHER;
}
// put an entry in the relocation table, handled or not
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/ClassicBindProcessor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/ClassicBindProcessor.java
index 4a594fa8a6..de79649574 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/ClassicBindProcessor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/commands/dyld/ClassicBindProcessor.java
@@ -46,6 +46,9 @@ public class ClassicBindProcessor extends AbstractClassicProcessor {
long address = relocation.getAddress() + getRelocationBase();
int symbolIndex = relocation.getValue();
NList nList = symbolTableCommand.getSymbolAt(symbolIndex);
+ if (nList == null) {
+ continue;
+ }
boolean isWeak = (nList.getDescription() & NListConstants.DESC_N_WEAK_REF) != 0;
String fromDylib = getClassicOrdinalName(nList.getLibraryOrdinal());
Section section = getSectionName(address);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java
index e3f512e9dc..bed3772f85 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/macho/relocation/MachoRelocation.java
@@ -260,14 +260,16 @@ public class MachoRelocation {
Symbol sym = null;
NList nlist = machoHeader.getFirstLoadCommand(SymbolTableCommand.class)
.getSymbolAt(relocInfo.getValue());
- Address addr = space.getAddress(nlist.getValue());
- sym = program.getSymbolTable()
- .getSymbol(SymbolUtilities.replaceInvalidChars(nlist.getString(), true), addr,
- null);
- if (sym == null) {
- sym = SymbolUtilities.getLabelOrFunctionSymbol(program, nlist.getString(), err -> {
- // no logging
- });
+ if (nlist != null) {
+ Address addr = space.getAddress(nlist.getValue());
+ sym = program.getSymbolTable()
+ .getSymbol(SymbolUtilities.replaceInvalidChars(nlist.getString(), true), addr,
+ null);
+ if (sym == null) {
+ sym = SymbolUtilities.getLabelOrFunctionSymbol(program, nlist.getString(), err -> {
+ // no logging
+ });
+ }
}
return sym;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java
index 8e9ee03fbc..84509cb75b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/MachoProgramBuilder.java
@@ -139,7 +139,7 @@ public class MachoProgramBuilder {
processUndefinedSymbols();
processAbsoluteSymbols();
List
chainedFixups = processChainedFixups();
- processDyldInfo(false);
+ processBindings(false);
markupHeaders(machoHeader, setupHeaderAddr(machoHeader.getAllSegments()));
markupSections();
processProgramVars();
@@ -776,7 +776,7 @@ public class MachoProgramBuilder {
}
}
- protected void processDyldInfo(boolean doClassic) {
+ protected void processBindings(boolean doClassic) {
List commands = machoHeader.getLoadCommands(DyldInfoCommand.class);
for (DyldInfoCommand command : commands) {
if (command.getBindSize() > 0) {
@@ -801,13 +801,7 @@ public class MachoProgramBuilder {
}
}
- if (!doClassic) {
- return;
- }
-
- //then we are use the old school binding technique.
- //this only still appears in powerpc
- if (commands.size() == 0) {
+ if (commands.size() == 0 && doClassic) {
ClassicBindProcessor classicBindProcess =
new ClassicBindProcessor(machoHeader, program);
try {
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationConstants.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationConstants.java
new file mode 100644
index 0000000000..a06f0c453b
--- /dev/null
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationConstants.java
@@ -0,0 +1,93 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.util.bin.format.macho.relocation;
+
+/**
+ * {@link PowerPC_MachoRelocationHandler} constants
+ *
+ * @see mach-o/ppc/reloc.h
+ */
+public class PowerPC_MachoRelocationConstants {
+
+ /**
+ * Generic relocation as described above
+ */
+ public final static int PPC_RELOC_VANILLA = 0;
+
+ /**
+ * The second relocation entry of a pair
+ */
+ public final static int PPC_RELOC_PAIR = 1;
+
+ /**
+ * 14 bit branch displacement (to a word address)
+ */
+ public final static int PPC_RELOC_BR14 = 2;
+
+ /**
+ * 24 bit branch displacement (to a word address)
+ */
+ public final static int PPC_RELOC_BR24 = 3;
+
+ /**
+ * A {@link #PPC_RELOC_PAIR} follows with the low half
+ */
+ public final static int PPC_RELOC_HI16 = 4;
+
+ /**
+ * A {@link #PPC_RELOC_PAIR} follows with the high half
+ */
+ public final static int PPC_RELOC_LO16 = 5;
+
+ /**
+ * Same as the {@link #PPC_RELOC_HI16} except the low 16 bits and the high 16 bits are added
+ * together with the low 16 bits sign-extended first. This means if bit 15 of the low 16 bits
+ * is set the high 16 bits stored in the instruction will be adjusted.
+ */
+ public final static int PPC_RELOC_HA16 = 6;
+
+ /**
+ * Same as the {@link #PPC_RELOC_LO16} except that the low 2 bits are not stored in the
+ * instruction and are always zero. This is used in double word load/store instructions.
+ */
+ public final static int PPC_RELOC_LO14 = 7;
+
+ /**
+ * A {@link #PPC_RELOC_PAIR} follows with subtract symbol value
+ */
+ public final static int PPC_RELOC_SECTDIFF = 8;
+
+ /**
+ * Pre-bound lazy pointer
+ */
+ public final static int PPC_RELOC_PB_LA_PTR = 9;
+
+ /**
+ * A section difference forms of above.
+ * A {@link #PPC_RELOC_PAIR} Follows these with subtract symbol value.
+ */
+ public final static int PPC_RELOC_HI16_SECTDIFF = 10;
+ public final static int PPC_RELOC_LO16_SECTDIFF = 11;
+ public final static int PPC_RELOC_HA16_SECTDIFF = 12;
+ public final static int PPC_RELOC_JBSR = 13;
+ public final static int PPC_RELOC_LO14_SECTDIFF = 14;
+
+ /**
+ * Like {@link #PPC_RELOC_SECTDIFF}, but the symbol referenced was local.
+ */
+ public final static int PPC_RELOC_LOCAL_SECTDIFF = 15;
+}
+
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationHandler.java
new file mode 100644
index 0000000000..d6d308d9e4
--- /dev/null
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/macho/relocation/PowerPC_MachoRelocationHandler.java
@@ -0,0 +1,89 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.util.bin.format.macho.relocation;
+
+import static ghidra.app.util.bin.format.macho.relocation.PowerPC_MachoRelocationConstants.*;
+
+import ghidra.app.util.bin.format.RelocationException;
+import ghidra.app.util.bin.format.macho.*;
+import ghidra.program.model.mem.MemoryAccessException;
+import ghidra.program.model.reloc.RelocationResult;
+
+/**
+ * A {@link MachoRelocationHandler} for PowerPC
+ *
+ * @see mach-o/ppc/reloc.h
+ */
+public class PowerPC_MachoRelocationHandler extends MachoRelocationHandler {
+
+ @Override
+ public boolean canRelocate(MachHeader header) {
+ return header.getCpuType() == CpuTypes.CPU_TYPE_POWERPC;
+ }
+
+ @Override
+ public boolean isPairedRelocation(RelocationInfo relocation) {
+ return switch (relocation.getType()) {
+ case PPC_RELOC_HI16:
+ case PPC_RELOC_LO16:
+ case PPC_RELOC_HA16:
+ case PPC_RELOC_LO14:
+ case PPC_RELOC_SECTDIFF:
+ case PPC_RELOC_HI16_SECTDIFF:
+ case PPC_RELOC_LO16_SECTDIFF:
+ case PPC_RELOC_HA16_SECTDIFF:
+ case PPC_RELOC_JBSR:
+ case PPC_RELOC_LO14_SECTDIFF:
+ case PPC_RELOC_LOCAL_SECTDIFF: {
+ yield true;
+ }
+ default:
+ yield false;
+ };
+ }
+
+ @Override
+ public RelocationResult relocate(MachoRelocation relocation)
+ throws MemoryAccessException, RelocationException {
+
+ if (!relocation.requiresRelocation()) {
+ return RelocationResult.SKIPPED;
+ }
+
+ RelocationInfo relocationInfo = relocation.getRelocationInfo();
+
+ switch (relocationInfo.getType()) {
+ case PPC_RELOC_VANILLA: // not seen yet
+ case PPC_RELOC_PAIR: // not seen yet
+ case PPC_RELOC_BR14: // not seen yet
+ case PPC_RELOC_BR24: // not seen yet
+ case PPC_RELOC_HI16: // not seen yet
+ case PPC_RELOC_LO16: // not seen yet
+ case PPC_RELOC_HA16: // not seen yet
+ case PPC_RELOC_LO14: // not seen yet
+ case PPC_RELOC_SECTDIFF: // not seen yet
+ case PPC_RELOC_PB_LA_PTR: // not seen yet
+ case PPC_RELOC_HI16_SECTDIFF: // not seen yet
+ case PPC_RELOC_LO16_SECTDIFF: // not seen yet
+ case PPC_RELOC_HA16_SECTDIFF: // not seen yet
+ case PPC_RELOC_JBSR: // not seen yet
+ case PPC_RELOC_LO14_SECTDIFF: // not seen yet
+ case PPC_RELOC_LOCAL_SECTDIFF: // not seen yet
+ default:
+ return RelocationResult.UNSUPPORTED;
+ }
+ }
+}