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; + } + } +}