diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java
new file mode 100644
index 0000000000..2f260c0159
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java
@@ -0,0 +1,294 @@
+/* ###
+ * 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.elf.relocation;
+
+import java.util.*;
+
+import ghidra.app.util.MemoryBlockUtils;
+import ghidra.app.util.bin.format.elf.*;
+import ghidra.program.model.address.*;
+import ghidra.program.model.data.PointerDataType;
+import ghidra.program.model.mem.MemoryAccessException;
+import ghidra.program.model.mem.MemoryBlock;
+import ghidra.util.*;
+import ghidra.util.exception.InvalidInputException;
+import ghidra.util.exception.NotFoundException;
+
+/**
+ * ElfGotRelocationContext
provides ability to generate a
+ * Global Offset Table (GOT) to facilitate GOT related relocations encountered within
+ * object modules.
+ *
+ * NOTE: This should be considered experimental and has its limitations with GOT size and
+ * placement which could behave improperly for large binaries.
+ *
+ * @param ELF relocation handler class
+ */
+public abstract class ElfGotRelocationContext
+ extends ElfRelocationContext {
+
+ private AddressRange allocatedGotLimits;
+ private Address allocatedGotAddress;
+ private Address lastAllocatedGotEntryAddress;
+ private Address nextAllocatedGotEntryAddress;
+
+ private Map gotMap;
+
+ ElfGotRelocationContext(H handler, ElfLoadHelper loadHelper,
+ Map symbolMap) {
+ super(handler, loadHelper, symbolMap);
+ }
+
+ @Override
+ public long getSymbolValue(ElfSymbol symbol) {
+ long symbolValue = super.getSymbolValue(symbol);
+ if (symbolValue == 0 && ElfConstants.GOT_SYMBOL_NAME.equals(symbol.getNameAsString())) {
+ Address gotAddr = symbolMap.get(symbol);
+ if (gotAddr == null) {
+ gotAddr = allocateGot();
+ }
+ if (gotAddr != null) {
+ return gotAddr.getOffset();
+ }
+ }
+ return symbolValue;
+ }
+
+ @Override
+ public long getGOTValue() throws NotFoundException {
+ try {
+ return super.getGOTValue();
+ }
+ catch (NotFoundException e) {
+ Address gotAddr = allocateGot();
+ if (gotAddr != null) {
+ return gotAddr.getOffset();
+ }
+ throw e;
+ }
+ }
+
+ private ElfSymbol findGotElfSymbol() {
+ for (ElfSymbolTable st : getElfHeader().getSymbolTables()) {
+ for (ElfSymbol s : st.getSymbols()) {
+ if (ElfConstants.GOT_SYMBOL_NAME.equals(s.getNameAsString())) {
+ return s;
+ }
+ }
+ }
+ return null;
+ }
+
+ private int computeRequiredGotSize() {
+ // NOTE: GOT allocation calculation assumes all GOT entries correspond to a specific
+ // symbol and not a computed offset. This assumption may need to be revised based upon
+ // uses of getGotEntryAddress method
+ Set uniqueSymbolValues = new HashSet<>();
+ for (ElfRelocationTable rt : getElfHeader().getRelocationTables()) {
+ ElfSymbolTable st = rt.getAssociatedSymbolTable();
+ if (st == null) {
+ continue;
+ }
+ for (ElfRelocation r : rt.getRelocations()) {
+ int symbolIndex = r.getSymbolIndex();
+ if (!requiresGotEntry(r) || symbolIndex == 0) {
+ continue;
+ }
+ ElfSymbol elfSymbol = st.getSymbol(symbolIndex);
+ if (elfSymbol == null) {
+ continue;
+ }
+ long symbolValue = getSymbolValue(elfSymbol);
+ if (!uniqueSymbolValues.add(symbolValue)) {
+ System.out.println("Duplicate sym value 0x" + Long.toHexString(symbolValue) +
+ " for " + elfSymbol.getNameAsString());
+ }
+ }
+ }
+ return Math.max(8, uniqueSymbolValues.size() * 8);
+ }
+
+ /**
+ * {@return true if the specified relocation type requires a GOT entry.}
+ *
+ * NOTE: It is very important that all relocations types which invoke
+ * {@link #getGotEntryAddress(ElfSymbol)} result in this method returning true. Failure to
+ * do so could result in an under allocation of the GOT memory block.
+ * @param r relocation type
+ */
+ protected abstract boolean requiresGotEntry(ElfRelocation r);
+
+ private Address allocateGot() {
+
+ if (allocatedGotAddress != null) {
+ if (allocatedGotAddress == Address.NO_ADDRESS) {
+ return null;
+ }
+ return allocatedGotAddress;
+ }
+
+ allocatedGotAddress = Address.NO_ADDRESS;
+ nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
+
+ ElfSymbol gotElfSymbol = findGotElfSymbol();
+
+ if (gotElfSymbol == null && !getElfHeader().isRelocatable()) {
+ loadHelper
+ .log("GOT allocatiom failed. " + ElfConstants.GOT_SYMBOL_NAME + " not defined");
+ return null;
+ }
+
+ if (gotElfSymbol != null && gotElfSymbol.getValue() != 0) {
+ loadHelper.log(
+ "GOT allocatiom failed. " + ElfConstants.GOT_SYMBOL_NAME + " already defined");
+ return null;
+ }
+
+ int alignment = getLoadAdapter().getLinkageBlockAlignment();
+ int gotSize = computeRequiredGotSize();
+ allocatedGotLimits = getLoadHelper().allocateLinkageBlock(alignment, gotSize,
+ ElfRelocationHandler.GOT_BLOCK_NAME);
+ if (allocatedGotLimits != null &&
+ allocatedGotLimits.getMinAddress().getOffset() < Integer.MAX_VALUE) {
+ // NOTE: GOT must fall within first 32-bit segment
+ if (gotElfSymbol != null) {
+ // remember where GOT was allocated
+ try {
+ loadHelper.createSymbol(allocatedGotLimits.getMinAddress(),
+ ElfConstants.GOT_SYMBOL_NAME, true, false, null);
+ }
+ catch (InvalidInputException e) {
+ throw new AssertionError("Unexpected exception", e);
+ }
+ symbolMap.put(gotElfSymbol, allocatedGotLimits.getMinAddress());
+ }
+ allocatedGotAddress = allocatedGotLimits.getMinAddress();
+ nextAllocatedGotEntryAddress = allocatedGotAddress;
+ gotMap = new HashMap<>();
+ loadHelper.log("Created " + ElfRelocationHandler.GOT_BLOCK_NAME +
+ " block required for GOT relocation processing");
+ return allocatedGotAddress;
+ }
+
+ loadHelper.log("Failed to allocate GOT block required for relocation processing");
+ return null;
+ }
+
+ /**
+ * Allocate the next section GOT entry location. If GOT has not been allocated an attempt
+ * will be made to create one. If allocated gotMap will also be established.
+ * @return Address of GOT entry or {@link Address#NO_ADDRESS} if unable to allocate.
+ */
+ private Address getNextAllocatedGotEntryAddress() {
+ if (nextAllocatedGotEntryAddress == null) {
+ if (allocateGot() == null) {
+ return Address.NO_ADDRESS; // failed to allocate got
+ }
+ }
+
+ Address addr = nextAllocatedGotEntryAddress;
+ if (addr == Address.NO_ADDRESS) {
+ return Address.NO_ADDRESS; // insufficient space in got
+ }
+
+ try {
+ // verify that entry fits in got
+ int pointerSize = loadHelper.getProgram().getDefaultPointerSize();
+ Address lastAddr = nextAllocatedGotEntryAddress.addNoWrap(pointerSize - 1);
+ if (allocatedGotLimits.contains(lastAddr)) {
+ // entry fits in got - update and return entry address
+ lastAllocatedGotEntryAddress = lastAddr;
+ nextAllocatedGotEntryAddress = lastAllocatedGotEntryAddress.addNoWrap(1);
+ if (!allocatedGotLimits.contains(nextAllocatedGotEntryAddress)) {
+ // allocated got space fully consumed
+ nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
+ }
+ return addr;
+ }
+ }
+ catch (AddressOverflowException e) {
+ // ignore
+ }
+
+ // insufficient space in got - fail future allocation attempts
+ nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
+ return Address.NO_ADDRESS;
+ }
+
+ /**
+ * Get or allocate a GOT entry for the specified symbolValue.
+ * NOTE: This is restricted to object modules only which do not of a GOT.
+ * @param elfSymbol ELF symbol
+ * @return GOT entry address or null if unable to allocate
+ */
+ public Address getGotEntryAddress(ElfSymbol elfSymbol) {
+ long symbolValue = getSymbolValue(elfSymbol);
+ Address addr = null;
+ if (gotMap != null) {
+ addr = gotMap.get(symbolValue);
+ }
+ if (addr == null) {
+ addr = getNextAllocatedGotEntryAddress();
+ if (gotMap != null) {
+ gotMap.put(symbolValue, addr);
+ }
+ }
+ return addr == Address.NO_ADDRESS ? null : addr;
+ }
+
+ /**
+ * Flush the section GOT table to a new %got memory block
+ */
+ private void createGot() {
+ if (lastAllocatedGotEntryAddress == null) {
+ return;
+ }
+ int size = (int) lastAllocatedGotEntryAddress.subtract(allocatedGotAddress) + 1;
+ try {
+ MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false,
+ ElfRelocationHandler.GOT_BLOCK_NAME, allocatedGotAddress, size,
+ "NOTE: This block is artificial and allows ELF Relocations to work correctly",
+ "Elf Loader", true, false, false, loadHelper.getLog());
+
+ // Mark block as an artificial fabrication
+ block.setArtificial(true);
+
+ DataConverter converter =
+ program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE
+ : LittleEndianDataConverter.INSTANCE;
+ for (long symbolValue : gotMap.keySet()) {
+ Address addr = gotMap.get(symbolValue);
+ byte[] bytes = converter.getBytes(symbolValue); // 8-byte pointer value
+ block.putBytes(addr, bytes);
+ loadHelper.createData(addr, PointerDataType.dataType);
+ }
+ }
+ catch (MemoryAccessException e) {
+ String msg = "Failed to create GOT at " + allocatedGotAddress;
+ loadHelper.log(msg);
+ Msg.error(this, msg, e);
+ }
+ }
+
+ @Override
+ public void dispose() {
+
+ // Generate the object module GOT table if required
+ createGot();
+
+ super.dispose();
+ }
+}
diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java
new file mode 100644
index 0000000000..1f19733a36
--- /dev/null
+++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java
@@ -0,0 +1,62 @@
+/* ###
+ * 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.elf.relocation;
+
+import java.util.Map;
+
+import ghidra.app.util.bin.format.elf.*;
+import ghidra.program.model.address.Address;
+
+/**
+ * AARCH64_ElfRelocationContext
provides ability to generate a
+ * Global Offset Table (GOT) to facilitate GOT related relocations encountered within
+ * object modules.
+ */
+class AARCH64_ElfRelocationContext extends ElfGotRelocationContext {
+
+ AARCH64_ElfRelocationContext(AARCH64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
+ Map symbolMap) {
+ super(handler, loadHelper, symbolMap);
+ }
+
+ @Override
+ protected boolean requiresGotEntry(ElfRelocation r) {
+
+ AARCH64_ElfRelocationType type = handler.getRelocationType(r.getType());
+ if (type == null) {
+ return false;
+ }
+
+ switch (type) {
+
+ // NOTE: There are many more relocation types that require a GOT allocation.
+ //@formatter:off
+
+ //case R_AARCH64_P32_GOT_LD_PREL19:
+ case R_AARCH64_P32_ADR_GOT_PAGE:
+ case R_AARCH64_P32_LD32_GOT_LO12_NC:
+ //case R_AARCH64_P32_LD32_GOTPAGE_LO14:
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ return true;
+
+ //@formatter:on
+ default:
+ return false;
+ }
+ }
+
+}
diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java
index aec97b4af7..3e8cb5e6e7 100644
--- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java
+++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java
@@ -4,9 +4,9 @@
* 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.
@@ -15,6 +15,8 @@
*/
package ghidra.app.util.bin.format.elf.relocation;
+import java.util.Map;
+
import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.bin.format.elf.*;
@@ -25,8 +27,8 @@ import ghidra.program.model.mem.*;
import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.reloc.RelocationResult;
-public class AARCH64_ElfRelocationHandler
- extends AbstractElfRelocationHandler> {
+public class AARCH64_ElfRelocationHandler extends
+ AbstractElfRelocationHandler {
/**
* Constructor
@@ -46,11 +48,17 @@ public class AARCH64_ElfRelocationHandler
}
@Override
- protected RelocationResult relocate(ElfRelocationContext> elfRelocationContext,
+ public AARCH64_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
+ Map symbolMap) {
+ return new AARCH64_ElfRelocationContext(this, loadHelper, symbolMap);
+ }
+
+ @Override
+ protected RelocationResult relocate(AARCH64_ElfRelocationContext elfRelocationContext,
ElfRelocation relocation, AARCH64_ElfRelocationType type, Address relocationAddress,
ElfSymbol sym, Address symbolAddr, long symbolValue, String symbolName)
throws MemoryAccessException {
-
+
Program program = elfRelocationContext.getProgram();
Memory memory = program.getMemory();
boolean isBigEndianInstructions =
@@ -58,13 +66,13 @@ public class AARCH64_ElfRelocationHandler
long addend = relocation.getAddend(); // will be 0 for REL case
long offset = relocationAddress.getOffset();
-
+
int symbolIndex = relocation.getSymbolIndex();
boolean is64bit = true;
boolean overflowCheck = true; // *_NC type relocations specify "no overflow check"
long newValue = 0;
int byteLength = 4; // most relocations affect 4-bytes (change if different)
-
+
// Handle relative relocations that do not require symbolAddr or symbolValue
switch (type) {
case R_AARCH64_P32_RELATIVE:
@@ -84,7 +92,7 @@ public class AARCH64_ElfRelocationHandler
default:
break;
}
-
+
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
return RelocationResult.FAILURE;
@@ -308,8 +316,7 @@ public class AARCH64_ElfRelocationHandler
// LD/ST64: (S+A) & 0xff8
case R_AARCH64_LDST64_ABS_LO12_NC:
- case R_AARCH64_P32_LDST64_ABS_LO12_NC:
- case R_AARCH64_LD64_GOT_LO12_NC: {
+ case R_AARCH64_P32_LDST64_ABS_LO12_NC: {
int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions);
newValue = (int) ((symbolValue + addend) & 0xff8) >> 3;
@@ -330,6 +337,53 @@ public class AARCH64_ElfRelocationHandler
break;
}
+ // ADRP: Page(G(GDAT(S)))-Page(P)
+ // Page of GOT entry address for S minus page of relocation address
+ // Set the immediate value of an ADRP to bits [32:12] of X
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_P32_ADR_GOT_PAGE: {
+ int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions);
+ Address symbolGotAddress = elfRelocationContext.getGotEntryAddress(sym);
+ if (symbolGotAddress == null) {
+ markAsError(program, relocationAddress, type, symbolName, symbolIndex,
+ "GOT allocation failure", elfRelocationContext.getLog());
+ return RelocationResult.FAILURE;
+ }
+ newValue = page(symbolGotAddress.getOffset()) - page(relocationAddress.getOffset());
+ newValue = (newValue & 0x1fffff000L) >>> 12;
+ int loBits = (int) newValue & 0x3;
+ int hiBits = (int) newValue >>> 2;
+
+ newValue = (oldValue & 0x9f00001fL) | (loBits << 29) | (hiBits << 5);
+ memory.setInt(relocationAddress, (int) newValue, isBigEndianInstructions);
+ break;
+ }
+
+ // LD/ST: G(GDAT(S))
+ case R_AARCH64_P32_LD32_GOT_LO12_NC: // Set the LD/ST immediate field to bits [11:2] of X
+ case R_AARCH64_LD64_GOT_LO12_NC: // Set the LD/ST immediate field to bits [11:3] of X
+ {
+ int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions);
+ Address symbolGotAddress = elfRelocationContext.getGotEntryAddress(sym);
+ if (symbolGotAddress == null) {
+ markAsError(program, relocationAddress, type, symbolName, symbolIndex,
+ "GOT allocation failure", elfRelocationContext.getLog());
+ return RelocationResult.FAILURE;
+ }
+ int lo12bits = (int) (symbolGotAddress.getOffset() & 0xfff);
+ if (type == AARCH64_ElfRelocationType.R_AARCH64_P32_LD32_GOT_LO12_NC) {
+ lo12bits &= ~0x3;
+ }
+ else {
+ lo12bits &= ~0x7;
+ }
+
+ // Bits [21:10] — imm12: 12-bit unsigned immediate offset
+ newValue = (oldValue & 0xffc003ffL) | (lo12bits << 10);
+ memory.setInt(relocationAddress, (int) newValue, isBigEndianInstructions);
+ break;
+ }
+
case R_AARCH64_P32_GLOB_DAT:
is64bit = false;
case R_AARCH64_GLOB_DAT: {
@@ -379,6 +433,10 @@ public class AARCH64_ElfRelocationHandler
return new RelocationResult(Status.APPLIED, byteLength);
}
+ private long page(long offset) {
+ return offset & ~0xfff;
+ }
+
/**
* Set the new value in memory
* @param memory memory
diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java
index 8b990df668..2a668a0f50 100644
--- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java
+++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java
@@ -4,9 +4,9 @@
* 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.
@@ -17,6 +17,17 @@ package ghidra.app.util.bin.format.elf.relocation;
public enum AARCH64_ElfRelocationType implements ElfRelocationType {
+ // Comment macros:
+ // S - symbol address
+ // A - addend
+ // P - relocation address
+ // X - result of a relocation operation
+ // PG(expr) = Page(expr) = expr & ~0xFFF
+ // G(expr) = Address of GOT entry corresponding to expr
+ // GDAT(expr) = GOT entry for expression expr value
+ //
+ // Reference: https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+
R_AARCH64_NONE(0),
R_AARCH64_P32_ABS32(1), // .word: (S+A)
R_AARCH64_P32_ABS16(2), // .half: (S+A)
@@ -40,10 +51,10 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType {
R_AARCH64_P32_JUMP26(20), // B: ((S+A-P) >> 2) & 0x3ffffff.
R_AARCH64_P32_CALL26(21), // BL: ((S+A-P) >> 2) & 0x3ffffff.
- R_AARCH64_P32_GOT_LD_PREL19(25),
- R_AARCH64_P32_ADR_GOT_PAGE(26),
- R_AARCH64_P32_LD32_GOT_LO12_NC(27),
- R_AARCH64_P32_LD32_GOTPAGE_LO14(28),
+ R_AARCH64_P32_GOT_LD_PREL19(25), // G(GDAT(S))- P
+ R_AARCH64_P32_ADR_GOT_PAGE(26), // ADRP: Page(G(GDAT(S)))-Page(P)
+ R_AARCH64_P32_LD32_GOT_LO12_NC(27), // LD/ST: G(GDAT(S))
+ R_AARCH64_P32_LD32_GOTPAGE_LO14(28), // LD/ST: G(GDAT(S))-Page(GOT)
R_AARCH64_P32_TLSGD_ADR_PREL21(80),
R_AARCH64_P32_TLSGD_ADR_PAGE21(81),
@@ -82,9 +93,9 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType {
R_AARCH64_P32_TLSDESC_ADD_LO12_NC(126),
R_AARCH64_P32_TLSDESC_CALL(127),
- R_AARCH64_P32_COPY(180), // Copy symbol at runtime.
- R_AARCH64_P32_GLOB_DAT(181), // Create GOT entry.
- R_AARCH64_P32_JUMP_SLOT(182), // Create PLT entry.
+ R_AARCH64_P32_COPY(180), // Copy symbol value at runtime.
+ R_AARCH64_P32_GLOB_DAT(181), // Relocate GOT entry.
+ R_AARCH64_P32_JUMP_SLOT(182), // Relocate PLT entry.
// Adjust by program base.
R_AARCH64_P32_RELATIVE(183),
@@ -127,28 +138,28 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType {
R_AARCH64_LDST16_ABS_LO12_NC(284), // LD/ST16: (S+A) & 0xffe
R_AARCH64_LDST32_ABS_LO12_NC(285), // LD/ST32: (S+A) & 0xffc
R_AARCH64_LDST64_ABS_LO12_NC(286), // LD/ST64: (S+A) & 0xff8
- R_AARCH64_MOVW_PREL_G0(287),
- R_AARCH64_MOVW_PREL_G0_NC(288),
- R_AARCH64_MOVW_PREL_G1(289),
- R_AARCH64_MOVW_PREL_G1_NC(290),
- R_AARCH64_MOVW_PREL_G2(291),
- R_AARCH64_MOVW_PREL_G2_NC(292),
- R_AARCH64_MOVW_PREL_G3(293),
+ R_AARCH64_MOVW_PREL_G0(287), // S+A-P
+ R_AARCH64_MOVW_PREL_G0_NC(288), // S+A-P
+ R_AARCH64_MOVW_PREL_G1(289), // S+A-P
+ R_AARCH64_MOVW_PREL_G1_NC(290), // S+A-P
+ R_AARCH64_MOVW_PREL_G2(291), // S+A-P
+ R_AARCH64_MOVW_PREL_G2_NC(292), // S+A-P
+ R_AARCH64_MOVW_PREL_G3(293), // S+A-P
R_AARCH64_LDST128_ABS_LO12_NC(299), // LD/ST128: (S+A) & 0xff0
- R_AARCH64_MOVW_GOTOFF_G0(300),
- R_AARCH64_MOVW_GOTOFF_G0_NC(301),
- R_AARCH64_MOVW_GOTOFF_G1(302),
- R_AARCH64_MOVW_GOTOFF_G1_NC(303),
- R_AARCH64_MOVW_GOTOFF_G2(304),
- R_AARCH64_MOVW_GOTOFF_G2_NC(305),
- R_AARCH64_MOVW_GOTOFF_G3(306),
- R_AARCH64_GOTREL64(307),
- R_AARCH64_GOTREL32(308),
- R_AARCH64_GOT_LD_PREL19(309),
- R_AARCH64_LD64_GOTOFF_LO15(310),
- R_AARCH64_ADR_GOT_PAGE(311),
- R_AARCH64_LD64_GOT_LO12_NC(312),
- R_AARCH64_LD64_GOTPAGE_LO15(313),
+ R_AARCH64_MOVW_GOTOFF_G0(300), // MOV[NZ]: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G0_NC(301), // MOVK: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G1(302), // MOV[NZ]: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G1_NC(303), // MOVK: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G2(304), // MOV[NZ]: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G2_NC(305), // MOVK: G(GDAT(S)) -GOT
+ R_AARCH64_MOVW_GOTOFF_G3(306), // MOV[NZ]: G(GDAT(S)) -GOT
+ R_AARCH64_GOTREL64(307), // S+A-GOT
+ R_AARCH64_GOTREL32(308), // S+A-GOT
+ R_AARCH64_GOT_LD_PREL19(309), // G(GDAT(S))- P
+ R_AARCH64_LD64_GOTOFF_LO15(310), // LD/ST: G(GDAT(S))- GOT
+ R_AARCH64_ADR_GOT_PAGE(311), // ADRP: Page(G(GDAT(S)))-Page(P)
+ R_AARCH64_LD64_GOT_LO12_NC(312), // LD/ST: G(GDAT(S))
+ R_AARCH64_LD64_GOTPAGE_LO15(313), // LD/ST: G(GDAT(S))-Page(GOT)
R_AARCH64_TLSGD_ADR_PREL21(512),
R_AARCH64_TLSGD_ADR_PAGE21(513),
@@ -226,9 +237,9 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType {
R_AARCH64_TLS_DTPMOD64(1028),
R_AARCH64_TLS_DTPREL64(1029),
R_AARCH64_TLS_TPREL64(1030),
- R_AARCH64_TLS_DTPMOD(1028),
- R_AARCH64_TLS_DTPREL(1029),
- R_AARCH64_TLS_TPREL(1030),
+ R_AARCH64_TLS_DTPMOD(1028), // aka R_AARCH64_TLS_DTPMOD64
+ R_AARCH64_TLS_DTPREL(1029), // aka R_AARCH64_TLS_DTPREL64
+ R_AARCH64_TLS_TPREL(1030), // aka R_AARCH64_TLS_TPREL64
R_AARCH64_TLSDESC(1031),
R_AARCH64_IRELATIVE(1032);
diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java
index 9ee63b228e..cc359b73d2 100644
--- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java
+++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java
@@ -15,31 +15,17 @@
*/
package ghidra.app.util.bin.format.elf.relocation;
-import java.util.*;
+import java.util.Map;
-import ghidra.app.util.MemoryBlockUtils;
import ghidra.app.util.bin.format.elf.*;
-import ghidra.program.model.address.*;
-import ghidra.program.model.data.PointerDataType;
-import ghidra.program.model.mem.MemoryAccessException;
-import ghidra.program.model.mem.MemoryBlock;
-import ghidra.util.*;
-import ghidra.util.exception.InvalidInputException;
-import ghidra.util.exception.NotFoundException;
+import ghidra.program.model.address.Address;
/**
* X86_64_ElfRelocationContext
provides ability to generate a
* Global Offset Table (GOT) to facilitate GOT related relocations encountered within
* object modules.
*/
-class X86_64_ElfRelocationContext extends ElfRelocationContext {
-
- private AddressRange allocatedGotLimits;
- private Address allocatedGotAddress;
- private Address lastAllocatedGotEntryAddress;
- private Address nextAllocatedGotEntryAddress;
-
- private Map gotMap;
+class X86_64_ElfRelocationContext extends ElfGotRelocationContext {
X86_64_ElfRelocationContext(X86_64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
Map symbolMap) {
@@ -47,75 +33,7 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext uniqueSymbolValues = new HashSet<>();
- for (ElfRelocationTable rt : getElfHeader().getRelocationTables()) {
- ElfSymbolTable st = rt.getAssociatedSymbolTable();
- if (st == null) {
- continue;
- }
- for (ElfRelocation r : rt.getRelocations()) {
- int symbolIndex = r.getSymbolIndex();
- if (!requiresGotEntry(r) || symbolIndex == 0) {
- continue;
- }
- ElfSymbol elfSymbol = st.getSymbol(symbolIndex);
- if (elfSymbol == null) {
- continue;
- }
- long symbolValue = getSymbolValue(elfSymbol);
- if (!uniqueSymbolValues.add(symbolValue)) {
- System.out.println("Duplicate sym value 0x" + Long.toHexString(symbolValue) +
- " for " + elfSymbol.getNameAsString());
- }
- }
- }
- return Math.max(8, uniqueSymbolValues.size() * 8);
- }
-
- private boolean requiresGotEntry(ElfRelocation r) {
+ protected boolean requiresGotEntry(ElfRelocation r) {
X86_64_ElfRelocationType type = handler.getRelocationType(r.getType());
if (type == null) {
@@ -140,164 +58,4 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext();
- loadHelper.log("Created " + ElfRelocationHandler.GOT_BLOCK_NAME +
- " block required for GOT relocation processing");
- return allocatedGotAddress;
- }
-
- loadHelper.log("Failed to allocate GOT block required for relocation processing");
- return null;
- }
-
- /**
- * Allocate the next section GOT entry location. If GOT has not been allocated an attempt
- * will be made to create one. If allocated gotMap will also be established.
- * @return Address of GOT entry or {@link Address#NO_ADDRESS} if unable to allocate.
- */
- private Address getNextAllocatedGotEntryAddress() {
- if (nextAllocatedGotEntryAddress == null) {
- if (allocateGot() == null) {
- return Address.NO_ADDRESS; // failed to allocate got
- }
- }
-
- Address addr = nextAllocatedGotEntryAddress;
- if (addr == Address.NO_ADDRESS) {
- return Address.NO_ADDRESS; // insufficient space in got
- }
-
- try {
- // verify that entry fits in got
- int pointerSize = loadHelper.getProgram().getDefaultPointerSize();
- Address lastAddr = nextAllocatedGotEntryAddress.addNoWrap(pointerSize - 1);
- if (allocatedGotLimits.contains(lastAddr)) {
- // entry fits in got - update and return entry address
- lastAllocatedGotEntryAddress = lastAddr;
- nextAllocatedGotEntryAddress = lastAllocatedGotEntryAddress.addNoWrap(1);
- if (!allocatedGotLimits.contains(nextAllocatedGotEntryAddress)) {
- // allocated got space fully consumed
- nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
- }
- return addr;
- }
- }
- catch (AddressOverflowException e) {
- // ignore
- }
-
- // insufficient space in got - fail future allocation attempts
- nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
- return Address.NO_ADDRESS;
- }
-
- /**
- * Get or allocate a GOT entry for the specified symbolValue.
- * NOTE: This is restricted to object modules only which do not of a GOT.
- * @param elfSymbol ELF symbol
- * @return GOT entry address or null if unable to allocate
- */
- public Address getGotEntryAddress(ElfSymbol elfSymbol) {
- long symbolValue = getSymbolValue(elfSymbol);
- Address addr = null;
- if (gotMap != null) {
- addr = gotMap.get(symbolValue);
- }
- if (addr == null) {
- addr = getNextAllocatedGotEntryAddress();
- if (gotMap != null) {
- gotMap.put(symbolValue, addr);
- }
- }
- return addr == Address.NO_ADDRESS ? null : addr;
- }
-
- /**
- * Flush the section GOT table to a new %got memory block
- */
- private void createGot() {
- if (lastAllocatedGotEntryAddress == null) {
- return;
- }
- int size = (int) lastAllocatedGotEntryAddress.subtract(allocatedGotAddress) + 1;
- try {
- MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false,
- ElfRelocationHandler.GOT_BLOCK_NAME, allocatedGotAddress, size,
- "NOTE: This block is artificial and allows ELF Relocations to work correctly",
- "Elf Loader", true, false, false, loadHelper.getLog());
-
- // Mark block as an artificial fabrication
- block.setArtificial(true);
-
- DataConverter converter =
- program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE
- : LittleEndianDataConverter.INSTANCE;
- for (long symbolValue : gotMap.keySet()) {
- Address addr = gotMap.get(symbolValue);
- byte[] bytes = converter.getBytes(symbolValue); // 8-byte pointer value
- block.putBytes(addr, bytes);
- loadHelper.createData(addr, PointerDataType.dataType);
- }
- }
- catch (MemoryAccessException e) {
- String msg = "Failed to create GOT at " + allocatedGotAddress;
- loadHelper.log(msg);
- Msg.error(this, msg, e);
- }
- }
-
- @Override
- public void dispose() {
-
- // Generate the object module GOT table if required
- createGot();
-
- super.dispose();
- }
}