mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-23 13:16:48 +08:00
Merge remote-tracking branch 'origin/GP-1090_ghidra1_ElfSH4RelocHandler--SQUASHED' into patch
This commit is contained in:
@@ -34,7 +34,6 @@ import ghidra.app.util.bin.format.elf.extend.ElfLoadAdapter;
|
||||
import ghidra.app.util.bin.format.elf.relocation.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.mem.FileBytes;
|
||||
import ghidra.program.database.register.AddressRangeObjectMap;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -136,7 +135,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
resolve(monitor);
|
||||
|
||||
if (elf.e_shnum() == 0) {
|
||||
// create/expand segments to their fullsize if not sections are defined
|
||||
// create/expand segments to their fullsize if no sections are defined
|
||||
expandProgramHeaderBlocks(monitor);
|
||||
}
|
||||
|
||||
@@ -146,8 +145,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
pruneDiscardableBlocks();
|
||||
|
||||
markupElfHeader(monitor);
|
||||
markupProgramHeaders(monitor);
|
||||
markupSectionHeaders(monitor);
|
||||
@@ -183,10 +180,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustSegmentAndSectionFileAllocations(ByteProvider byteProvider)
|
||||
private void adjustSegmentAndSectionFileAllocations(
|
||||
ByteProvider byteProvider)
|
||||
throws IOException {
|
||||
|
||||
// Identify file ranges not consumed by segments and sections
|
||||
// Identify file ranges not allocated to segments or sections
|
||||
RangeMap fileMap = new RangeMap();
|
||||
fileMap.paintRange(0, byteProvider.length() - 1, -1); // -1: unallocated
|
||||
|
||||
@@ -220,17 +218,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
|
||||
// Ignore header regions which will always be allocated to blocks
|
||||
int elfHeaderSize = elf.toDataType().getLength();
|
||||
fileMap.paintRange(0, elfHeaderSize - 1, -4);
|
||||
fileMap.paintRange(0, elfHeaderSize - 1, -4); // -4: header block
|
||||
int programHeaderSize = elf.e_phentsize() * elf.e_phnum();
|
||||
if (programHeaderSize != 0) {
|
||||
fileMap.paintRange(elf.e_phoff(), elf.e_phoff() + programHeaderSize - 1, -4);
|
||||
fileMap.paintRange(elf.e_phoff(), elf.e_phoff() + programHeaderSize - 1, -4); // -4: header block
|
||||
}
|
||||
int sectionHeaderSize = elf.e_shentsize() * elf.e_shnum();
|
||||
if (sectionHeaderSize != 0) {
|
||||
fileMap.paintRange(elf.e_shoff(), elf.e_shoff() + sectionHeaderSize - 1, -4);
|
||||
fileMap.paintRange(elf.e_shoff(), elf.e_shoff() + sectionHeaderSize - 1, -4); // -4: header block
|
||||
}
|
||||
|
||||
// Unused file ranges - add as OTHER blocks
|
||||
// Add unallocated non-zero file regions as OTHER blocks
|
||||
IndexRangeIterator rangeIterator = fileMap.getIndexRangeIterator(0);
|
||||
int unallocatedIndex = 0;
|
||||
while (rangeIterator.hasNext()) {
|
||||
@@ -239,10 +237,18 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
if (value != -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
long start = range.getStart();
|
||||
long length = range.getEnd() - start + 1;
|
||||
|
||||
if (isZeroFilledFileRegion(byteProvider, start, length)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = UNALLOCATED_NAME_PREFIX + unallocatedIndex++;
|
||||
try {
|
||||
addInitializedMemorySection(null, range.getStart(),
|
||||
range.getEnd() - range.getStart() + 1, AddressSpace.OTHER_SPACE.getMinAddress(),
|
||||
addInitializedMemorySection(null, start, length,
|
||||
AddressSpace.OTHER_SPACE.getMinAddress(),
|
||||
name, false, false, false, null, false, false);
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
@@ -251,45 +257,19 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void pruneDiscardableBlocks() {
|
||||
try {
|
||||
for (MemoryBlock block : memory.getBlocks()) {
|
||||
long size = block.getSize();
|
||||
// prune any zero-filled unallocated block or segment blocks smaller than DISCARDABLE_SEGMENT_SIZE
|
||||
if (!block.getName().startsWith(UNALLOCATED_NAME_PREFIX)) {
|
||||
// Don't prune segments when sections are absent
|
||||
if (elf.e_shnum() == 0 || size > DISCARDABLE_SEGMENT_SIZE ||
|
||||
!block.getName().startsWith(SEGMENT_NAME_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isZeroFilledBlock(block)) {
|
||||
Msg.debug(this,
|
||||
"Removing discardable alignment/filler segment at " + block.getStart());
|
||||
memory.removeBlock(block, TaskMonitor.DUMMY);
|
||||
}
|
||||
}
|
||||
private boolean isZeroFilledFileRegion(ByteProvider byteProvider, long start, long length)
|
||||
throws IOException {
|
||||
int bufSize = 16 * 1024;
|
||||
if (length < bufSize) {
|
||||
bufSize = (int) length;
|
||||
}
|
||||
catch (LockException | MemoryAccessException e) {
|
||||
throw new AssertException(e); // should never happen
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isZeroFilledBlock(MemoryBlock block) throws MemoryAccessException {
|
||||
int bufSize = 8 * 1024;
|
||||
long blockSize = block.getSize();
|
||||
if (blockSize < bufSize) {
|
||||
bufSize = (int) blockSize;
|
||||
}
|
||||
byte[] bytes = new byte[bufSize];
|
||||
Address addr = block.getStart();
|
||||
long cnt = 0;
|
||||
while (cnt < blockSize) {
|
||||
int readLen = block.getBytes(addr.add(cnt), bytes, 0, bufSize);
|
||||
if (readLen <= 0 || !isZeroedArray(bytes, readLen)) {
|
||||
long remaining = length;
|
||||
while (remaining > 0) {
|
||||
byte[] bytes = byteProvider.readBytes(start, Math.min(remaining, bufSize));
|
||||
if (!isZeroedArray(bytes, bytes.length)) {
|
||||
return false;
|
||||
}
|
||||
cnt += readLen;
|
||||
remaining -= bytes.length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -303,6 +283,29 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isDiscardableFillerSegment(MemoryLoadable loadable, String blockName,
|
||||
Address start, long fileOffset, long length) throws IOException {
|
||||
if (elf.e_shnum() == 0 || elf.e_phnum() == 0) {
|
||||
return false; // only prune if both sections and program headers are present
|
||||
}
|
||||
if (length > DISCARDABLE_SEGMENT_SIZE || !blockName.startsWith(SEGMENT_NAME_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elf.getLoadAdapter().hasFilteredLoadInputStream(this, loadable, start)) {
|
||||
// block is unable to map directly to file bytes - read from filtered input stream
|
||||
try (InputStream dataInput =
|
||||
getInitializedBlockInputStream(loadable, start, fileOffset, length)) {
|
||||
byte[] bytes = new byte[(int) length];
|
||||
return dataInput.read(bytes) == bytes.length && isZeroedArray(bytes, bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[(int) length];
|
||||
return fileBytes.getModifiedBytes(fileOffset, bytes) == bytes.length &&
|
||||
isZeroedArray(bytes, bytes.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageLog getLog() {
|
||||
return log;
|
||||
@@ -3220,11 +3223,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
boolean w, boolean x, TaskMonitor monitor)
|
||||
throws IOException, AddressOverflowException, CancelledException {
|
||||
|
||||
long revisedLength = checkBlockLimit(name, dataLength, true);
|
||||
|
||||
if (isDiscardableFillerSegment(loadable, name, start, fileOffset, dataLength)) {
|
||||
Msg.debug(this,
|
||||
"Discarding " + dataLength + "-byte alignment/filler " + name + " at " + start);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: MemoryBlockUtil poorly and inconsistently handles duplicate name errors (can throw RuntimeException).
|
||||
// Are we immune from such errors? If not, how should they be handled?
|
||||
|
||||
long revisedLength = checkBlockLimit(name, dataLength, true);
|
||||
|
||||
if (start.isNonLoadedMemoryAddress()) {
|
||||
r = false;
|
||||
w = false;
|
||||
@@ -3245,19 +3254,32 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
blockComment += " (section truncated)";
|
||||
}
|
||||
|
||||
if (elf.getLoadAdapter().hasFilteredLoadInputStream(this, loadable, start)) {
|
||||
// block is unable to map directly to file bytes - load from input stream
|
||||
try (InputStream dataInput =
|
||||
getInitializedBlockInputStream(loadable, start, fileOffset, revisedLength)) {
|
||||
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start,
|
||||
dataInput, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log,
|
||||
monitor);
|
||||
MemoryBlock block = null;
|
||||
try {
|
||||
if (elf.getLoadAdapter().hasFilteredLoadInputStream(this, loadable, start)) {
|
||||
// block is unable to map directly to file bytes - load from input stream
|
||||
try (InputStream dataInput =
|
||||
getInitializedBlockInputStream(loadable, start, fileOffset, revisedLength)) {
|
||||
block = MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start,
|
||||
dataInput, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log,
|
||||
monitor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// create block using direct mapping to file bytes
|
||||
block = MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start,
|
||||
fileBytes, fileOffset, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x,
|
||||
log);
|
||||
}
|
||||
}
|
||||
|
||||
// create block using direct mapping to file bytes
|
||||
return MemoryBlockUtils.createInitializedBlock(program, isOverlay, name, start, fileBytes,
|
||||
fileOffset, revisedLength, blockComment, BLOCK_SOURCE_NAME, r, w, x, log);
|
||||
finally {
|
||||
if (block == null) {
|
||||
Address end = start.addNoWrap(revisedLength - 1);
|
||||
Msg.error(this, "Unexpected ELF memory bock load conflict when creating '" + name +
|
||||
"' at " + start.toString(true) + "-" + end.toString(true));
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -368,18 +368,12 @@ public abstract class MemorySectionResolver {
|
||||
maxAddr = block.getEnd();
|
||||
}
|
||||
else {
|
||||
// block may be null due to unexpected conflict
|
||||
// block may be null due to unexpected conflict - allow to continue
|
||||
block = createInitializedBlock(section.key, false, blockName, address,
|
||||
fileOffset, rangeSize, section.getComment(), section.isReadable(),
|
||||
section.isWritable(), section.isExecute(), monitor);
|
||||
minAddr = address;
|
||||
maxAddr = address.addNoWrap(rangeSize - 1);
|
||||
if (block == null) {
|
||||
// This is a bug but allow load to continue by not referring to block below
|
||||
Msg.error(this,
|
||||
"Unexpected ELF memory bock load conflict when creating '" + blockName +
|
||||
"' at " + minAddr.toString(true) + "-" + maxAddr.toString(true));
|
||||
}
|
||||
}
|
||||
if (fileLoadRangeMap != null) {
|
||||
long chunkFileOffset = section.getFileOffset() + sectionByteOffset;
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.plugin.core.reloc.RelocationFixupHandler;
|
||||
import ghidra.app.util.opinion.ElfLoader;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Processor;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.reloc.Relocation;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
|
||||
public class ElfSH4RelocationFixupHandler extends RelocationFixupHandler {
|
||||
|
||||
@Override
|
||||
public boolean processRelocation(Program program, Relocation relocation, Address oldImageBase,
|
||||
Address newImageBase) throws MemoryAccessException, CodeUnitInsertionException {
|
||||
|
||||
switch (relocation.getType()) {
|
||||
case SH_ElfRelocationConstants.R_SH_DIR32:
|
||||
case SH_ElfRelocationConstants.R_SH_REL32:
|
||||
return process32BitRelocation(program, relocation, oldImageBase, newImageBase);
|
||||
|
||||
// case SH_ElfRelocationConstants.R_SH_DIR8WPN:
|
||||
// case SH_ElfRelocationConstants.R_SH_DIR8WPZ:
|
||||
// case SH_ElfRelocationConstants.R_SH_IND12W:
|
||||
// case SH_ElfRelocationConstants.R_SH_DIR8WPL:
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlesProgram(Program program) {
|
||||
if (!ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) {
|
||||
return false;
|
||||
}
|
||||
Language language = program.getLanguage();
|
||||
if (language.getLanguageDescription().getSize() != 32) {
|
||||
return false;
|
||||
}
|
||||
Processor processor = language.getProcessor();
|
||||
return ("SuperH4".equals(processor.toString()) || "SuperH".equals(processor.toString()));
|
||||
}
|
||||
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/* ###
|
||||
* 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;
|
||||
|
||||
public class SH_ElfRelocationConstants {
|
||||
|
||||
public static final int R_SH_NONE = 0; // No operation needed
|
||||
public static final int R_SH_DIR32 = 1; // (S + A) */
|
||||
public static final int R_SH_REL32 = 2; // (S + A) - P
|
||||
public static final int R_SH_DIR8WPN = 3; // 8-bit PC relative branch divided by 2 : (((S + A) - P) >> 1) & 0xff
|
||||
public static final int R_SH_IND12W = 4; // 12-bit PC relative branch divided by 2 : (((S + A) - P) >> 1) & 0xfff
|
||||
public static final int R_SH_DIR8WPL = 5; // 8-bit PC unsigned-relative branch divided by 4 : (((S + A) - P) >> 2) & 0xff
|
||||
public static final int R_SH_DIR8WPZ = 6; // 8-bit PC unsigned-relative branch divided by 2 : (((S + A) - P) >> 1) & 0xff
|
||||
public static final int R_SH_DIR8BP = 7;
|
||||
public static final int R_SH_DIR8W = 8;
|
||||
public static final int R_SH_DIR8L = 9;
|
||||
|
||||
// Relocation numbering in this file corresponds to GNU binutils and
|
||||
// values below this point may differ significantly from those specified
|
||||
// for other uses (e.g., see https://android.googlesource.com/platform/external/elfutils/+/android-4.1.2_r1/libelf/elf.h )
|
||||
|
||||
public static final int R_SH_LOOP_START = 10;
|
||||
public static final int R_SH_LOOP_END = 11;
|
||||
|
||||
public static final int R_SH_GNU_VTINHERIT = 22;
|
||||
public static final int R_SH_GNU_VTENTRY = 23;
|
||||
public static final int R_SH_SWITCH8 = 24;
|
||||
|
||||
public static final int R_SH_SWITCH16 = 25;
|
||||
public static final int R_SH_SWITCH32 = 26;
|
||||
public static final int R_SH_USES = 27;
|
||||
public static final int R_SH_COUNT = 28;
|
||||
public static final int R_SH_ALIGN = 29;
|
||||
public static final int R_SH_CODE = 30;
|
||||
public static final int R_SH_DATA = 31;
|
||||
public static final int R_SH_LABEL = 32;
|
||||
|
||||
public static final int R_SH_DIR16 = 33;
|
||||
public static final int R_SH_DIR8 = 34;
|
||||
public static final int R_SH_DIR8UL = 35;
|
||||
public static final int R_SH_DIR8UW = 36;
|
||||
public static final int R_SH_DIR8U = 37;
|
||||
public static final int R_SH_DIR8SW = 38;
|
||||
public static final int R_SH_DIR8S = 39;
|
||||
public static final int R_SH_DIR4UL = 40;
|
||||
public static final int R_SH_DIR4UW = 41;
|
||||
public static final int R_SH_DIR4U = 42;
|
||||
public static final int R_SH_PSHA = 43;
|
||||
public static final int R_SH_PSHL = 44;
|
||||
public static final int R_SH_DIR5U = 45;
|
||||
public static final int R_SH_DIR6U = 46;
|
||||
public static final int R_SH_DIR6S = 47;
|
||||
public static final int R_SH_DIR10S = 48;
|
||||
public static final int R_SH_DIR10SW = 49;
|
||||
public static final int R_SH_DIR10SL = 50;
|
||||
public static final int R_SH_DIR10SQ = 51;
|
||||
|
||||
public static final int R_SH_DIR16S = 53;
|
||||
|
||||
public static final int R_SH_TLS_GD_32 = 144;
|
||||
public static final int R_SH_TLS_LD_32 = 145;
|
||||
public static final int R_SH_TLS_LDO_32 = 146;
|
||||
public static final int R_SH_TLS_IE_32 = 147;
|
||||
public static final int R_SH_TLS_LE_32 = 148;
|
||||
public static final int R_SH_TLS_DTPMOD32 = 149;
|
||||
public static final int R_SH_TLS_DTPOFF32 = 150;
|
||||
public static final int R_SH_TLS_TPOFF32 = 151;
|
||||
|
||||
public static final int R_SH_GOT32 = 160;
|
||||
public static final int R_SH_PLT32 = 161;
|
||||
public static final int R_SH_COPY = 162;
|
||||
public static final int R_SH_GLOB_DAT = 163;
|
||||
public static final int R_SH_JMP_SLOT = 164;
|
||||
public static final int R_SH_RELATIVE = 165;
|
||||
public static final int R_SH_GOTOFF = 166;
|
||||
public static final int R_SH_GOTPC = 167;
|
||||
public static final int R_SH_GOTPLT32 = 168;
|
||||
public static final int R_SH_GOT_LOW16 = 169;
|
||||
public static final int R_SH_GOT_MEDLOW16 = 170;
|
||||
public static final int R_SH_GOT_MEDHI16 = 171;
|
||||
public static final int R_SH_GOT_HI16 = 172;
|
||||
public static final int R_SH_GOTPLT_LOW16 = 173;
|
||||
public static final int R_SH_GOTPLT_MEDLOW16 = 174;
|
||||
public static final int R_SH_GOTPLT_MEDHI16 = 175;
|
||||
public static final int R_SH_GOTPLT_HI16 = 176;
|
||||
public static final int R_SH_PLT_LOW16 = 177;
|
||||
public static final int R_SH_PLT_MEDLOW16 = 178;
|
||||
public static final int R_SH_PLT_MEDHI16 = 179;
|
||||
public static final int R_SH_PLT_HI16 = 180;
|
||||
public static final int R_SH_GOTOFF_LOW16 = 181;
|
||||
public static final int R_SH_GOTOFF_MEDLOW16 = 182;
|
||||
public static final int R_SH_GOTOFF_MEDHI16 = 183;
|
||||
public static final int R_SH_GOTOFF_HI16 = 184;
|
||||
public static final int R_SH_GOTPC_LOW16 = 185;
|
||||
public static final int R_SH_GOTPC_MEDLOW16 = 186;
|
||||
public static final int R_SH_GOTPC_MEDHI16 = 187;
|
||||
public static final int R_SH_GOTPC_HI16 = 188;
|
||||
public static final int R_SH_GOT10BY4 = 189;
|
||||
public static final int R_SH_GOTPLT10BY4 = 190;
|
||||
public static final int R_SH_GOT10BY8 = 191;
|
||||
public static final int R_SH_GOTPLT10BY8 = 192;
|
||||
public static final int R_SH_COPY64 = 193;
|
||||
public static final int R_SH_GLOB_DAT64 = 194;
|
||||
public static final int R_SH_JMP_SLOT64 = 195;
|
||||
public static final int R_SH_RELATIVE64 = 196;
|
||||
|
||||
public static final int R_SH_SHMEDIA_CODE = 242;
|
||||
public static final int R_SH_PT_16 = 243;
|
||||
public static final int R_SH_IMMS16 = 244;
|
||||
public static final int R_SH_IMMU16 = 245;
|
||||
public static final int R_SH_IMM_LOW16 = 246;
|
||||
public static final int R_SH_IMM_LOW16_PCREL = 247;
|
||||
public static final int R_SH_IMM_MEDLOW16 = 248;
|
||||
public static final int R_SH_IMM_MEDLOW16_PCREL = 249;
|
||||
public static final int R_SH_IMM_MEDHI16 = 250;
|
||||
public static final int R_SH_IMM_MEDHI16_PCREL = 251;
|
||||
public static final int R_SH_IMM_HI16 = 252;
|
||||
public static final int R_SH_IMM_HI16_PCREL = 253;
|
||||
public static final int R_SH_64 = 254;
|
||||
public static final int R_SH_64_PCREL = 255;
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/* ###
|
||||
* 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 ghidra.app.util.bin.format.elf.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
public class SH_ElfRelocationHandler extends ElfRelocationHandler {
|
||||
|
||||
@Override
|
||||
public boolean canRelocate(ElfHeader elf) {
|
||||
return elf.e_machine() == ElfConstants.EM_SH && elf.is32Bit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
|
||||
Address relocationAddress) throws MemoryAccessException, NotFoundException {
|
||||
|
||||
ElfHeader elf = elfRelocationContext.getElfHeader();
|
||||
if (elf.e_machine() != ElfConstants.EM_SH || !elf.is32Bit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Program program = elfRelocationContext.getProgram();
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
|
||||
int type = relocation.getType();
|
||||
if (type == SH_ElfRelocationConstants.R_SH_NONE) {
|
||||
return;
|
||||
}
|
||||
int symbolIndex = relocation.getSymbolIndex();
|
||||
|
||||
int addend = (int) relocation.getAddend();
|
||||
|
||||
ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex);
|
||||
String symbolName = sym.getNameAsString();
|
||||
|
||||
int offset = (int) relocationAddress.getOffset();
|
||||
|
||||
Address symbolAddr = elfRelocationContext.getSymbolAddress(sym);
|
||||
int symbolValue = (int) elfRelocationContext.getSymbolValue(sym);
|
||||
|
||||
int newValue = 0;
|
||||
|
||||
switch (type) {
|
||||
case SH_ElfRelocationConstants.R_SH_DIR32: { //32 bit absolute relocation
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = memory.getInt(relocationAddress);
|
||||
}
|
||||
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
|
||||
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
|
||||
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
|
||||
}
|
||||
newValue = symbolValue + addend;
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
break;
|
||||
}
|
||||
case SH_ElfRelocationConstants.R_SH_REL32: { // 32 bit PC relative relocation
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = memory.getInt(relocationAddress);
|
||||
}
|
||||
newValue = (symbolValue + addend) - offset;
|
||||
memory.setInt(relocationAddress, newValue);
|
||||
break;
|
||||
}
|
||||
case SH_ElfRelocationConstants.R_SH_DIR8WPN: // 8-bit PC relative branch divided by 2
|
||||
case SH_ElfRelocationConstants.R_SH_DIR8WPZ: { // 8-bit PC unsigned-relative branch divided by 2
|
||||
short oldShortValue = memory.getShort(relocationAddress);
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = oldShortValue & 0xff;
|
||||
if (type == SH_ElfRelocationConstants.R_SH_DIR8WPN && (addend & 0x80) != 0) {
|
||||
addend -= 0x100; // sign-extend addend for R_SH_DIR8WPN
|
||||
}
|
||||
}
|
||||
newValue = ((symbolValue + addend) - offset) >> 1;
|
||||
newValue = (oldShortValue & 0xff00) | (newValue & 0xff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
break;
|
||||
}
|
||||
case SH_ElfRelocationConstants.R_SH_IND12W: { // 12-bit PC relative branch divided by 2
|
||||
short oldShortValue = memory.getShort(relocationAddress);
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = oldShortValue & 0xfff;
|
||||
if ((addend & 0x800) != 0) {
|
||||
addend -= 0x1000; // sign-extend addend
|
||||
}
|
||||
}
|
||||
newValue = ((symbolValue + addend) - offset) >> 1;
|
||||
newValue = (oldShortValue & 0xf000) | (newValue & 0xfff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
break;
|
||||
}
|
||||
case SH_ElfRelocationConstants.R_SH_DIR8WPL: { // 8-bit PC unsigned-relative branch divided by 4
|
||||
short oldShortValue = memory.getShort(relocationAddress);
|
||||
if (elfRelocationContext.extractAddend()) {
|
||||
addend = oldShortValue & 0xff;
|
||||
}
|
||||
newValue = ((symbolValue + addend) - offset) >> 2;
|
||||
newValue = (oldShortValue & 0xff00) | (newValue & 0xff);
|
||||
memory.setShort(relocationAddress, (short) newValue);
|
||||
break;
|
||||
}
|
||||
|
||||
case SH_ElfRelocationConstants.R_SH_COPY: {
|
||||
markAsWarning(program, relocationAddress, "R_SH_COPY", symbolName, symbolIndex,
|
||||
"Runtime copy not supported", elfRelocationContext.getLog());
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
|
||||
elfRelocationContext.getLog());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user