mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 20:22:44 +00:00
GP-2984 modified ELF relocation processing to use single ElfRelocationContext instance. Modified X86-64 relocation processing to handle GOTPCREL for object modules.
This commit is contained in:
parent
acd80575c1
commit
6e1ad5578f
@ -20,6 +20,8 @@ package ghidra.app.util.bin.format.elf;
|
||||
*/
|
||||
public interface ElfConstants {
|
||||
|
||||
public static final String GOT_SYMBOL_NAME = "_GLOBAL_OFFSET_TABLE_";
|
||||
|
||||
// ELF Identification Area Indexes
|
||||
|
||||
/**Length of the File ID*/
|
||||
|
@ -17,7 +17,8 @@ package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
@ -175,7 +176,7 @@ public interface ElfLoadHelper {
|
||||
* Returns the appropriate .got (Global Offset Table) section address using the
|
||||
* DT_PLTGOT value defined in the .dynamic section.
|
||||
* If the dynamic value is not defined, the symbol offset for _GLOBAL_OFFSET_TABLE_
|
||||
* will be used, otherwise null will be returned.
|
||||
* will be used, otherwise null will be returned. See {@link ElfConstants#GOT_SYMBOL_NAME}.
|
||||
* @return the .got section address offset
|
||||
*/
|
||||
public Long getGOTValue();
|
||||
@ -215,14 +216,15 @@ public interface ElfLoadHelper {
|
||||
* Add a fake relocation table entry if none previously existed for the specified address.
|
||||
* This is intended to record original file bytes when forced modifications have been
|
||||
* performed during the ELF import processing. A relocation type of 0 will be specified for
|
||||
* fake entry.
|
||||
* fake entry.
|
||||
* NOTE: The number of recorded original FileBytes currently ignores the specified length.
|
||||
* However, the length is still used to verify that that the intended modification region
|
||||
* dose not intersect another relocation.
|
||||
* @param address relocation address
|
||||
* @param length number of bytes affected
|
||||
* @return true if recorded successfully, or false if conflict with existing relocation entry occurs
|
||||
* @throws MemoryAccessException if unable to read bytes from memory
|
||||
* @throws AddressOverflowException if range address wrap occurs
|
||||
* @return true if recorded successfully, or false if conflict with existing relocation
|
||||
* entry and memory addressing error occurs
|
||||
*/
|
||||
public boolean addFakeRelocTableEntry(Address address, int length)
|
||||
throws MemoryAccessException, AddressOverflowException;
|
||||
public boolean addFakeRelocTableEntry(Address address, int length);
|
||||
|
||||
}
|
||||
|
@ -36,30 +36,48 @@ public class ElfRelocationContext {
|
||||
|
||||
protected final ElfRelocationHandler handler;
|
||||
protected final ElfLoadHelper loadHelper;
|
||||
protected final ElfRelocationTable relocationTable;
|
||||
private ElfSymbolTable symbolTable; // may be null
|
||||
private ElfSymbol nullSymbol; // corresponds to symbolIndex==0 when no symbolTable
|
||||
protected final Map<ElfSymbol, Address> symbolMap;
|
||||
protected final Program program;
|
||||
|
||||
protected ElfRelocationTable relocationTable;
|
||||
protected ElfSymbolTable symbolTable; // may be null
|
||||
|
||||
private ElfSymbol nullSymbol; // corresponds to symbolIndex==0 when no symbolTable
|
||||
|
||||
/**
|
||||
* Relocation context for a specific Elf image and relocation table
|
||||
* @param handler relocation handler or null if not available
|
||||
* @param loadHelper the elf load helper
|
||||
* @param relocationTable Elf relocation table
|
||||
* @param symbolMap Elf symbol placement map
|
||||
*/
|
||||
protected ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
this.handler = handler;
|
||||
this.loadHelper = loadHelper;
|
||||
this.relocationTable = relocationTable;
|
||||
symbolTable = relocationTable.getAssociatedSymbolTable();
|
||||
this.symbolMap = symbolMap;
|
||||
this.program = loadHelper.getProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked at start of relocation processing for specified table.
|
||||
* The method {@link #endRelocationTableProcessing()} will be invoked after last relocation
|
||||
* is processed.
|
||||
* @param relocTable relocation table
|
||||
*/
|
||||
public void startRelocationTableProcessing(ElfRelocationTable relocTable) {
|
||||
this.relocationTable = relocTable;
|
||||
symbolTable = relocTable.getAssociatedSymbolTable();
|
||||
if (symbolTable == null) {
|
||||
nullSymbol = ElfSymbol.createNullSymbol(loadHelper.getElfHeader());
|
||||
}
|
||||
this.symbolMap = symbolMap;
|
||||
this.program = loadHelper.getProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked at end of relocation processing for current relocation table.
|
||||
* See {@link #startRelocationTableProcessing(ElfRelocationTable)}.
|
||||
*/
|
||||
public void endRelocationTableProcessing() {
|
||||
this.relocationTable = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,20 +148,19 @@ public class ElfRelocationContext {
|
||||
/**
|
||||
* Get a relocation context for a specfic Elf image and relocation table
|
||||
* @param loadHelper Elf load helper
|
||||
* @param relocationTable Elf relocation table
|
||||
* @param symbolMap Elf symbol placement map
|
||||
* @return relocation context or null
|
||||
*/
|
||||
public static ElfRelocationContext getRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
ElfHeader elf = loadHelper.getElfHeader();
|
||||
ElfRelocationContext context = null;
|
||||
ElfRelocationHandler handler = ElfRelocationHandlerFactory.getHandler(elf);
|
||||
if (handler != null) {
|
||||
context = handler.createRelocationContext(loadHelper, relocationTable, symbolMap);
|
||||
context = handler.createRelocationContext(loadHelper, symbolMap);
|
||||
}
|
||||
if (context == null) {
|
||||
context = new ElfRelocationContext(handler, loadHelper, relocationTable, symbolMap);
|
||||
context = new ElfRelocationContext(handler, loadHelper, symbolMap);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
@ -38,6 +38,12 @@ import ghidra.util.exception.NotFoundException;
|
||||
*/
|
||||
abstract public class ElfRelocationHandler implements ExtensionPoint {
|
||||
|
||||
/**
|
||||
* Fabricated Global Offset Table (GOT) name/prefix to be used when processing an object module
|
||||
* and a GOT must be fabricated to allow relocation processing.
|
||||
*/
|
||||
public static final String GOT_BLOCK_NAME = "%got";
|
||||
|
||||
abstract public boolean canRelocate(ElfHeader elf);
|
||||
|
||||
/**
|
||||
@ -55,12 +61,11 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
|
||||
* Relocation context for a specific Elf image and relocation table. The relocation context
|
||||
* is used to process relocations and manage any data required to process relocations.
|
||||
* @param loadHelper Elf load helper
|
||||
* @param relocationTable Elf relocation table
|
||||
* @param symbolMap Elf symbol placement map
|
||||
* @return relocation context or null if unsupported
|
||||
*/
|
||||
public ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -794,89 +794,96 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
log("ELF relocation handler extension not found! Unable to process relocations.");
|
||||
}
|
||||
|
||||
Address defaultBase = getDefaultAddress(elf.adjustAddressForPrelink(0));
|
||||
AddressSpace defaultSpace = defaultBase.getAddressSpace();
|
||||
long defaultBaseOffset = defaultBase.getAddressableWordOffset();
|
||||
|
||||
int totalCount = 0;
|
||||
for (ElfRelocationTable relocationTable : relocationTables) {
|
||||
totalCount += relocationTable.getRelocationCount();
|
||||
}
|
||||
monitor.initialize(totalCount);
|
||||
|
||||
for (ElfRelocationTable relocationTable : relocationTables) {
|
||||
|
||||
monitor.checkCanceled();
|
||||
|
||||
Address relocTableAddr = null;
|
||||
|
||||
ElfSectionHeader section = relocationTable.getTableSectionHeader();
|
||||
if (section != null) {
|
||||
relocTableAddr = findLoadAddress(section, 0);
|
||||
ElfRelocationContext context = null;
|
||||
if (processRelocations) {
|
||||
context = ElfRelocationContext.getRelocationContext(this, symbolMap);
|
||||
}
|
||||
try {
|
||||
for (ElfRelocationTable relocationTable : relocationTables) {
|
||||
monitor.checkCanceled();
|
||||
processRelocationTable(relocationTable, context, monitor);
|
||||
}
|
||||
else {
|
||||
relocTableAddr = findLoadAddress(relocationTable.getFileOffset(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cases:
|
||||
* 1. elf.isRelocatable()
|
||||
* a) sectionToBeRelocated null (may be NULL section?)
|
||||
* b) sectionToBeRelocated known - offset relative to section load address
|
||||
*
|
||||
* 2. !elf.isRelocatable()
|
||||
* a) sectionToBeRelocated null (may be NULL section?)
|
||||
* b) sectionToBeRelocated known - offset relative to image base
|
||||
*/
|
||||
|
||||
AddressSpace relocationSpace = defaultSpace;
|
||||
long baseOffset = defaultBaseOffset;
|
||||
|
||||
ElfSectionHeader sectionToBeRelocated = relocationTable.getSectionToBeRelocated();
|
||||
if (sectionToBeRelocated != null) {
|
||||
// relocation offsets are relative to start of section load address
|
||||
Address sectionLoadAddr = findLoadAddress(sectionToBeRelocated, 0);
|
||||
if (sectionLoadAddr == null) {
|
||||
log("Failed to identify relocation base address for relocation table 0x" +
|
||||
relocationTable.getAddressOffset() + " [section: " +
|
||||
sectionToBeRelocated.getNameAsString() + "]");
|
||||
monitor.incrementProgress(relocationTable.getRelocationCount());
|
||||
continue;
|
||||
}
|
||||
relocationSpace = sectionLoadAddr.getAddressSpace();
|
||||
if (elf.isRelocatable()) {
|
||||
baseOffset = sectionLoadAddr.getAddressableWordOffset();
|
||||
}
|
||||
else if (relocationSpace != defaultSpace) {
|
||||
baseOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (relocTableAddr != null) {
|
||||
markupRelocationTable(relocTableAddr, relocationTable, monitor);
|
||||
}
|
||||
|
||||
ElfRelocationContext context = null;
|
||||
if (processRelocations) {
|
||||
context =
|
||||
ElfRelocationContext.getRelocationContext(this, relocationTable, symbolMap);
|
||||
}
|
||||
try {
|
||||
processRelocationTable(relocationTable, context, relocationSpace, baseOffset,
|
||||
monitor);
|
||||
}
|
||||
finally {
|
||||
if (context != null) {
|
||||
context.dispose();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (context != null) {
|
||||
context.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processRelocationTable(ElfRelocationTable relocationTable,
|
||||
ElfRelocationContext context, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
Address defaultBase = getDefaultAddress(elf.adjustAddressForPrelink(0));
|
||||
AddressSpace defaultSpace = defaultBase.getAddressSpace();
|
||||
long defaultBaseOffset = defaultBase.getAddressableWordOffset();
|
||||
|
||||
Address relocTableAddr = null;
|
||||
|
||||
ElfSectionHeader section = relocationTable.getTableSectionHeader();
|
||||
if (section != null) {
|
||||
relocTableAddr = findLoadAddress(section, 0);
|
||||
}
|
||||
else {
|
||||
relocTableAddr = findLoadAddress(relocationTable.getFileOffset(), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cases:
|
||||
* 1. elf.isRelocatable()
|
||||
* a) sectionToBeRelocated null (may be NULL section?)
|
||||
* b) sectionToBeRelocated known - offset relative to section load address
|
||||
*
|
||||
* 2. !elf.isRelocatable()
|
||||
* a) sectionToBeRelocated null (may be NULL section?)
|
||||
* b) sectionToBeRelocated known - offset relative to image base
|
||||
*/
|
||||
|
||||
AddressSpace relocationSpace = defaultSpace;
|
||||
long baseOffset = defaultBaseOffset;
|
||||
|
||||
ElfSectionHeader sectionToBeRelocated = relocationTable.getSectionToBeRelocated();
|
||||
if (sectionToBeRelocated != null) {
|
||||
// relocation offsets are relative to start of section load address
|
||||
Address sectionLoadAddr = findLoadAddress(sectionToBeRelocated, 0);
|
||||
if (sectionLoadAddr == null) {
|
||||
log("Failed to identify relocation base address for relocation table 0x" +
|
||||
relocationTable.getAddressOffset() + " [section: " +
|
||||
sectionToBeRelocated.getNameAsString() + "]");
|
||||
monitor.incrementProgress(relocationTable.getRelocationCount());
|
||||
return;
|
||||
}
|
||||
relocationSpace = sectionLoadAddr.getAddressSpace();
|
||||
if (elf.isRelocatable()) {
|
||||
baseOffset = sectionLoadAddr.getAddressableWordOffset();
|
||||
}
|
||||
else if (relocationSpace != defaultSpace) {
|
||||
baseOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (relocTableAddr != null) {
|
||||
markupRelocationTable(relocTableAddr, relocationTable, monitor);
|
||||
}
|
||||
|
||||
processRelocationTableEntries(relocationTable, context, relocationSpace, baseOffset,
|
||||
monitor);
|
||||
}
|
||||
|
||||
private void processRelocationTableEntries(ElfRelocationTable relocationTable,
|
||||
ElfRelocationContext context, AddressSpace relocationSpace, long baseWordOffset,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (context != null) {
|
||||
context.startRelocationTableProcessing(relocationTable);
|
||||
}
|
||||
|
||||
ElfSymbolTable symbolTable = relocationTable.getAssociatedSymbolTable();
|
||||
ElfRelocation[] relocs = relocationTable.getRelocations();
|
||||
|
||||
@ -970,11 +977,15 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Save relocation data
|
||||
// Save relocation data - uses original FileBytes
|
||||
program.getRelocationTable()
|
||||
.add(relocAddr, reloc.getType(), values, null, symbolName);
|
||||
}
|
||||
}
|
||||
|
||||
if (context != null) {
|
||||
context.endRelocationTableProcessing();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -996,20 +1007,24 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFakeRelocTableEntry(Address address, int length)
|
||||
throws AddressOverflowException {
|
||||
Address maxAddr = address.addNoWrap(length - 1);
|
||||
RelocationTable relocationTable = program.getRelocationTable();
|
||||
List<Relocation> relocations = relocationTable.getRelocations(address);
|
||||
if (!relocations.isEmpty()) {
|
||||
return false;
|
||||
public boolean addFakeRelocTableEntry(Address address, int length) {
|
||||
try {
|
||||
Address maxAddr = address.addNoWrap(length - 1);
|
||||
RelocationTable relocationTable = program.getRelocationTable();
|
||||
List<Relocation> relocations = relocationTable.getRelocations(address);
|
||||
if (!relocations.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Address nextRelocAddr = relocationTable.getRelocationAddressAfter(address);
|
||||
if (nextRelocAddr == null || nextRelocAddr.compareTo(maxAddr) > 0) {
|
||||
relocationTable.add(address, 0, new long[0], null, null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Address nextRelocAddr = relocationTable.getRelocationAddressAfter(address);
|
||||
if (nextRelocAddr != null && nextRelocAddr.compareTo(maxAddr) <= 0) {
|
||||
return false;
|
||||
catch (AddressOverflowException e) {
|
||||
Msg.error(this, "Failed to generate fake relocation data at " + address, e);
|
||||
}
|
||||
relocationTable.add(address, 0, new long[0], null, null);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1420,7 +1435,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
block.setWrite(true);
|
||||
block.setSourceName(BLOCK_SOURCE_NAME);
|
||||
block.setComment(
|
||||
"NOTE: This block is artificial and is used to make relocations work correctly");
|
||||
"NOTE: This block is artificial and allows ELF Relocations to work correctly");
|
||||
}
|
||||
catch (Exception e) {
|
||||
log("Error creating external memory block: " + " - " + getMessage(e));
|
||||
@ -1547,6 +1562,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
boolean usingFakeExternal = false;
|
||||
if (address == Address.NO_ADDRESS) {
|
||||
|
||||
if (ElfConstants.GOT_SYMBOL_NAME.equals(symName)) {
|
||||
// Do not assign GOT symbol to the EXTERNAL block.
|
||||
// This is likely an object module which is not fully linked.
|
||||
// It is very likely relocation handler will need to allocate a GOT
|
||||
// for any GOT-based relocations.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(symName)) {
|
||||
continue;
|
||||
}
|
||||
@ -3200,7 +3223,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
throw new AssertException("unexpected", e);
|
||||
}
|
||||
}
|
||||
Symbol gotSym = SymbolUtilities.getLabelOrFunctionSymbol(program, "_GLOBAL_OFFSET_TABLE_",
|
||||
Symbol gotSym =
|
||||
SymbolUtilities.getLabelOrFunctionSymbol(program, ElfConstants.GOT_SYMBOL_NAME,
|
||||
err -> log(err));
|
||||
if (gotSym != null) {
|
||||
return gotSym.getAddress().getAddressableWordOffset();
|
||||
|
@ -17,7 +17,8 @@ package ghidra.app.util.bin.format.elf.relocation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.app.util.bin.format.elf.ElfLoadHelper;
|
||||
import ghidra.app.util.bin.format.elf.ElfSymbol;
|
||||
import ghidra.app.util.bin.format.elf.extend.ARM_ElfExtension;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
@ -26,9 +27,8 @@ class ARM_ElfRelocationContext extends ElfRelocationContext {
|
||||
private final boolean applyPcBiasToRelativeRelocations;
|
||||
|
||||
protected ARM_ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable,
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, relocationTable, symbolMap);
|
||||
super(handler, loadHelper, symbolMap);
|
||||
|
||||
applyPcBiasToRelativeRelocations =
|
||||
loadHelper.getOption(ARM_ElfExtension.APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_OPTION_NAME,
|
||||
|
@ -28,8 +28,8 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
@Override
|
||||
public ARM_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
return new ARM_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return new ARM_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -36,8 +36,6 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
// private static final int TP_OFFSET = 0x7000;
|
||||
// private static final int DTP_OFFSET = 0x8000;
|
||||
|
||||
// private static final String GOT_SYMBOL_NAME = "_GLOBAL_OFFSET_TABLE_";
|
||||
|
||||
@Override
|
||||
public boolean canRelocate(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_MIPS;
|
||||
@ -45,8 +43,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
@Override
|
||||
public MIPS_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
return new MIPS_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return new MIPS_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1061,12 +1059,37 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
private Address lastSymbolAddr;
|
||||
|
||||
MIPS_ElfRelocationContext(MIPS_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
// TODO: move section GOT creation into ElfRelocationContext to make it
|
||||
// available to other relocation handlers
|
||||
@Override
|
||||
public void endRelocationTableProcessing() {
|
||||
|
||||
// Mark all deferred relocations which were never processed
|
||||
for (MIPS_DeferredRelocation reloc : hi16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
hi16list.clear();
|
||||
for (MIPS_DeferredRelocation reloc : got16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
got16list.clear();
|
||||
|
||||
// Generate the section GOT table if required
|
||||
createGot();
|
||||
|
||||
sectionGotLimits = null;
|
||||
sectionGotAddress = null;
|
||||
lastSectionGotEntryAddress = null;
|
||||
nextSectionGotEntryAddress = null;
|
||||
gotMap = null;
|
||||
useSavedAddend = false;
|
||||
savedAddendHasError = false;
|
||||
lastSymbolAddr = null;
|
||||
|
||||
super.endRelocationTableProcessing();
|
||||
}
|
||||
|
||||
private void allocateSectionGot() {
|
||||
int alignment = getLoadAdapter().getLinkageBlockAlignment();
|
||||
@ -1155,7 +1178,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
* Determine if the next relocation has the same offset.
|
||||
* If true, the computed value should be stored to savedAddend and
|
||||
* useSaveAddend set true.
|
||||
* @param relocIndex current relocation index
|
||||
* @param relocation current relocation
|
||||
* @return true if next relocation has same offset
|
||||
*/
|
||||
boolean nextRelocationHasSameOffset(ElfRelocation relocation) {
|
||||
@ -1193,7 +1216,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
private String getSectionGotName() {
|
||||
String sectionName = relocationTable.getSectionToBeRelocated().getNameAsString();
|
||||
return "%got" + sectionName;
|
||||
return ElfRelocationHandler.GOT_BLOCK_NAME + sectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1204,12 +1227,12 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
return;
|
||||
}
|
||||
int size = (int) lastSectionGotEntryAddress.subtract(sectionGotAddress) + 1;
|
||||
String sectionName = relocationTable.getSectionToBeRelocated().getNameAsString();
|
||||
String blockName = getSectionGotName();
|
||||
try {
|
||||
MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false,
|
||||
blockName, sectionGotAddress, size, "GOT for " + sectionName + " section",
|
||||
"MIPS-Elf Loader", true, false, false, loadHelper.getLog());
|
||||
blockName, sectionGotAddress, size,
|
||||
"NOTE: This block is artificial and allows ELF Relocations to work correctly",
|
||||
"Elf Loader", true, false, false, loadHelper.getLog());
|
||||
DataConverter converter =
|
||||
program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE
|
||||
: LittleEndianDataConverter.INSTANCE;
|
||||
@ -1302,24 +1325,6 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
void addGOT16Relocation(MIPS_DeferredRelocation got16reloc) {
|
||||
got16list.add(got16reloc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// Mark all deferred relocations which were never processed
|
||||
for (MIPS_DeferredRelocation reloc : hi16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
hi16list.clear();
|
||||
for (MIPS_DeferredRelocation reloc : got16list) {
|
||||
reloc.markUnprocessed(this, "LO16 Relocation");
|
||||
}
|
||||
got16list.clear();
|
||||
|
||||
// Generate the section GOT table if required
|
||||
createGot();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,6 @@ package ghidra.app.util.bin.format.elf.relocation;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.util.bin.format.elf.ElfLoadHelper;
|
||||
import ghidra.app.util.bin.format.elf.ElfRelocationTable;
|
||||
import ghidra.app.util.bin.format.elf.ElfSymbol;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
@ -26,8 +25,8 @@ import ghidra.program.model.address.AddressSpace;
|
||||
class PIC30_ElfRelocationContext extends ElfRelocationContext {
|
||||
|
||||
protected PIC30_ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
private boolean isDebugSection(AddressSpace overlaySpace) {
|
||||
|
@ -107,8 +107,8 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
@Override
|
||||
public PIC30_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
return new PIC30_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return new PIC30_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
private boolean isEDSVariant(ElfRelocationContext elfRelocationContext) {
|
||||
|
@ -121,7 +121,7 @@ public class PowerPC_ElfExtension extends ElfExtension {
|
||||
elfLoadHelper.addFakeRelocTableEntry(gotAddr, 4);
|
||||
memory.setInt(gotAddr, dynamicOffset);
|
||||
}
|
||||
catch (MemoryAccessException | AddressOverflowException e) {
|
||||
catch (MemoryAccessException e) {
|
||||
elfLoadHelper.log(e);
|
||||
}
|
||||
}
|
||||
|
@ -41,8 +41,8 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
@Override
|
||||
public PowerPC_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
|
||||
return new PowerPC_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return new PowerPC_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -286,9 +286,8 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
private Integer sda2Base;
|
||||
|
||||
protected PowerPC_ElfRelocationContext(ElfRelocationHandler handler,
|
||||
ElfLoadHelper loadHelper, ElfRelocationTable relocationTable,
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, relocationTable, symbolMap);
|
||||
ElfLoadHelper loadHelper, Map<ElfSymbol, Address> symbolMap) {
|
||||
super(handler, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,9 +95,15 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
memory.setInt(relocationAddress, value);
|
||||
break;
|
||||
case X86_32_ElfRelocationConstants.R_386_GOTOFF:
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = (int) symbolValue + (int) addend - (int) dotgot;
|
||||
memory.setInt(relocationAddress, value);
|
||||
try {
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = (int) symbolValue + (int) addend - (int) dotgot;
|
||||
memory.setInt(relocationAddress, value);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
markAsError(program, relocationAddress, "R_386_GOTOFF", symbolName,
|
||||
e.getMessage(), elfRelocationContext.getLog());
|
||||
}
|
||||
break;
|
||||
case X86_32_ElfRelocationConstants.R_386_COPY:
|
||||
markAsWarning(program, relocationAddress, "R_386_COPY", symbolName, symbolIndex,
|
||||
@ -106,22 +112,22 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
// Thread Local Symbol relocations (unimplemented concept)
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_DTPMOD32:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_DTPMOD32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_DTPOFF32:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_DTPOFF32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_TPOFF32:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_TPOFF32", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_32_ElfRelocationConstants.R_386_TLS_TPOFF:
|
||||
markAsWarning(program, relocationAddress, "R_386_TLS_TPOFF", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
@ -149,9 +155,15 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
case X86_32_ElfRelocationConstants.R_386_GOTPC:
|
||||
// similar to R_386_PC32 but uses .got address instead of symbol address
|
||||
dotgot = elfRelocationContext.getGOTValue();
|
||||
value = (int) (dotgot + addend - offset);
|
||||
memory.setInt(relocationAddress, value);
|
||||
try {
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = (int) (dotgot + addend - offset);
|
||||
memory.setInt(relocationAddress, value);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
markAsError(program, relocationAddress, "R_386_GOTPC", symbolName,
|
||||
e.getMessage(), elfRelocationContext.getLog());
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO: Cases not yet examined
|
||||
|
@ -0,0 +1,263 @@
|
||||
/* ###
|
||||
* 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.AssertException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
/**
|
||||
* <code>X86_64_ElfRelocationContext</code> 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<Long, Address> gotMap;
|
||||
|
||||
X86_64_ElfRelocationContext(X86_64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||
Map<ElfSymbol, Address> 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 = 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<Long> 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;
|
||||
}
|
||||
uniqueSymbolValues.add(elfSymbol.getValue());
|
||||
}
|
||||
}
|
||||
return Math.max(8, uniqueSymbolValues.size() * 8);
|
||||
}
|
||||
|
||||
private boolean requiresGotEntry(ElfRelocation r) {
|
||||
switch (r.getType()) {
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTOFF64:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPC32:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOT64:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL64:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPC64:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCRELX:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_REX_GOTPCRELX:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Address allocateGot() {
|
||||
|
||||
allocatedGotAddress = Address.NO_ADDRESS;
|
||||
nextAllocatedGotEntryAddress = Address.NO_ADDRESS;
|
||||
|
||||
ElfSymbol gotElfSymbol = findGotElfSymbol();
|
||||
if (gotElfSymbol == null) {
|
||||
// TODO: may need to support cases where GOT symbol not defined
|
||||
loadHelper.log(
|
||||
"GOT allocatiom failed. " + ElfConstants.GOT_SYMBOL_NAME + " not defined");
|
||||
return null;
|
||||
}
|
||||
if (getSymbolAddress(gotElfSymbol) != null) {
|
||||
throw new AssertException(ElfConstants.GOT_SYMBOL_NAME + " already allocated");
|
||||
}
|
||||
|
||||
int alignment = getLoadAdapter().getLinkageBlockAlignment();
|
||||
allocatedGotLimits =
|
||||
getLoadHelper().allocateLinkageBlock(alignment, computeRequiredGotSize(),
|
||||
ElfRelocationHandler.GOT_BLOCK_NAME);
|
||||
if (allocatedGotLimits != null &&
|
||||
allocatedGotLimits.getMinAddress().getOffset() < Integer.MAX_VALUE) {
|
||||
// GOT must fall within first 32-bit segment
|
||||
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 " + ElfRelocationHandler.GOT_BLOCK_NAME +
|
||||
" 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) {
|
||||
allocateGot();
|
||||
}
|
||||
|
||||
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 symbolValue symbol value
|
||||
* @return GOT entry address or null if unable to allocate
|
||||
*/
|
||||
public Address getGotEntryAddress(long symbolValue) {
|
||||
Address addr = null;
|
||||
if (gotMap != null) {
|
||||
addr = gotMap.get(symbolValue);
|
||||
}
|
||||
if (addr == null) {
|
||||
addr = getNextAllocatedGotEntryAddress();
|
||||
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());
|
||||
DataConverter converter =
|
||||
program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE
|
||||
: LittleEndianDataConverter.INSTANCE;
|
||||
for (long symbolValue : gotMap.keySet()) {
|
||||
Address addr = gotMap.get(symbolValue);
|
||||
byte[] bytes;
|
||||
if (program.getDefaultPointerSize() == 4) {
|
||||
bytes = converter.getBytes((int) symbolValue);
|
||||
}
|
||||
else {
|
||||
bytes = converter.getBytes(symbolValue);
|
||||
}
|
||||
block.putBytes(addr, bytes);
|
||||
loadHelper.createData(addr, PointerDataType.dataType);
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
|
||||
// Generate the object module GOT table if required
|
||||
createGot();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
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;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@ -34,6 +36,12 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
return X86_64_ElfRelocationConstants.R_X86_64_RELATIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X86_64_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||
Map<ElfSymbol, Address> symbolMap) {
|
||||
return new X86_64_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
@ -46,6 +54,9 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
X86_64_ElfRelocationContext x86RelocationContext =
|
||||
(X86_64_ElfRelocationContext) elfRelocationContext;
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == X86_64_ElfRelocationConstants.R_X86_64_NONE) {
|
||||
return;
|
||||
@ -120,9 +131,15 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
memory.setLong(relocationAddress, value);
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTOFF64:
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = symbolValue + addend - dotgot;
|
||||
memory.setLong(relocationAddress, value);
|
||||
try {
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = symbolValue + addend - dotgot;
|
||||
memory.setLong(relocationAddress, value);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
markAsError(program, relocationAddress, "R_X86_64_GOTOFF64", symbolName,
|
||||
e.getMessage(), elfRelocationContext.getLog());
|
||||
}
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_32: // this one complains for unsigned overflow
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_32S: // this one complains for signed overflow
|
||||
@ -143,36 +160,112 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
// Thread Local Symbol relocations (unimplemented concept)
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_DTPMOD64:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_DTPMOD64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_DTPOFF64:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_DTPOFF64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_TPOFF64:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_TPOFF64", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_TLSDESC:
|
||||
markAsWarning(program, relocationAddress, "R_X86_64_TLSDESC", symbolName,
|
||||
symbolIndex, "Thread Local Symbol relocation not support",
|
||||
symbolIndex, "Thread Local Symbol relocation not supported",
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
|
||||
// cases which do not use symbol value
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPC32:
|
||||
dotgot = elfRelocationContext.getGOTValue();
|
||||
value = dotgot + addend - offset;
|
||||
try {
|
||||
long dotgot = elfRelocationContext.getGOTValue();
|
||||
value = dotgot + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
markAsError(program, relocationAddress, "R_X86_64_GOTPC32", symbolName,
|
||||
e.getMessage(), elfRelocationContext.getLog());
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCRELX:
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_REX_GOTPCRELX:
|
||||
|
||||
// Check for supported Relax cases (assumes non-PIC)
|
||||
// Assumes non-PIC treatment is OK and attempts
|
||||
// indirect-to-direct instruction transformation
|
||||
|
||||
Address opAddr = relocationAddress.subtract(2);
|
||||
Address modRMAddr = relocationAddress.subtract(1);
|
||||
Address directValueAddr = null;
|
||||
|
||||
byte op = memory.getByte(opAddr);
|
||||
byte modRM = memory.getByte(modRMAddr);
|
||||
|
||||
byte symbolType = sym.getType();
|
||||
if (symbolType < ElfSymbol.STT_NOTYPE || symbolType > ElfSymbol.STT_COMMON) {
|
||||
// do not transform instruction for OS-specific symbol types
|
||||
}
|
||||
else if (op == (byte) 0x8b) { // check for MOV op
|
||||
// convert to LEA op
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0x8d); // direct LEA op
|
||||
directValueAddr = relocationAddress;
|
||||
}
|
||||
else if (op == (byte) 0xff) { // check for possible JMP/CALL op
|
||||
if (modRM == (byte) 0x25) { // check for indirect JMP op
|
||||
// convert to direct JMP op
|
||||
// must compensate for shorter instruction by appending NOP
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0xe9); // direct JMP op
|
||||
memory.setByte(relocationAddress.add(3), (byte) 0x90); // append NOP
|
||||
directValueAddr = modRMAddr;
|
||||
addend += 1;
|
||||
}
|
||||
else if (modRM == (byte) 0x15) { // check for indirect CALL instruction
|
||||
// convert to direct CALL instruction
|
||||
// use of addr32 prefix allows use of single instruction
|
||||
elfRelocationContext.getLoadHelper().addFakeRelocTableEntry(opAddr, 2);
|
||||
memory.setByte(opAddr, (byte) 0x67); // addr32 prefix
|
||||
memory.setByte(modRMAddr, (byte) 0xe8); // direct CALL op
|
||||
directValueAddr = relocationAddress;
|
||||
}
|
||||
}
|
||||
if (directValueAddr != null) {
|
||||
value = symbolValue + addend - offset;
|
||||
memory.setInt(directValueAddr, (int) value);
|
||||
break;
|
||||
}
|
||||
|
||||
// If instruction not handled as relaxed instruction
|
||||
// Let R_X86_64_GOTPCREL case handle as simple GOTPCREL relocation.
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL:
|
||||
Address symbolGotAddress = x86RelocationContext.getGotEntryAddress(symbolValue);
|
||||
if (symbolGotAddress == null) {
|
||||
markAsError(program, relocationAddress, type, symbolName,
|
||||
"GOT allocation failure", elfRelocationContext.getLog());
|
||||
break;
|
||||
}
|
||||
value = symbolGotAddress.getOffset() + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
break;
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL:
|
||||
dotgot = elfRelocationContext.getGOTValue();
|
||||
value = symbolValue + dotgot + addend - offset;
|
||||
memory.setInt(relocationAddress, (int) value);
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_GOTPCREL64:
|
||||
symbolGotAddress = x86RelocationContext.getGotEntryAddress(symbolValue);
|
||||
if (symbolGotAddress == null) {
|
||||
markAsError(program, relocationAddress, "R_X86_64_GOTPCREL64", symbolName,
|
||||
"GOT allocation failure", elfRelocationContext.getLog());
|
||||
break;
|
||||
}
|
||||
value = symbolGotAddress.getOffset() + addend - offset;
|
||||
memory.setLong(relocationAddress, value);
|
||||
break;
|
||||
|
||||
case X86_64_ElfRelocationConstants.R_X86_64_RELATIVE:
|
||||
|
Loading…
Reference in New Issue
Block a user