mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 12:49:45 +00:00
GP-2041 Added ELF ARM PC Bias import option for relocation processing
This commit is contained in:
parent
91e5259018
commit
8e00f4faa4
@ -37,6 +37,15 @@ public interface ElfLoadHelper {
|
||||
*/
|
||||
Program getProgram();
|
||||
|
||||
/**
|
||||
* Get an import processing option value
|
||||
* @param <T> class of option value (e.g., String, Boolean, etc.)
|
||||
* @param optionName option name
|
||||
* @param defaultValue default option value which also establishes expected value type
|
||||
* @return option value
|
||||
*/
|
||||
<T> T getOption(String optionName, T defaultValue);
|
||||
|
||||
/**
|
||||
* Get ELF Header object
|
||||
* @return ELF Header object
|
||||
|
@ -18,9 +18,9 @@ package ghidra.app.util.bin.format.elf.extend;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
@ -512,4 +512,13 @@ public class ElfLoadAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extension-specific load options
|
||||
* @param elf ELF header
|
||||
* @param options list to which load options may be added
|
||||
*/
|
||||
public void addLoadOptions(ElfHeader elf, List<Option> options) {
|
||||
// no additional options
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ import ghidra.app.util.OptionUtils;
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.format.elf.ElfException;
|
||||
import ghidra.app.util.bin.format.elf.ElfHeader;
|
||||
import ghidra.app.util.bin.format.elf.extend.ElfExtensionFactory;
|
||||
import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.util.NumericUtilities;
|
||||
@ -87,6 +89,12 @@ public class ElfLoaderOptionsFactory {
|
||||
options.add(
|
||||
new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT,
|
||||
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-resolveExternalSymbols"));
|
||||
|
||||
ElfLoadAdapter extensionAdapter = ElfExtensionFactory.getLoadAdapter(elf);
|
||||
if (extensionAdapter != null) {
|
||||
extensionAdapter.addLoadOptions(elf, options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean includeDataImageBaseOption(ElfHeader elf, Language language) {
|
||||
|
@ -25,8 +25,7 @@ import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.*;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
@ -94,6 +93,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
listing = program.getListing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOption(String optionName, T defaultValue) {
|
||||
return OptionUtils.getOption(optionName, options, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElfHeader getElfHeader() {
|
||||
return elf;
|
||||
|
@ -15,19 +15,33 @@
|
||||
*/
|
||||
package ghidra.app.util.bin.format.elf.extend;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.Option;
|
||||
import ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.app.util.opinion.Loader;
|
||||
import ghidra.program.model.address.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.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class ARM_ElfExtension extends ElfExtension {
|
||||
|
||||
/**
|
||||
* ARM PC Bias option affecting all relative relocations.
|
||||
* If PC Bias is already accounted for within relocation addend this option should be specified
|
||||
* as false, otherwise true (default).
|
||||
*/
|
||||
public static final String APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_OPTION_NAME =
|
||||
"Apply PC Bias to relative relocations";
|
||||
public static final boolean APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_DEFAULT = false; // reflects binutils
|
||||
|
||||
// Elf Program Header Extensions
|
||||
public static final ElfProgramHeaderType PT_ARM_EXIDX =
|
||||
new ElfProgramHeaderType(0x70000000, "PT_ARM_EXIDX", "Frame unwind information");
|
||||
@ -62,6 +76,31 @@ public class ARM_ElfExtension extends ElfExtension {
|
||||
return "_ARM";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLoadOptions(ElfHeader elf, List<Option> options) {
|
||||
|
||||
// If PC Bias option disabled addend assumed to includes PC Bias,
|
||||
// if enabled PC Bias must be factored in explicitly during relocation processing
|
||||
boolean enablePcBiasOption = false;
|
||||
|
||||
try {
|
||||
elf.parse(); // ensure ELF is fully parsed to query section data
|
||||
|
||||
// Enable PC Bias use if Green Hills (GHS) detected
|
||||
ElfSectionHeader section = elf.getSection(".ghsinfo");
|
||||
if (section != null) {
|
||||
enablePcBiasOption = true;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
Msg.warn(this, "Failed to fully parse ELF headers to formulate ARM import options");
|
||||
}
|
||||
|
||||
options.add(new Option(APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_OPTION_NAME,
|
||||
enablePcBiasOption, Boolean.class,
|
||||
Loader.COMMAND_LINE_ARG_PREFIX + "-applyArmElfRelocPCBias"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processElf(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
@ -0,0 +1,67 @@
|
||||
/* ###
|
||||
* 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.app.util.bin.format.elf.extend.ARM_ElfExtension;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
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);
|
||||
|
||||
applyPcBiasToRelativeRelocations =
|
||||
loadHelper.getOption(ARM_ElfExtension.APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_OPTION_NAME,
|
||||
ARM_ElfExtension.APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate PC Bias value which should be applied to the computed relocation value.
|
||||
* This method and related option is intended as a work around for differences in how tool-chain
|
||||
* and associated loaders handle the PC Bias and if they factor it into the addend or not.
|
||||
* Within Ghidra, the default is to assume the PC Bias is not factored into the relocation addend
|
||||
* with the {@link ARM_ElfExtension#APPLY_PC_BIAS_TO_RELATIVE_RELOCATIONS_OPTION_NAME} option
|
||||
* being true.
|
||||
* <p>
|
||||
* Example as to how this PC Bias value factors into relocation value computation:
|
||||
* <pre>
|
||||
* value = (symbolValue + addend) - (relocAddr + pcBias)
|
||||
* </pre>
|
||||
* Within the Sleigh language this bias may be reflected by:
|
||||
* <pre>
|
||||
* ARM:
|
||||
* (inst_start + 8) or (inst_next + 4)
|
||||
* Thumb (either 16-bit or 32-bit forms):
|
||||
* (inst_start + 4)
|
||||
* </pre>
|
||||
* @param isThumb true if Thumb instruction, false if ARM
|
||||
* @return PC Bias value to be applied
|
||||
*/
|
||||
int getPcBias(boolean isThumb) {
|
||||
if (applyPcBiasToRelativeRelocations) {
|
||||
return isThumb ? 4 : 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -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.Function;
|
||||
@ -24,6 +26,12 @@ import ghidra.util.exception.NotFoundException;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRelocate(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_ARM;
|
||||
@ -35,14 +43,17 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
public void relocate(ElfRelocationContext context, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_ARM) {
|
||||
ElfHeader elf = context.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_ARM ||
|
||||
!(context instanceof ARM_ElfRelocationContext)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ARM_ElfRelocationContext elfRelocationContext = (ARM_ElfRelocationContext) context;
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
@ -75,7 +86,9 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = (oldValue << 8 >> 6); // extract addend and sign-extend with *4 factor
|
||||
}
|
||||
newValue = (int) (symbolValue - offset + addend);
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(false));
|
||||
|
||||
// if this a BLX instruction, must set bit24 to identify half-word
|
||||
if ((oldValue & 0xf0000000) == 0xf0000000) {
|
||||
newValue = (oldValue & 0xfe000000) | (((newValue >> 1) & 1) << 24) |
|
||||
@ -132,7 +145,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case ARM_ElfRelocationConstants.R_ARM_LDR_PC_G0: { // Target class: ARM Instruction
|
||||
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue -= (offset + 8); // PC relative, PC will be 8 bytes after inst start
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(false));
|
||||
newValue = (oldValue & 0xff7ff000) | ((~(newValue >> 31) & 1) << 23) |
|
||||
((newValue >> 2) & 0xfff);
|
||||
memory.setInt(relocationAddress, newValue, instructionBigEndian);
|
||||
@ -303,8 +316,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
case ARM_ElfRelocationConstants.R_ARM_GOT_PLT32:
|
||||
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
||||
newValue = (int) (symbolValue + addend);
|
||||
|
||||
newValue -= (offset + 8); // PC relative, PC will be 8 bytes past inst start
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(false));
|
||||
|
||||
// is this a BLX instruction, must put the lower half word in bit24
|
||||
// TODO: this might not appear on a BLX, but just in case
|
||||
@ -404,7 +416,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
if (type == ARM_ElfRelocationConstants.R_ARM_THM_MOVW_PREL_NC ||
|
||||
type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_PREL) {
|
||||
value -= (offset + 4); // PC relative, PC will be 4 bytes past inst start
|
||||
value -= (offset + elfRelocationContext.getPcBias(true));
|
||||
}
|
||||
if (type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_ABS ||
|
||||
type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_PREL ||
|
||||
@ -574,7 +586,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
addend = (oldValue << 21 >> 20); // extract addend and sign-extend with *2 factor
|
||||
}
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue -= offset; // PC relative
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||
newValue = (oldValue & 0x0000f800) | ((newValue >> 1) & 0x000007ff);
|
||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||
break;
|
||||
@ -585,7 +597,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
addend = (oldValue << 24 >> 23); // extract addend and sign-extend with *2 factor
|
||||
}
|
||||
newValue = (int) (symbolValue + addend);
|
||||
newValue -= offset; // PC relative
|
||||
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||
newValue = (oldValue & 0x0000ff00) | ((newValue >> 1) & 0x000000ff);
|
||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user