From e83e62d01d25a98499548324c8f80754d53a2f5c Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 28 Aug 2023 11:45:17 -0400 Subject: [PATCH] GP-3792 correct ELF RISCV branch/jump relocations --- .../RISCV_ElfRelocationHandler.java | 81 +++++++++++-------- 1 file changed, 47 insertions(+), 34 deletions(-) diff --git a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java index 8fda8c2861..a09e402637 100644 --- a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java +++ b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java @@ -163,8 +163,8 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { value32 = (int) (symbolValue + addend); memory.setInt(relocationAddress, value32); if (symbolIndex != 0 && addend != 0 && !sym.isSection()) { - warnExternalOffsetRelocation(program, relocationAddress, - symbolAddr, symbolName, addend, elfRelocationContext.getLog()); + warnExternalOffsetRelocation(program, relocationAddress, symbolAddr, symbolName, + addend, elfRelocationContext.getLog()); if (elf.is32Bit()) { applyComponentOffsetPointer(program, relocationAddress, addend); } @@ -177,8 +177,8 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { memory.setLong(relocationAddress, value64); byteLength = 8; if (symbolIndex != 0 && addend != 0 && !sym.isSection()) { - warnExternalOffsetRelocation(program, relocationAddress, - symbolAddr, symbolName, addend, elfRelocationContext.getLog()); + warnExternalOffsetRelocation(program, relocationAddress, symbolAddr, symbolName, + addend, elfRelocationContext.getLog()); if (elf.is64Bit()) { applyComponentOffsetPointer(program, relocationAddress, addend); } @@ -254,20 +254,18 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { return RelocationResult.UNSUPPORTED; case RISCV_ElfRelocationConstants.R_RISCV_BRANCH: - // PC-relative branch (B-Type) + // PC-relative branch (SB-Type) target = (int) (addend + symbolValue - offset); - value32 = - ((target & 0x01e) << 7) | ((target & 0x0800) >> 4) | ((target & 0x03e0) << 20) | - ((target & 0x1000) << 19) | (memory.getInt(relocationAddress) & 0x1fff07f); + value32 = encodeSBTypeImm(target) | + (memory.getInt(relocationAddress) & ~encodeSBTypeImm(-1)); memory.setInt(relocationAddress, value32); break; case RISCV_ElfRelocationConstants.R_RISCV_JAL: - // PC-relative jump (J-Type) + // PC-relative jump (UJ-Type) target = (int) (addend + symbolValue - offset); - value32 = - (target & 0xff000) | ((target & 0x00800) << 9) | ((target & 0x007fe) << 20) | - ((target & 0x100000) << 11) | (memory.getInt(relocationAddress) & 0xfff); + value32 = encodeUJTypeImm(target) | + (memory.getInt(relocationAddress) & ~encodeUJTypeImm(-1)); memory.setInt(relocationAddress, value32); break; @@ -340,17 +338,15 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { case RISCV_ElfRelocationConstants.R_RISCV_HI20: // Absolute address %hi(symbol) (U-Type) - value32 = - (int) ((symbolValue + 0x800) & 0xfffff000) | - (memory.getInt(relocationAddress) & 0xfff); + value32 = (int) ((symbolValue + 0x800) & 0xfffff000) | + (memory.getInt(relocationAddress) & 0xfff); memory.setInt(relocationAddress, value32); break; case RISCV_ElfRelocationConstants.R_RISCV_LO12_I: // Absolute address %lo(symbol) (I-Type) - value32 = - ((int) (symbolValue & 0x00000fff) << 20) | - (memory.getInt(relocationAddress) & 0xfffff); + value32 = ((int) (symbolValue & 0x00000fff) << 20) | + (memory.getInt(relocationAddress) & 0xfffff); memory.setInt(relocationAddress, value32); break; @@ -469,29 +465,18 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { case RISCV_ElfRelocationConstants.R_RISCV_RVC_BRANCH: { // PC-relative branch offset (CB-Type) short target_s = (short) (addend + symbolValue - offset); - // 15 13 | 12 11 10|9 7| 6 5 4 3 2|1 0 - // C.BEQZ offset[8|4:3] src offset[7:6|2:1|5] C1 - value16 = (short) (((target_s & 0x100) << 4) | ((target_s & 0x18) << 7) | - ((target_s & 0xc0) >> 1) | - ((target_s & 0x06) << 2) | ((target_s & 0x20) >> 3) | - (memory.getShort(relocationAddress) & 0xe383)); + value16 = (short) (encodeCBTypeImm(target_s) | + (memory.getShort(relocationAddress) & ~encodeCBTypeImm(-1))); memory.setShort(relocationAddress, value16); byteLength = 2; break; } case RISCV_ElfRelocationConstants.R_RISCV_RVC_JUMP: { + // PC-relative jump offset (CJ-Type) short target_s = (short) (addend + symbolValue - offset); - // Complicated swizzling going on here. - // For details, see The RISC-V Instruction Set Manual Volume I: Unprivileged ISA - // 15 13 | 12 11 10 9 8 7 6 5 3 2|1 0 - // C.J offset[11| 4|9:8|10|6|7|3:1|5] C1 - value16 = (short) (((target_s & 0x800) << 1) | ((target_s & 0x10) << 7) | - ((target_s & 0x300) << 1) | - ((target_s & 0x400) >> 2) | ((target_s & 0x40) << 1) | - ((target_s & 0x80) >> 1) | - ((target_s & 0x0e) << 2) | ((target_s & 0x20) >> 3) | - (memory.getShort(relocationAddress) & 0xe003)); + value16 = (short) (encodeCJTypeImm(target_s) | + (memory.getShort(relocationAddress) & ~encodeCJTypeImm(-1))); memory.setShort(relocationAddress, value16); byteLength = 2; break; @@ -574,4 +559,32 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler { } return new RelocationResult(Status.APPLIED, byteLength); } + + private static int getBitField(int val, int shiftRight, int bitSize) { + return ((val >> shiftRight) & ((1 << bitSize) - 1)); + } + + private static int encodeSBTypeImm(int val) { + return (getBitField(val, 1, 4) << 8) | (getBitField(val, 5, 6) << 25) | + (getBitField(val, 11, 1) << 7) | (getBitField(val, 12, 1) << 31); + } + + private static int encodeUJTypeImm(int val) { + return (getBitField(val, 1, 10) << 21) | (getBitField(val, 11, 1) << 20) | + (getBitField(val, 12, 8) << 12) | (getBitField(val, 20, 1) << 31); + } + + private static int encodeCBTypeImm(int val) { + return (getBitField(val, 1, 2) << 3) | (getBitField(val, 3, 2) << 10) | + (getBitField(val, 5, 1) << 2) | (getBitField(val, 6, 2) << 5) | + (getBitField(val, 8, 1) << 12); + } + + private static int encodeCJTypeImm(int val) { + return (getBitField(val, 1, 3) << 3) | (getBitField(val, 4, 1) << 11) | + (getBitField(val, 5, 1) << 2) | (getBitField(val, 6, 1) << 7) | + (getBitField(val, 7, 1) << 6) | (getBitField(val, 8, 2) << 9) | + (getBitField(val, 10, 1) << 8) | (getBitField(val, 11, 1) << 12); + } + }