diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec b/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec
index 7e90bd5390..ded16f678d 100644
--- a/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec
+++ b/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec
@@ -87,6 +87,9 @@
+
+
+
@@ -105,7 +108,8 @@
-
+
+
diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec b/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec
index d1699dc0c7..1e36de335d 100644
--- a/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec
+++ b/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec
@@ -87,6 +87,9 @@
+
+
+
@@ -105,7 +108,9 @@
-
+
+
+
diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc b/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc
index 10f0cc691c..3148135f19 100644
--- a/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc
+++ b/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc
@@ -1733,12 +1733,20 @@ define pcodeop stdcixOp;
}
# binutils-descr: "lq", OP(56), OP_MASK, POWER4, PPC476, {RTQ, DQ, RAQ}
-define pcodeop lqOp;
# ISA-cmt: lq - Load Quadword
# ISA-info: lq - Form "DQ" Page 751 Category "LSQ"
# binutils: power4.d: +0: e0 83 00 00 lq r4,0\(r3\)
# binutils: power4.d: +4: e0 83 00 00 lq r4,0\(r3\)
-:lq RT,A,DQ is $(NOTVLE) & OP=56 & RT & A & DQ & BITS_0_3=0 { RT = lqOp(RT,A); }
+:lq RT,A,DQ is $(NOTVLE) & OP=56 & RT & Dp & A & DQ & BITS_0_3=0 & regp [regpset = Dp+1;] {
+ ea:$(REGISTER_SIZE) = A + sext(DQ:2 << 4);
+@if ENDIAN == "big"
+ RT = *:$(REGISTER_SIZE) ea;
+ regp = *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE));
+@else
+ RT = *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE));
+ regp = *:$(REGISTER_SIZE) ea;
+@endif
+}
define pcodeop lvepxOp;
:lvepx RT,A,B is OP=31 & RT & A & B & XOP_1_10=295 & BIT_0=0 { RT = lvepxOp(RT,A,B); }
@@ -2038,7 +2046,6 @@ define pcodeop stfdpOp;
}
# binutils-descr: "stq", DSO(62,2), DS_MASK, POWER4, PPC476, {RSQ, DS, RA0}
-define pcodeop stqOp;
# ISA-cmt: stq - Store Quadword
# ISA-info: stq - Form "DS" Page 751 Category "LSQ"
# binutils: power4.d: +50: f8 c7 00 02 stq r6,0\(r7\)
@@ -2046,9 +2053,15 @@ define pcodeop stqOp;
# binutils: power4.d: +58: f8 c7 ff f2 stq r6,-16\(r7\)
# binutils: power4.d: +5c: f8 c7 80 02 stq r6,-32768\(r7\)
# binutils: power4.d: +60: f8 c7 7f f2 stq r6,32752\(r7\)
-:stq S,RA_OR_ZERO,DS is $(NOTVLE) & OP=62 & S & RA_OR_ZERO & DS & BITS_0_1=2 {
- EA:$(REGISTER_SIZE) = RA_OR_ZERO + sext(DS:2 << 2);
- *:16 EA = stqOp(S,RA_OR_ZERO,DS:2);
+:stq RS,RA_OR_ZERO,DS is $(NOTVLE) & OP=62 & RS & Dp & RA_OR_ZERO & DS & BITS_0_1=2 & regp [regpset = Dp+1;] {
+ ea:$(REGISTER_SIZE) = RA_OR_ZERO + sext(DS:2 << 2);
+@if ENDIAN == "big"
+ *:$(REGISTER_SIZE) ea = RS;
+ *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)) = regp;
+@else
+ *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)) = RS;
+ *:$(REGISTER_SIZE) ea = regp;
+@endif
}
define pcodeop stvepxOp;
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java
index 288615404b..e0f7f9cb5a 100644
--- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java
@@ -47,11 +47,22 @@ public class PowerPC64_ElfExtension extends ElfExtension {
public static final ElfDynamicType DT_PPC64_OPDSZ = new ElfDynamicType(0x70000002,
"DT_PPC64_OPDSZ", "Specify the size of the .opd section", ElfDynamicValueType.ADDRESS);
public static final ElfDynamicType DT_PPC64_OPT = new ElfDynamicType(0x70000003, "DT_PPC64_OPT",
- "Specify whether various optimisations are possible", ElfDynamicValueType.VALUE);
+ "Specify whether various optimizations are possible", ElfDynamicValueType.VALUE);
// PPC64 ABI Version Flag Bits contained within ElfHeader e_flags
private static final int EF_PPC64_ABI = 3;
+ // DT_PPC64_OPT bits
+ private static final int PPC64_OPT_TLS = 1;
+ private static final int PPC64_OPT_MULTI_TOC = 2;
+ private static final int PPC64_OPT_LOCALENTRY = 4;
+
+ // ELFv2 ABI symbol st_other bits
+ // STO_PPC64_LOCAL specifies the number of instructions between a
+ // function's global entry point and local entry point
+ private static final int STO_PPC64_LOCAL_BIT = 5;
+ private static final int STO_PPC64_LOCAL_MASK = 0xE0;
+
public static final String TOC_BASE = "TOC_BASE"; // injected symbol to mark global TOC_BASE
@Override
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java
index 771edcac6b..0b7af29eca 100644
--- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java
@@ -46,6 +46,11 @@ public class PowerPC_ElfExtension extends ElfExtension {
public static final ElfDynamicType DT_PPC_OPT = new ElfDynamicType(0x70000001, "DT_PPC_OPT",
"Specify that tls descriptors should be optimized", ElfDynamicValueType.VALUE);
+ // ELF header flags
+ private static final int EF_PPC_EMB = 0x80000000; // PowerPC embedded flag
+ private static final int EF_PPC_RELOCATABLE = 0x00010000;
+ private static final int EF_PPC_RELOCATABLE_LIB = 0x00008000;
+
// Program header (segment) flags
private static final int PF_PPC_VLE = 0x10000000;
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java
index 5e80f900f0..a0c691b6b1 100644
--- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java
@@ -122,6 +122,44 @@ public class PowerPC64_ElfRelocationConstants {
public static final int R_PPC64_DTPREL16_HIGHEST = 105; // half16 #highest(@dtprel)
public static final int R_PPC64_DTPREL16_HIGHESTA = 106; // half16 #highesta(@dtprel)
+ public static final int R_PPC64_PLTSEQ_NOTOC = 121;
+ public static final int R_PPC64_PLTCALL_NOTOC = 122;
+ public static final int R_PPC64_PCREL_OPT = 123;
+
+ public static final int R_PPC64_D34 = 128;
+ public static final int R_PPC64_D34_LO = 129;
+ public static final int R_PPC64_D34_HI30 = 130;
+ public static final int R_PPC64_D34_HA30 = 131;
+ public static final int R_PPC64_PCREL34 = 132;
+ public static final int R_PPC64_GOT_PCREL34 = 133;
+ public static final int R_PPC64_PLT_PCREL34 = 134;
+ public static final int R_PPC64_PLT_PCREL34_NOTOC = 135;
+ public static final int R_PPC64_ADDR16_HIGHER34 = 136;
+ public static final int R_PPC64_ADDR16_HIGHERA34 = 137;
+ public static final int R_PPC64_ADDR16_HIGHEST34 = 138;
+ public static final int R_PPC64_ADDR16_HIGHESTA34 = 139;
+ public static final int R_PPC64_REL16_HIGHER34 = 140;
+ public static final int R_PPC64_REL16_HIGHERA34 = 141;
+ public static final int R_PPC64_REL16_HIGHEST34 = 142;
+ public static final int R_PPC64_REL16_HIGHESTA34 = 143;
+ public static final int R_PPC64_D28 = 144;
+ public static final int R_PPC64_PCREL28 = 145;
+ public static final int R_PPC64_TPREL34 = 146;
+ public static final int R_PPC64_DTPREL34 = 147;
+ public static final int R_PPC64_GOT_TLSGD_PCREL34 = 148;
+ public static final int R_PPC64_GOT_TLSLD_PCREL34 = 149;
+ public static final int R_PPC64_GOT_TPREL_PCREL34 = 150;
+ public static final int R_PPC64_GOT_DTPREL_PCREL34 = 151;
+
+ public static final int R_PPC64_REL16_HIGH = 240;
+ public static final int R_PPC64_REL16_HIGHA = 241;
+ public static final int R_PPC64_REL16_HIGHER = 242;
+ public static final int R_PPC64_REL16_HIGHERA = 243;
+ public static final int R_PPC64_REL16_HIGHEST = 244;
+ public static final int R_PPC64_REL16_HIGHESTA = 245;
+
+ public static final int R_PPC64_JMP_IREL = 247;
+
// Masks for manipulating Power PC relocation targets
public static final int PPC64_WORD32 = 0xFFFFFFFF;
public static final int PPC64_WORD30 = 0xFFFFFFFC;
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java
index efdaedf5c8..6c3554eae4 100644
--- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java
@@ -58,6 +58,85 @@ public class PowerPC_ElfRelocationConstants {
public static final int R_PPC_SECTOFF_HA = 36; // half16 #ha(R + A)
public static final int R_PPC_ADDR30 = 37; // word30 (S + A - P) >> 2
+ public static final int R_POWERPC_TLS = 67;
+ public static final int R_POWERPC_DTPMOD = 68;
+ public static final int R_POWERPC_TPREL16 = 69;
+ public static final int R_POWERPC_TPREL16_LO = 70;
+ public static final int R_POWERPC_TPREL16_HI = 71;
+ public static final int R_POWERPC_TPREL16_HA = 72;
+ public static final int R_POWERPC_TPREL = 73;
+ public static final int R_POWERPC_DTPREL16 = 74;
+ public static final int R_POWERPC_DTPREL16_LO = 75;
+ public static final int R_POWERPC_DTPREL16_HI = 76;
+ public static final int R_POWERPC_DTPREL16_HA = 77;
+ public static final int R_POWERPC_DTPREL = 78;
+ public static final int R_POWERPC_GOT_TLSGD16 = 79;
+ public static final int R_POWERPC_GOT_TLSGD16_LO = 80;
+ public static final int R_POWERPC_GOT_TLSGD16_HI = 81;
+ public static final int R_POWERPC_GOT_TLSGD16_HA = 82;
+ public static final int R_POWERPC_GOT_TLSLD16 = 83;
+ public static final int R_POWERPC_GOT_TLSLD16_LO = 84;
+ public static final int R_POWERPC_GOT_TLSLD16_HI = 85;
+ public static final int R_POWERPC_GOT_TLSLD16_HA = 86;
+ public static final int R_POWERPC_GOT_TPREL16 = 87;
+ public static final int R_POWERPC_GOT_TPREL16_LO = 88;
+ public static final int R_POWERPC_GOT_TPREL16_HI = 89;
+ public static final int R_POWERPC_GOT_TPREL16_HA = 90;
+ public static final int R_POWERPC_GOT_DTPREL16 = 91;
+ public static final int R_POWERPC_GOT_DTPREL16_LO = 92;
+ public static final int R_POWERPC_GOT_DTPREL16_HI = 93;
+ public static final int R_POWERPC_GOT_DTPREL16_HA = 94;
+ public static final int R_PPC_TLSGD = 95;
+ public static final int R_PPC_TLSLD = 96;
+
+ public static final int R_PPC_EMB_NADDR32 = 101; // uword32 (A - S)
+ public static final int R_PPC_EMB_NADDR16 = 102; // uhalf16 (A - S)
+ public static final int R_PPC_EMB_NADDR16_LO = 103; // uhalf16 #lo(A - S)
+ public static final int R_PPC_EMB_NADDR16_HI = 104; // uhalf16 #hi(A - S)
+ public static final int R_PPC_EMB_NADDR16_HA = 105; // uhalf16 #ha(A - S)
+ public static final int R_PPC_EMB_SDAI16 = 106; // uhalf16 T
+ public static final int R_PPC_EMB_SDA2I16 = 107; // uhalf16 U
+ public static final int R_PPC_EMB_SDA2REL = 108; // uhalf16 S + A - _SDA2_BASE_
+ public static final int R_PPC_EMB_SDA21 = 109; // ulow21
+ public static final int R_PPC_EMB_MRKREF = 110; // none
+ public static final int R_PPC_EMB_RELSEC16 = 111; // uhalf16 V + A
+ public static final int R_PPC_EMB_RELST_LO = 112; // uhalf16 #lo(W + A)
+ public static final int R_PPC_EMB_RELST_HI = 113; // uhalf16 #hi(W + A)
+ public static final int R_PPC_EMB_RELST_HA = 114; // uhalf16 #ha(W + A)
+ public static final int R_PPC_EMB_BIT_FLD = 115; // uword32
+ public static final int R_PPC_EMB_RELSDA = 116; // uhalf16
+
+ public static final int R_POWERPC_PLTSEQ = 119;
+ public static final int R_POWERPC_PLTCALL = 120;
+
+ public static final int R_PPC_VLE_REL8 = 216;
+ public static final int R_PPC_VLE_REL15 = 217;
+ public static final int R_PPC_VLE_REL24 = 218;
+ public static final int R_PPC_VLE_LO16A = 219;
+ public static final int R_PPC_VLE_LO16D = 220;
+ public static final int R_PPC_VLE_HI16A = 221;
+ public static final int R_PPC_VLE_HI16D = 222;
+ public static final int R_PPC_VLE_HA16A = 223;
+ public static final int R_PPC_VLE_HA16D = 224;
+ public static final int R_PPC_VLE_SDA21 = 225;
+ public static final int R_PPC_VLE_SDA21_LO = 226;
+ public static final int R_PPC_VLE_SDAREL_LO16A = 227;
+ public static final int R_PPC_VLE_SDAREL_LO16D = 228;
+ public static final int R_PPC_VLE_SDAREL_HI16A = 229;
+ public static final int R_PPC_VLE_SDAREL_HI16D = 230;
+ public static final int R_PPC_VLE_SDAREL_HA16A = 231;
+ public static final int R_PPC_VLE_SDAREL_HA16D = 232;
+
+ public static final int R_POWERPC_REL16DX_HA = 246;
+ public static final int R_POWERPC_IRELATIVE = 248;
+ public static final int R_POWERPC_REL16 = 249;
+ public static final int R_POWERPC_REL16_LO = 250;
+ public static final int R_POWERPC_REL16_HI = 251;
+ public static final int R_POWERPC_REL16_HA = 252;
+ public static final int R_POWERPC_GNU_VTINHERIT = 253;
+ public static final int R_POWERPC_GNU_VTENTRY = 254;
+ public static final int R_PPC_TOC16 = 255;
+
// Masks for manipulating Power PC relocation targets
public static final int PPC_WORD32 = 0xFFFFFFFF;
public static final int PPC_WORD30 = 0xFFFFFFFC;
diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java
index 87b62bfb14..5fde5de741 100644
--- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java
+++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java
@@ -15,14 +15,22 @@
*/
package ghidra.app.util.bin.format.elf.relocation;
+import java.math.BigInteger;
+import java.util.Map;
+
+import com.google.common.base.Predicate;
+
import ghidra.app.util.bin.format.elf.*;
import ghidra.app.util.bin.format.elf.extend.PowerPC_ElfExtension;
-import ghidra.program.model.address.Address;
+import ghidra.app.util.importer.MessageLog;
+import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language;
+import ghidra.program.model.lang.Register;
+import ghidra.program.model.listing.ContextChangeException;
import ghidra.program.model.listing.Program;
-import ghidra.program.model.mem.Memory;
-import ghidra.program.model.mem.MemoryAccessException;
-import ghidra.util.exception.NotFoundException;
+import ghidra.program.model.mem.*;
+import ghidra.program.model.symbol.*;
+import ghidra.util.exception.*;
public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
@@ -31,16 +39,25 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
return elf.e_machine() == ElfConstants.EM_PPC && elf.is32Bit();
}
+ @Override
+ public PowerPC_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
+ ElfRelocationTable relocationTable, Map symbolMap) {
+ return new PowerPC_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
+ }
+
@Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException {
- ElfHeader elf = elfRelocationContext.getElfHeader();
+ PowerPC_ElfRelocationContext ppcRelocationContext =
+ (PowerPC_ElfRelocationContext) elfRelocationContext;
+
+ ElfHeader elf = ppcRelocationContext.getElfHeader();
if (elf.e_machine() != ElfConstants.EM_PPC || !elf.is32Bit()) {
return;
}
- Program program = elfRelocationContext.getProgram();
+ Program program = ppcRelocationContext.getProgram();
Memory memory = program.getMemory();
int type = relocation.getType();
@@ -49,12 +66,12 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
}
int symbolIndex = relocation.getSymbolIndex();
- Language language = elfRelocationContext.getProgram().getLanguage();
+ Language language = ppcRelocationContext.getProgram().getLanguage();
if (!"PowerPC".equals(language.getProcessor().toString()) ||
language.getLanguageDescription().getSize() != 32) {
markAsError(program, relocationAddress, Long.toString(type), null,
"Unsupported language for 32-bit PowerPC relocation",
- elfRelocationContext.getLog());
+ ppcRelocationContext.getLog());
}
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
@@ -72,7 +89,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
//
// // Relocation addend already includes original symbol value but needs to account
// // for any image base adjustment
-// symbolValue = (int) elfRelocationContext.getImageBaseWordAdjustmentOffset();
+// symbolValue = (int) ppcRelocationContext.getImageBaseWordAdjustmentOffset();
// }
// else {
Address symbolAddr = (elfRelocationContext.getSymbolAddress(sym));
@@ -162,7 +179,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
memory.setInt(relocationAddress, newValue);
break;
case PowerPC_ElfRelocationConstants.R_PPC_RELATIVE:
- newValue = (int) elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
+ newValue = (int) ppcRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
memory.setInt(relocationAddress, newValue);
break;
case PowerPC_ElfRelocationConstants.R_PPC_REL32:
@@ -202,15 +219,200 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
// not too far away since a fabricated GOT would be in the same block
// and we may only have room in the plt for two instructions.
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
- elfRelocationContext.getLog());
+ ppcRelocationContext.getLog());
}
break;
+ case PowerPC_ElfRelocationConstants.R_PPC_EMB_SDA21:
+ // NOTE: PPC EABI V1.0 specifies this relocation on a 24-bit field address while
+ // GNU assumes a 32-bit field address. We cope with this difference by
+ // forcing a 32-bit alignment of the relocation address.
+ long alignedRelocOffset = relocationAddress.getOffset() & ~3;
+ relocationAddress = relocationAddress.getNewAddress(alignedRelocOffset);
+
+ oldValue = memory.getInt(relocationAddress);
+
+ Address symAddr = ppcRelocationContext.getSymbolAddress(sym);
+ MemoryBlock block = memory.getBlock(symAddr);
+ Integer sdaBase = null;
+ Integer gprID = null;
+
+ if (block != null) {
+ String blockName = block.getName();
+ if (".sdata".equals(blockName) || ".sbss".equals(blockName)) {
+ sdaBase = ppcRelocationContext.getSDABase();
+ gprID = 13;
+ }
+ else if (".sdata2".equals(blockName) || ".sbss2".equals(blockName)) {
+ sdaBase = ppcRelocationContext.getSDA2Base();
+ gprID = 2;
+ }
+ else if (".PPC.EMB.sdata0".equals(blockName) ||
+ ".PPC.EMB.sbss0".equals(blockName)) {
+ sdaBase = 0;
+ gprID = 0;
+ }
+ else if (MemoryBlock.EXTERNAL_BLOCK_NAME.equals(blockName)) {
+ markAsError(program, relocationAddress, type, sym.getNameAsString(),
+ "Unsupported relocation for external symbol",
+ ppcRelocationContext.getLog());
+ break;
+ }
+ }
+ if (gprID == null || sdaBase == null) {
+ markAsError(program, relocationAddress, type, sym.getNameAsString(),
+ "Failed to identfy appropriate data block", ppcRelocationContext.getLog());
+ break;
+ }
+
+ newValue = (symbolValue - sdaBase + addend) & 0xffff;
+ newValue |= gprID << 16;
+ newValue |= oldValue & 0xffe00000;
+ memory.setInt(relocationAddress, newValue);
+ break;
+
default:
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
- elfRelocationContext.getLog());
+ ppcRelocationContext.getLog());
break;
}
+ }
+
+ /**
+ * PowerPC_ElfRelocationContext provides extended relocation context..
+ */
+ private static class PowerPC_ElfRelocationContext extends ElfRelocationContext {
+
+ private Integer sdaBase;
+ private Integer sda2Base;
+
+ protected PowerPC_ElfRelocationContext(ElfRelocationHandler handler,
+ ElfLoadHelper loadHelper, ElfRelocationTable relocationTable,
+ Map symbolMap) {
+ super(handler, loadHelper, relocationTable, symbolMap);
+ }
+
+ /**
+ * Get or establish _SDA_BASE_ value and apply as r13 context value to all memory blocks
+ * with execute permission.
+ * @return _SDA_BASE_ offset or null if unable to determine or establish
+ */
+ Integer getSDABase() {
+ if (sdaBase != null) {
+ if (sdaBase == -1) {
+ return null;
+ }
+ return sdaBase;
+ }
+ sdaBase = getBaseOffset("_SDA_BASE_", ".sdata", ".sbss");
+ if (sdaBase == -1) {
+ getLog().appendMsg("ERROR: failed to establish _SDA_BASE_");
+ return null;
+ }
+ setRegisterContext("r13", BigInteger.valueOf(sdaBase), b -> b.isExecute());
+ return sdaBase;
+ }
+
+ /**
+ * Get or establish _SDA2_BASE_ value and apply as r2 context value to all memory blocks
+ * with execute permission.
+ * @return _SDA2_BASE_ offset or null if unable to determine or establish
+ */
+ Integer getSDA2Base() {
+ if (sda2Base != null) {
+ if (sda2Base == -1) {
+ return null;
+ }
+ return sda2Base;
+ }
+ sda2Base = getBaseOffset("_SDA2_BASE_", ".sdata2", ".sbss2");
+ if (sda2Base == -1) {
+ getLog().appendMsg("ERROR: failed to establish _SDA2_BASE_");
+ return null;
+ }
+ setRegisterContext("r2", BigInteger.valueOf(sda2Base), b -> b.isExecute());
+ return sda2Base;
+ }
+
+ /**
+ * Apply register context to all memory blocks which satisfy blockPredicate check.
+ * @param regName register name
+ * @param value context value
+ * @param blockPredicate determine which memory blocks get context applied
+ */
+ private void setRegisterContext(String regName, BigInteger value,
+ Predicate blockPredicate) {
+ Register reg = program.getRegister(regName);
+ for (MemoryBlock block : program.getMemory().getBlocks()) {
+ if (block.isExecute()) {
+ try {
+ program.getProgramContext().setValue(reg, block.getStart(), block.getEnd(),
+ value);
+ }
+ catch (ContextChangeException e) {
+ throw new AssertException(e); // no instructions should exist yet
+ }
+ }
+ }
+ }
+
+ /**
+ * Establish base offset from symbol or range of specified memory blocks.
+ * @param symbolName base symbol name
+ * @param blockNames block names which may be used to establish base range
+ * @return base offset or -1 on failure
+ */
+ private Integer getBaseOffset(String symbolName, String... blockNames) {
+
+ MessageLog log = getLog();
+
+ Symbol baseSymbol = SymbolUtilities.getLabelOrFunctionSymbol(program, symbolName,
+ msg -> log.appendMsg(msg));
+ if (baseSymbol != null) {
+ int baseOffset = (int) baseSymbol.getAddress().getOffset();
+ String absString = "";
+ if (baseSymbol.isPinned()) {
+ absString = "absolute ";
+ }
+ log.appendMsg(
+ "Using " + absString + symbolName + " of 0x" + Integer.toHexString(baseOffset));
+ return baseOffset;
+ }
+
+ Memory mem = program.getMemory();
+ AddressSpace defaultSpace = program.getAddressFactory().getDefaultAddressSpace();
+ AddressSet blockSet = new AddressSet();
+ for (String blockName : blockNames) {
+ MemoryBlock block = mem.getBlock(blockName);
+ if (block != null) {
+ if (!block.getStart().getAddressSpace().equals(defaultSpace)) {
+ log.appendMsg("ERROR: " + blockName + " not in default space");
+ return -1;
+ }
+ blockSet.add(block.getStart(), block.getEnd());
+ }
+ }
+ if (blockSet.isEmpty()) {
+ return -1;
+ }
+
+ Address baseAddr = blockSet.getMinAddress();
+ long range = blockSet.getMaxAddress().subtract(baseAddr) + 1;
+ if (range > Short.MAX_VALUE) {
+ // use aligned midpoint of range
+ baseAddr = baseAddr.add((range / 2) & ~0x0f);
+ }
+
+ try {
+ program.getSymbolTable().createLabel(baseAddr, symbolName, SourceType.ANALYSIS);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertException(e);
+ }
+
+ int baseOffset = (int) baseAddr.getOffset();
+ log.appendMsg("Defined " + symbolName + " of 0x" + Integer.toHexString(baseOffset));
+ return baseOffset;
+ }
}
-
}