mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 06:34:58 +08:00
Merge remote-tracking branch 'origin/GP-2041_ghidra1_ElfArmPCBiasOption--SQUASHED'
This commit is contained in:
@@ -37,6 +37,15 @@ public interface ElfLoadHelper {
|
|||||||
*/
|
*/
|
||||||
Program getProgram();
|
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
|
* Get ELF Header object
|
||||||
* @return ELF Header object
|
* @return ELF Header object
|
||||||
|
|||||||
+11
-2
@@ -18,9 +18,9 @@ package ghidra.app.util.bin.format.elf.extend;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
import ghidra.app.util.Option;
|
||||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
import ghidra.app.util.bin.format.elf.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
@@ -512,4 +512,13 @@ public class ElfLoadAdapter {
|
|||||||
return null;
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -22,6 +22,8 @@ import ghidra.app.util.OptionUtils;
|
|||||||
import ghidra.app.util.bin.ByteProvider;
|
import ghidra.app.util.bin.ByteProvider;
|
||||||
import ghidra.app.util.bin.format.elf.ElfException;
|
import ghidra.app.util.bin.format.elf.ElfException;
|
||||||
import ghidra.app.util.bin.format.elf.ElfHeader;
|
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.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.util.NumericUtilities;
|
import ghidra.util.NumericUtilities;
|
||||||
@@ -87,6 +89,12 @@ public class ElfLoaderOptionsFactory {
|
|||||||
options.add(
|
options.add(
|
||||||
new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT,
|
new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT,
|
||||||
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-resolveExternalSymbols"));
|
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) {
|
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 org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||||
import ghidra.app.util.MemoryBlockUtils;
|
import ghidra.app.util.*;
|
||||||
import ghidra.app.util.Option;
|
|
||||||
import ghidra.app.util.bin.*;
|
import ghidra.app.util.bin.*;
|
||||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
import ghidra.app.util.bin.format.elf.*;
|
||||||
@@ -94,6 +93,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||||||
listing = program.getListing();
|
listing = program.getListing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T getOption(String optionName, T defaultValue) {
|
||||||
|
return OptionUtils.getOption(optionName, options, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElfHeader getElfHeader() {
|
public ElfHeader getElfHeader() {
|
||||||
return elf;
|
return elf;
|
||||||
|
|||||||
+39
@@ -15,19 +15,33 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.elf.extend;
|
package ghidra.app.util.bin.format.elf.extend;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.util.Option;
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
import ghidra.app.util.bin.format.elf.*;
|
||||||
|
import ghidra.app.util.opinion.Loader;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
import ghidra.program.model.listing.ContextChangeException;
|
import ghidra.program.model.listing.ContextChangeException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class ARM_ElfExtension extends ElfExtension {
|
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
|
// Elf Program Header Extensions
|
||||||
public static final ElfProgramHeaderType PT_ARM_EXIDX =
|
public static final ElfProgramHeaderType PT_ARM_EXIDX =
|
||||||
new ElfProgramHeaderType(0x70000000, "PT_ARM_EXIDX", "Frame unwind information");
|
new ElfProgramHeaderType(0x70000000, "PT_ARM_EXIDX", "Frame unwind information");
|
||||||
@@ -62,6 +76,31 @@ public class ARM_ElfExtension extends ElfExtension {
|
|||||||
return "_ARM";
|
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
|
@Override
|
||||||
public void processElf(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
public void processElf(ElfLoadHelper elfLoadHelper, TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|||||||
+67
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+22
-10
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.elf.relocation;
|
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.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
@@ -24,6 +26,12 @@ import ghidra.util.exception.NotFoundException;
|
|||||||
|
|
||||||
public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
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
|
@Override
|
||||||
public boolean canRelocate(ElfHeader elf) {
|
public boolean canRelocate(ElfHeader elf) {
|
||||||
return elf.e_machine() == ElfConstants.EM_ARM;
|
return elf.e_machine() == ElfConstants.EM_ARM;
|
||||||
@@ -35,14 +43,17 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
public void relocate(ElfRelocationContext context, ElfRelocation relocation,
|
||||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||||
|
|
||||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
ElfHeader elf = context.getElfHeader();
|
||||||
if (elf.e_machine() != ElfConstants.EM_ARM) {
|
if (elf.e_machine() != ElfConstants.EM_ARM ||
|
||||||
|
!(context instanceof ARM_ElfRelocationContext)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARM_ElfRelocationContext elfRelocationContext = (ARM_ElfRelocationContext) context;
|
||||||
|
|
||||||
Program program = elfRelocationContext.getProgram();
|
Program program = elfRelocationContext.getProgram();
|
||||||
|
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
@@ -75,7 +86,9 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
|||||||
if (elfRelocationContext.extractAddend()) {
|
if (elfRelocationContext.extractAddend()) {
|
||||||
addend = (oldValue << 8 >> 6); // extract addend and sign-extend with *4 factor
|
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 this a BLX instruction, must set bit24 to identify half-word
|
||||||
if ((oldValue & 0xf0000000) == 0xf0000000) {
|
if ((oldValue & 0xf0000000) == 0xf0000000) {
|
||||||
newValue = (oldValue & 0xfe000000) | (((newValue >> 1) & 1) << 24) |
|
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
|
case ARM_ElfRelocationConstants.R_ARM_LDR_PC_G0: { // Target class: ARM Instruction
|
||||||
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
||||||
newValue = (int) (symbolValue + addend);
|
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 = (oldValue & 0xff7ff000) | ((~(newValue >> 31) & 1) << 23) |
|
||||||
((newValue >> 2) & 0xfff);
|
((newValue >> 2) & 0xfff);
|
||||||
memory.setInt(relocationAddress, newValue, instructionBigEndian);
|
memory.setInt(relocationAddress, newValue, instructionBigEndian);
|
||||||
@@ -303,8 +316,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
|||||||
case ARM_ElfRelocationConstants.R_ARM_GOT_PLT32:
|
case ARM_ElfRelocationConstants.R_ARM_GOT_PLT32:
|
||||||
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
int oldValue = memory.getInt(relocationAddress, instructionBigEndian);
|
||||||
newValue = (int) (symbolValue + addend);
|
newValue = (int) (symbolValue + addend);
|
||||||
|
newValue -= (offset + elfRelocationContext.getPcBias(false));
|
||||||
newValue -= (offset + 8); // PC relative, PC will be 8 bytes past inst start
|
|
||||||
|
|
||||||
// is this a BLX instruction, must put the lower half word in bit24
|
// 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
|
// 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 ||
|
if (type == ARM_ElfRelocationConstants.R_ARM_THM_MOVW_PREL_NC ||
|
||||||
type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_PREL) {
|
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 ||
|
if (type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_ABS ||
|
||||||
type == ARM_ElfRelocationConstants.R_ARM_THM_MOVT_PREL ||
|
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
|
addend = (oldValue << 21 >> 20); // extract addend and sign-extend with *2 factor
|
||||||
}
|
}
|
||||||
newValue = (int) (symbolValue + addend);
|
newValue = (int) (symbolValue + addend);
|
||||||
newValue -= offset; // PC relative
|
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||||
newValue = (oldValue & 0x0000f800) | ((newValue >> 1) & 0x000007ff);
|
newValue = (oldValue & 0x0000f800) | ((newValue >> 1) & 0x000007ff);
|
||||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||||
break;
|
break;
|
||||||
@@ -585,7 +597,7 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
|
|||||||
addend = (oldValue << 24 >> 23); // extract addend and sign-extend with *2 factor
|
addend = (oldValue << 24 >> 23); // extract addend and sign-extend with *2 factor
|
||||||
}
|
}
|
||||||
newValue = (int) (symbolValue + addend);
|
newValue = (int) (symbolValue + addend);
|
||||||
newValue -= offset; // PC relative
|
newValue -= (offset + elfRelocationContext.getPcBias(true)); // PC relative
|
||||||
newValue = (oldValue & 0x0000ff00) | ((newValue >> 1) & 0x000000ff);
|
newValue = (oldValue & 0x0000ff00) | ((newValue >> 1) & 0x000000ff);
|
||||||
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
memory.setShort(relocationAddress, (short) newValue, instructionBigEndian);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user