rizin/librz/bin/format/elf/elf_relocs_patching.c
Khairul Azhar Kasmiran 3204f0c405
Use stdint types for ut64 and friends (#6276)
* Use `stdint` types for `ut64` and friends
* Use `inttypes.h` format specifiers
2026-04-22 21:43:04 +08:00

2991 lines
95 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-FileCopyrightText: 2024-2025 RizinOrg <info@rizin.re>
// SPDX-FileCopyrightText: 2009-2021 nibble <nibble.ds@gmail.com>
// SPDX-FileCopyrightText: 2009-2021 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include "elf.h"
#include "elf/glibc_elf.h"
#include "rz_types.h"
#include "rz_types_base.h"
#include "rz_util/rz_assert.h"
#include "rz_util/rz_buf.h"
#include "rz_util/rz_log.h"
typedef struct reloc_formular_symbols_t {
ut64 A; // Appendend
ut64 B; // Base address
ut64 G; // Offset into GOT for symbol entry.
ut64 GOT; // Address of entry zero in GOT.
ut64 L; // Offset into POT for symbol entry.
ut64 P; // Place address of the field being relocated. The address of the bytes to patch.
ut64 S; // Value of symbol.
ut64 Z; // Size of symbol.
ut64 TLS; // Thread-pointer-relative offset to a thread-local symbol.
ut64 T; // Base address of the static thread-local tmeplate that contains a thread-local symbol.
ut64 MB; // Base address of all strings consumed by compiler message base optimization (Hexagon specific).
ut64 GP; // Value of GP register (Hexagon specific).
ut64 AHL; // Special value used by MIPS to handle R_MIPS_HI16 & R_MIPS_LO16 relocs
/**
* \brief Sparc64: Secondary addend, extracted from the r_info field by
* applying the ELF_SPARC64_R_TYPE_DATA macro (alias for ELF64_R_TYPE_DATA).
*/
ut64 O;
} RelocFormularSymbols;
typedef struct {
ut32 cmpMask; // Opcode bits of instruction.
ut32 relocMask; // Relocation bitmask for patching.
} HexagonRelocMask;
/**
* \brief Maps instructions of the R_HEX_6_X relocation typ
* to its bitmask patched during relocation.
*/
static const HexagonRelocMask hex_rel6_x_masks[] = {
{ 0x38000000, 0x0000201f }, { 0x39000000, 0x0000201f },
{ 0x3e000000, 0x00001f80 }, { 0x3f000000, 0x00001f80 },
{ 0x40000000, 0x000020f8 }, { 0x41000000, 0x000007e0 },
{ 0x42000000, 0x000020f8 }, { 0x43000000, 0x000007e0 },
{ 0x44000000, 0x000020f8 }, { 0x45000000, 0x000007e0 },
{ 0x46000000, 0x000020f8 }, { 0x47000000, 0x000007e0 },
{ 0x6a000000, 0x00001f80 }, { 0x7c000000, 0x001f2000 },
{ 0x9a000000, 0x00000f60 }, { 0x9b000000, 0x00000f60 },
{ 0x9c000000, 0x00000f60 }, { 0x9d000000, 0x00000f60 },
{ 0x9f000000, 0x001f0100 }, { 0xab000000, 0x0000003f },
{ 0xad000000, 0x0000003f }, { 0xaf000000, 0x00030078 },
{ 0xd7000000, 0x006020e0 }, { 0xd8000000, 0x006020e0 },
{ 0xdb000000, 0x006020e0 }, { 0xdf000000, 0x006020e0 }
};
/**
* \brief Returns the bitmask for reloc patching of a Hexagon instruction
* of type R_HEX_6_X.
*
* \param insn The instruction bits.
* \return ut32 The bitmask for patching.
*/
static ut32 hexagon_get_bitmask_r6(ut32 insn) {
if ((insn & 0xc000) == 0) { // Duplex instruction
return 0x03f00000;
}
for (int i = 0; i < sizeof(hex_rel6_x_masks) / sizeof(HexagonRelocMask); ++i) {
if ((0xff000000 & insn) == hex_rel6_x_masks[i].cmpMask) {
return hex_rel6_x_masks[i].relocMask;
}
}
RZ_LOG_ERROR("Unrecognized instruction for 6_X relocation: 0x%x\n", insn);
return 0;
}
/**
* \brief Returns the bitmask for reloc patching of a Hexagon instruction
* of type R_HEX_8_X.
*
* \param insn The instruction bits.
* \return ut32 The bitmask for patching.
*/
static ut32 hexagon_get_bitmask_r8(ut32 insn) {
if ((0xff000000 & insn) == 0xde000000) {
return 0x00e020e8;
}
if ((0xff000000 & insn) == 0x3c000000) {
return 0x0000207f;
}
return 0x00001fe0;
}
/**
* \brief Returns the bitmask for reloc patching of a Hexagon instruction
* of type R_HEX_11_X.
*
* \param insn The instruction bits.
* \return ut32 The bitmask for patching.
*/
static ut32 hexagon_get_bitmask_r11(ut32 insn) {
if ((0xff000000 & insn) == 0xa1000000) {
return 0x060020ff;
}
return 0x06003fe0;
}
/**
* \brief Returns the bitmask for reloc patching of a Hexagon instruction
* of type R_HEX_16_X.
*
* \param insn The instruction bits.
* \return ut32 The bitmask for patching.
*/
static ut32 hexagon_get_bitmask_r16(ut32 insn) {
if ((0xff000000 & insn) == 0x48000000) {
return 0x061f20ff;
}
if ((0xff000000 & insn) == 0x49000000) {
return 0x061f3fe0;
}
if ((0xff000000 & insn) == 0x78000000) {
return 0x00df3fe0;
}
if ((0xff000000 & insn) == 0xb0000000) {
return 0x0fe03fe0;
}
if ((insn & 0xc000) == 0) { // Duplex instruction
return 0x03f00000;
}
for (int i = 0; i < sizeof(hex_rel6_x_masks) / sizeof(HexagonRelocMask); ++i) {
if ((0xff000000 & insn) == hex_rel6_x_masks[i].cmpMask) {
return hex_rel6_x_masks[i].relocMask;
}
}
RZ_LOG_ERROR("Unrecognized instruction for 16_X relocation: 0x%x\n", insn);
return 0;
}
/**
* \brief Patches a given value into an opcode at \p addr in \p buf_patched.
* The bits from \p val are spread into the resulting value according to \p mask.
*
* Often immediated bits in opcodes are not sequential.
* If a relocation value is patched into the opcode,
* its bits must be aligned with bit locations in the opcode.
* The parameter \p mask indicates where the immediate bits are located.
*
* \param buf_patched Pointer to buffer.
* \param big_endian If set reads and writes the buffer in big endian.
* \param addr Address the opcode is located.
* \param mask The bitmask (patchable bits) of the opcode bits to set.
* \param val The value patched into the opcode.
*/
static void patch_val_over_mask_32(RZ_INOUT RzBuffer *buf_patched, bool big_endian, const ut32 addr, const ut32 mask, const ut32 val) {
rz_return_if_fail(buf_patched);
ut8 buf[4] = { 0 };
rz_buf_read_at(buf_patched, addr, buf, 4);
ut32 opcode = rz_read_ble32(buf, big_endian) | rz_bits_spread(mask, val);
rz_write_ble32(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, addr, buf, 4);
}
/**
* \brief Does the same as patch_val_over_mask_32 but for 64bit values.
*/
static void patch_val_over_mask_64(RZ_INOUT RzBuffer *buf_patched, bool big_endian, const ut64 addr, const ut64 mask, const ut64 val) {
rz_return_if_fail(buf_patched);
ut8 buf[8] = { 0 };
rz_buf_read_at(buf_patched, addr, buf, 8);
ut64 opcode = rz_read_ble64(buf, big_endian) | rz_bits_spread(mask, val);
rz_write_ble64(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, addr, buf, 8);
}
/**
* \brief Does the same as patch_val_over_mask_32 but for 16bit values.
*/
static void patch_val_over_mask_16(RZ_INOUT RzBuffer *buf_patched, bool big_endian, const ut64 addr, const ut16 mask, const ut16 val) {
rz_return_if_fail(buf_patched);
ut8 buf[2] = { 0 };
rz_buf_read_at(buf_patched, addr, buf, 2);
ut16 opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(mask, val);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, addr, buf, 2);
}
#define UNHANDL(NAME) \
RZ_LOG_WARN("Unhandled " NAME " reloc\n"); \
return
#define UNHANDL_DEF(NAME, NUM) \
RZ_LOG_WARN(NAME ": Unhandled patching case for relocation %d.\n", NUM)
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols (e.g. TLS, G) are not yet implemented and are set to 0.
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_hexagon(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[8] = { 0 };
ut64 val = 0;
ut64 bitmask = R_HEX_BITMASK_WORD32; // Mask of value and opcode bits.
switch (rel_type) {
default:
// For more implementetations check out the LLVM src:
// https://github.com/llvm/llvm-project/blob/abc17a67519747be36f1fd03e227c5103da4c677/lld/ELF/Arch/Hexagon.cpp
UNHANDL_DEF("Hexagon", rel_type);
return;
case R_HEX_NONE:
return;
case R_HEX_GLOB_DAT:
case R_HEX_JMP_SLOT:
val = (fs->S + fs->A);
break;
case R_HEX_RELATIVE:
val = (fs->B + fs->A);
break;
case R_HEX_B22_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B22;
val = (fs->S + fs->A - fs->P) >> 2;
break;
case R_HEX_B15_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B15;
val = (fs->S + fs->A - fs->P) >> 2;
break;
case R_HEX_B7_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B7;
val = (fs->S + fs->A - fs->P) >> 2;
break;
case R_HEX_LO16:
bitmask = R_HEX_BITMASK_WORD32_LO;
val = (fs->S + fs->A);
break;
case R_HEX_HI16:
bitmask = R_HEX_BITMASK_WORD32_HL;
val = (fs->S + fs->A) >> 16;
break;
case R_HEX_32:
val = (fs->S + fs->A);
break;
case R_HEX_16:
bitmask = R_HEX_BITMASK_WORD16;
val = (fs->S + fs->A);
break;
case R_HEX_8:
bitmask = R_HEX_BITMASK_WORD8;
val = (fs->S + fs->A);
break;
case R_HEX_HL16:
bitmask = R_HEX_BITMASK_WORD32_HL;
val = (fs->S + fs->A);
break;
case R_HEX_B13_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B13;
val = (fs->S + fs->A - fs->P) >> 2;
break;
case R_HEX_B9_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B9;
val = (fs->S + fs->A - fs->P) >> 2;
break;
case R_HEX_B32_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_X26;
val = (fs->S + fs->A - fs->P) >> 6;
break;
case R_HEX_32_6_X:
bitmask = R_HEX_BITMASK_WORD32_X26;
val = (fs->S + fs->A) >> 6;
break;
case R_HEX_B22_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B22;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_B15_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B15;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_B13_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B13;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_B9_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B9;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_B7_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B7;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_12_X:
bitmask = R_HEX_BITMASK_WORD32_R6;
val = (fs->S + fs->A);
break;
case R_HEX_32_PCREL:
val = (fs->S + fs->A - fs->P);
break;
case R_HEX_GOTREL_LO16:
bitmask = R_HEX_BITMASK_WORD32_LO;
val = (fs->S + fs->A - fs->GOT);
break;
case R_HEX_GOTREL_HI16:
bitmask = R_HEX_BITMASK_WORD32_HL;
val = (fs->S + fs->A - fs->GOT) >> 16;
break;
case R_HEX_GOTREL_32:
val = (fs->S + fs->A - fs->GOT);
break;
case R_HEX_GOTREL_32_6_X:
bitmask = R_HEX_BITMASK_WORD32_X26;
val = (fs->S + fs->A - fs->GOT) >> 6;
break;
case R_HEX_PLT_B22_PCREL:
case R_HEX_LD_PLT_B22_PCREL:
case R_HEX_GD_PLT_B22_PCREL:
bitmask = R_HEX_BITMASK_WORD32_B22;
val = (fs->L + fs->A - fs->P) >> 2;
break;
case R_HEX_GD_PLT_B22_PCREL_X:
case R_HEX_LD_PLT_B22_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_B22;
val = (fs->S + fs->A - fs->P) & 0x3f;
break;
case R_HEX_GD_PLT_B32_PCREL_X:
case R_HEX_LD_PLT_B32_PCREL_X:
bitmask = R_HEX_BITMASK_WORD32_X26;
val = (fs->S + fs->A - fs->P) >> 6;
break;
case R_HEX_16_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r16(rz_read_le32(buf));
val = (fs->S + fs->A) & 0x3f;
break;
case R_HEX_11_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r11(rz_read_le32(buf));
val = (fs->S + fs->A) & 0x3f;
break;
case R_HEX_10_X:
bitmask = 0x00203fe0;
val = (fs->S + fs->A) & 0x3f;
break;
case R_HEX_9_X:
bitmask = 0x00003fe0;
val = (fs->S + fs->A) & 0x3f;
break;
case R_HEX_8_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r8(rz_read_le32(buf));
val = (fs->S + fs->A);
break;
case R_HEX_6_PCREL_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r6(rz_read_le32(buf));
val = (fs->S + fs->A - fs->P);
break;
case R_HEX_6_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r6(rz_read_le32(buf));
val = (fs->S + fs->A);
break;
case R_HEX_GOTREL_16_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r16(rz_read_le32(buf));
val = (fs->S + fs->A - fs->GOT);
break;
case R_HEX_GOTREL_11_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r11(rz_read_le32(buf));
val = (fs->S + fs->A - fs->GOT);
break;
case R_HEX_DTPREL_32_6_X:
bitmask = R_HEX_BITMASK_WORD32_X26;
val = (fs->S + fs->A - fs->T) >> 6;
break;
case R_HEX_DTPREL_16_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r16(rz_read_le32(buf));
val = (fs->S + fs->A - fs->T);
break;
case R_HEX_DTPREL_11_X:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
bitmask = hexagon_get_bitmask_r11(rz_read_le32(buf));
val = (fs->S + fs->A - fs->T);
break;
}
// Patch two opcodes at once.
if (rel_type == R_HEX_HL16) {
patch_val_over_mask_32(buf_patched, false, patch_addr, bitmask, val & 0xffffffff);
patch_val_over_mask_32(buf_patched, false, patch_addr + 4, bitmask, val >> 32);
} else {
patch_val_over_mask_32(buf_patched, false, patch_addr, bitmask, val);
}
}
static void patch_reloc_sparc(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
ut64 val = 0;
ut64 bitmask = 0;
switch (rel_type) {
default:
UNHANDL_DEF("Sparc", rel_type);
return;
case R_SPARC_GOTDATA_OP:
// bitmask = R_SPARC_BITMASK_WORD32;
// I can't find details how this one is patched.
// The docs all refer to "the explanation following this table."
// But there is no explanation in all the docs I could find.
// There is a related LLVM issue about those though:
// https://github.com/llvm/llvm-project/issues/100320
//
// But in https://docs.oracle.com/cd/E53394_01/html/E54833/gpvxz.html
// it looks like this relocation simply signals the
// linker to check for an optimization.
// So return her silently.
return;
case R_SPARC_JMP_SLOT:
// PLT entry patched by the runtime linker are of these reloc types.
// The values written there depend on %g1.
// %g1 seems to be used to store the relative offset from the PC
// to a section base address is made in.
// So for JMP_SLOT it would hold the offset to the PLT at patch time.
// At least this is how it is done for the GOT patching in here
// https://docs.oracle.com/cd/E53394_01/html/E54833/gpvxz.html
case R_SPARC_COPY:
// Copies data from a shared library to the
// dynamic executable's pre-allocated space for this data.
UNHANDL_DEF("Sparc", rel_type);
case R_SPARC_NONE:
return;
case R_SPARC_8:
bitmask = R_SPARC_BITMASK_BYTE8;
val = (fs->S + fs->A);
break;
case R_SPARC_16:
bitmask = R_SPARC_BITMASK_HALF16;
val = (fs->S + fs->A);
break;
case R_SPARC_32:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->S + fs->A);
break;
case R_SPARC_DISP8:
bitmask = R_SPARC_BITMASK_BYTE8;
val = (fs->S + fs->A - fs->P);
break;
case R_SPARC_DISP16:
bitmask = R_SPARC_BITMASK_HALF16;
val = (fs->S + fs->A - fs->P);
break;
case R_SPARC_DISP32:
bitmask = R_SPARC_BITMASK_DISP32;
val = (fs->S + fs->A - fs->P);
break;
case R_SPARC_WDISP30:
bitmask = R_SPARC_BITMASK_DISP30;
val = ((fs->S + fs->A - fs->P) >> 2);
break;
case R_SPARC_WDISP22:
bitmask = R_SPARC_BITMASK_DISP22;
val = ((fs->S + fs->A - fs->P) >> 2);
break;
case R_SPARC_HI22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A) >> 10);
break;
case R_SPARC_22:
bitmask = R_SPARC_BITMASK_IMM22;
val = (fs->S + fs->A);
break;
case R_SPARC_13:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (fs->S + fs->A);
break;
case R_SPARC_LO10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = ((fs->S + fs->A) & 0x3ff);
break;
case R_SPARC_GOT10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (fs->G & 0x3ff);
break;
case R_SPARC_GOT13:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (fs->G);
break;
case R_SPARC_GOT22:
bitmask = R_SPARC_BITMASK_SIMM22;
val = (fs->G >> 10);
break;
case R_SPARC_PC10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = ((fs->S + fs->A - fs->P) & 0x3ff);
break;
case R_SPARC_PC22:
bitmask = R_SPARC_BITMASK_DISP22;
val = ((fs->S + fs->A - fs->P) >> 10);
break;
case R_SPARC_WPLT30:
bitmask = R_SPARC_BITMASK_DISP30;
val = ((fs->L + fs->A - fs->P) >> 2);
break;
case R_SPARC_GLOB_DAT:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->S + fs->A);
break;
case R_SPARC_RELATIVE:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->B + fs->A);
break;
case R_SPARC_UA32:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->S + fs->A);
break;
case R_SPARC_PLT32:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->L + fs->A);
break;
case R_SPARC_HIPLT22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->L + fs->A) >> 10);
break;
case R_SPARC_LOPLT10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = ((fs->L + fs->A) & 0x3ff);
break;
case R_SPARC_PCPLT32:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->L + fs->A - fs->P);
break;
case R_SPARC_PCPLT22:
bitmask = R_SPARC_BITMASK_DISP22;
val = ((fs->L + fs->A - fs->P) >> 10);
break;
case R_SPARC_PCPLT10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = ((fs->L + fs->A - fs->P) & 0x3ff);
break;
case R_SPARC_10:
bitmask = R_SPARC_BITMASK_SIMM10;
val = (fs->S + fs->A);
break;
case R_SPARC_11:
bitmask = R_SPARC_BITMASK_SIMM11;
val = (fs->S + fs->A);
break;
case R_SPARC_64:
bitmask = R_SPARC_BITMASK_XWORD64;
val = (fs->S + fs->A);
break;
case R_SPARC_OLO10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (((fs->S + fs->A) & 0x3ff) + fs->O);
break;
case R_SPARC_HH22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A) >> 42);
break;
case R_SPARC_HM10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (((fs->S + fs->A) >> 32) & 0x3ff);
break;
case R_SPARC_LM22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A) >> 10);
break;
case R_SPARC_PC_HH22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A - fs->P) >> 42);
break;
case R_SPARC_PC_HM10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (((fs->S + fs->A - fs->P) >> 32) & 0x3ff);
break;
case R_SPARC_PC_LM22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A - fs->P) >> 10);
break;
case R_SPARC_WDISP16:
bitmask = R_SPARC_BITMASK_D2_DISP14;
val = ((fs->S + fs->A - fs->P) >> 2);
break;
case R_SPARC_WDISP19:
bitmask = R_SPARC_BITMASK_DISP19;
val = ((fs->S + fs->A - fs->P) >> 2);
break;
case R_SPARC_7:
bitmask = R_SPARC_BITMASK_IMM7;
val = (fs->S + fs->A);
break;
case R_SPARC_5:
bitmask = R_SPARC_BITMASK_IMM5;
val = (fs->S + fs->A);
break;
case R_SPARC_6:
bitmask = R_SPARC_BITMASK_IMM6;
val = (fs->S + fs->A);
break;
case R_SPARC_DISP64:
bitmask = R_SPARC_BITMASK_XWORD64;
val = (fs->S + fs->A - fs->P);
break;
case R_SPARC_PLT64:
bitmask = R_SPARC_BITMASK_XWORD64;
val = (fs->L + fs->A);
break;
case R_SPARC_HIX22:
bitmask = R_SPARC_BITMASK_IMM22;
val = (((fs->S + fs->A) ^ 0xffffffffffffffff) >> 10);
break;
case R_SPARC_LOX10:
bitmask = R_SPARC_BITMASK_SIMM13;
val = (((fs->S + fs->A) & 0x3ff) | 0x1c00);
break;
case R_SPARC_H44:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A) >> 22);
break;
case R_SPARC_M44:
bitmask = R_SPARC_BITMASK_IMM10;
val = (((fs->S + fs->A) >> 12) & 0x3ff);
break;
case R_SPARC_L44:
bitmask = R_SPARC_BITMASK_IMM13;
val = ((fs->S + fs->A) & 0xfff);
break;
case R_SPARC_REGISTER:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->S + fs->A);
break;
case R_SPARC_UA64:
bitmask = R_SPARC_BITMASK_XWORD64;
val = (fs->S + fs->A);
break;
case R_SPARC_UA16:
bitmask = R_SPARC_BITMASK_HALF16;
val = (fs->S + fs->A);
break;
case R_SPARC_H34:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->S + fs->A) >> 12);
break;
case R_SPARC_SIZE64:
bitmask = R_SPARC_BITMASK_XWORD64;
val = (fs->Z + fs->A);
break;
case R_SPARC_GOTDATA_HIX22:
bitmask = R_SPARC_BITMASK_IMM22;
val = (((fs->S + fs->A - fs->GOT) >> 10) ^ ((fs->S + fs->A - fs->GOT) >> 31));
break;
case R_SPARC_GOTDATA_LOX10:
bitmask = R_SPARC_BITMASK_IMM13;
val = (((fs->S + fs->A - fs->GOT) & 0x3ff) | (((fs->S + fs->A - fs->GOT) >> 31) & 0x1c00));
break;
case R_SPARC_GOTDATA_OP_HIX22:
bitmask = R_SPARC_BITMASK_IMM22;
val = ((fs->G >> 10) ^ (fs->G >> 31));
break;
case R_SPARC_GOTDATA_OP_LOX10:
bitmask = R_SPARC_BITMASK_IMM13;
val = ((fs->G & 0x3ff) | ((fs->G >> 31) & 0x1c00));
break;
case R_SPARC_SIZE32:
bitmask = R_SPARC_BITMASK_WORD32;
val = (fs->Z + fs->A);
break;
case R_SPARC_WDISP10:
bitmask = R_SPARC_BITMASK_D2_DISP8;
val = ((fs->S + fs->A - fs->P) >> 2);
break;
}
if (bitmask == R_SPARC_BITMASK_XWORD64) {
patch_val_over_mask_64(buf_patched, big_endian, patch_addr, bitmask, val);
} else {
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, bitmask, val);
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_mips(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[4] = { 0 };
ut64 val = 0;
switch (rel_type) {
default:
UNHANDL_DEF("MIPS", rel_type);
return;
case R_MIPS_NONE:
return;
case R_MIPS_16: // S + signextend(A)
rz_buf_read_at(buf_patched, patch_addr, buf, 2);
val = rz_read_ble16(buf, big_endian);
val += fs->S + fs->A;
rz_write_ble16(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
return;
case R_MIPS_32: // S + A
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = rz_read_ble32(buf, big_endian);
val += fs->S + fs->A;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
return;
case R_MIPS_REL32: // A EA + S
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = rz_read_ble32(buf, big_endian);
val += fs->S + fs->A - fs->P;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
return;
case R_MIPS_26: // (((A << 2) | (P & 0xf0000000) + S) >> 2
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = rz_read_ble32(buf, big_endian);
val += ((fs->A << 2) | (fs->P & 0xf0000000));
val += fs->S;
val >>= 2;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
return;
case R_MIPS_HI16:
rz_buf_read_at(buf_patched, patch_addr, buf, 2);
fs->AHL = rz_read_ble16(buf, big_endian) << 16;
return;
case R_MIPS_LO16:
rz_buf_read_at(buf_patched, patch_addr, buf, 2);
val = rz_read_ble16(buf, big_endian);
val += fs->AHL;
val += fs->S;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
return;
case R_MIPS_GPREL16: UNHANDL("R_MIPS_GPREL16");
case R_MIPS_LITERAL: UNHANDL("R_MIPS_LITERAL");
case R_MIPS_GOT16: UNHANDL("R_MIPS_GOT16");
case R_MIPS_PC16: UNHANDL("R_MIPS_PC16");
case R_MIPS_CALL16: UNHANDL("R_MIPS_CALL16");
case R_MIPS_GPREL32: UNHANDL("R_MIPS_GPREL32");
case R_MIPS_SHIFT5: UNHANDL("R_MIPS_SHIFT5");
case R_MIPS_SHIFT6: UNHANDL("R_MIPS_SHIFT6");
case R_MIPS_64: UNHANDL("R_MIPS_64");
case R_MIPS_GOT_DISP: UNHANDL("R_MIPS_GOT_DISP");
case R_MIPS_GOT_PAGE: UNHANDL("R_MIPS_GOT_PAGE");
case R_MIPS_GOT_OFST: UNHANDL("R_MIPS_GOT_OFST");
case R_MIPS_GOT_HI16: UNHANDL("R_MIPS_GOT_HI16");
case R_MIPS_GOT_LO16: UNHANDL("R_MIPS_GOT_LO16");
case R_MIPS_SUB: UNHANDL("R_MIPS_SUB");
case R_MIPS_INSERT_A: UNHANDL("R_MIPS_INSERT_A");
case R_MIPS_INSERT_B: UNHANDL("R_MIPS_INSERT_B");
case R_MIPS_DELETE: UNHANDL("R_MIPS_DELETE");
case R_MIPS_HIGHER: UNHANDL("R_MIPS_HIGHER");
case R_MIPS_HIGHEST: UNHANDL("R_MIPS_HIGHEST");
case R_MIPS_CALL_HI16: UNHANDL("R_MIPS_CALL_HI16");
case R_MIPS_CALL_LO16: UNHANDL("R_MIPS_CALL_LO16");
case R_MIPS_SCN_DISP: UNHANDL("R_MIPS_SCN_DISP");
case R_MIPS_REL16: UNHANDL("R_MIPS_REL16");
case R_MIPS_ADD_IMMEDIATE: UNHANDL("R_MIPS_ADD_IMMEDIATE");
case R_MIPS_PJUMP: UNHANDL("R_MIPS_PJUMP");
case R_MIPS_RELGOT: UNHANDL("R_MIPS_RELGOT");
case R_MIPS_JALR: UNHANDL("R_MIPS_JALR");
case R_MIPS_TLS_DTPMOD32: UNHANDL("R_MIPS_TLS_DTPMOD32");
case R_MIPS_TLS_DTPREL32: UNHANDL("R_MIPS_TLS_DTPREL32");
case R_MIPS_TLS_DTPMOD64: UNHANDL("R_MIPS_TLS_DTPMOD64");
case R_MIPS_TLS_DTPREL64: UNHANDL("R_MIPS_TLS_DTPREL64");
case R_MIPS_TLS_GD: UNHANDL("R_MIPS_TLS_GD");
case R_MIPS_TLS_LDM: UNHANDL("R_MIPS_TLS_LDM");
case R_MIPS_TLS_DTPREL_HI16: UNHANDL("R_MIPS_TLS_DTPREL_HI16");
case R_MIPS_TLS_DTPREL_LO16: UNHANDL("R_MIPS_TLS_DTPREL_LO16");
case R_MIPS_TLS_GOTTPREL: UNHANDL("R_MIPS_TLS_GOTTPREL");
case R_MIPS_TLS_TPREL32: UNHANDL("R_MIPS_TLS_TPREL32");
case R_MIPS_TLS_TPREL64: UNHANDL("R_MIPS_TLS_TPREL64");
case R_MIPS_TLS_TPREL_HI16: UNHANDL("R_MIPS_TLS_TPREL_HI16");
case R_MIPS_TLS_TPREL_LO16: UNHANDL("R_MIPS_TLS_TPREL_LO16");
case R_MIPS_GLOB_DAT: UNHANDL("R_MIPS_GLOB_DAT");
case R_MIPS_COPY: UNHANDL("R_MIPS_COPY");
case R_MIPS_JUMP_SLOT: UNHANDL("R_MIPS_JUMP_SLOT");
case R_MICROMIPS_26_S1: UNHANDL("R_MICROMIPS_26_S1");
case R_MICROMIPS_HI16: UNHANDL("R_MICROMIPS_HI16");
case R_MICROMIPS_LO16: UNHANDL("R_MICROMIPS_LO16");
case R_MICROMIPS_GPREL16: UNHANDL("R_MICROMIPS_GPREL16");
case R_MICROMIPS_LITERAL: UNHANDL("R_MICROMIPS_LITERAL");
case R_MICROMIPS_GOT16: UNHANDL("R_MICROMIPS_GOT16");
case R_MICROMIPS_PC7_S1: UNHANDL("R_MICROMIPS_PC7_S1");
case R_MICROMIPS_PC10_S1: UNHANDL("R_MICROMIPS_PC10_S1");
case R_MICROMIPS_PC16_S1: UNHANDL("R_MICROMIPS_PC16_S1");
case R_MICROMIPS_CALL16: UNHANDL("R_MICROMIPS_CALL16");
case R_MICROMIPS_GOT_DISP: UNHANDL("R_MICROMIPS_GOT_DISP");
case R_MICROMIPS_GOT_PAGE: UNHANDL("R_MICROMIPS_GOT_PAGE");
case R_MICROMIPS_GOT_OFST: UNHANDL("R_MICROMIPS_GOT_OFST");
case R_MICROMIPS_GOT_HI16: UNHANDL("R_MICROMIPS_GOT_HI16");
case R_MICROMIPS_GOT_LO16: UNHANDL("R_MICROMIPS_GOT_LO16");
case R_MICROMIPS_SUB: UNHANDL("R_MICROMIPS_SUB");
case R_MICROMIPS_HIGHER: UNHANDL("R_MICROMIPS_HIGHER");
case R_MICROMIPS_HIGHEST: UNHANDL("R_MICROMIPS_HIGHEST");
case R_MICROMIPS_CALL_HI16: UNHANDL("R_MICROMIPS_CALL_HI16");
case R_MICROMIPS_CALL_LO16: UNHANDL("R_MICROMIPS_CALL_LO16");
case R_MICROMIPS_SCN_DISP: UNHANDL("R_MICROMIPS_SCN_DISP");
case R_MICROMIPS_JALR: UNHANDL("R_MICROMIPS_JALR");
case R_MICROMIPS_HI0_LO16: UNHANDL("R_MICROMIPS_HI0_LO16");
case R_MICROMIPS_TLS_GD: UNHANDL("R_MICROMIPS_TLS_GD");
case R_MICROMIPS_TLS_LDM: UNHANDL("R_MICROMIPS_TLS_LDM");
case R_MICROMIPS_TLS_DTPREL_HI16: UNHANDL("R_MICROMIPS_TLS_DTPREL_HI16");
case R_MICROMIPS_TLS_DTPREL_LO16: UNHANDL("R_MICROMIPS_TLS_DTPREL_LO16");
case R_MICROMIPS_TLS_GOTTPREL: UNHANDL("R_MICROMIPS_TLS_GOTTPREL");
case R_MICROMIPS_TLS_TPREL_HI16: UNHANDL("R_MICROMIPS_TLS_TPREL_HI16");
case R_MICROMIPS_TLS_TPREL_LO16: UNHANDL("R_MICROMIPS_TLS_TPREL_LO16");
case R_MICROMIPS_GPREL7_S2: UNHANDL("R_MICROMIPS_GPREL7_S2");
case R_MICROMIPS_PC23_S2: UNHANDL("R_MICROMIPS_PC23_S2");
case R_MIPS_PC32: UNHANDL("R_MIPS_PC32");
case R_MIPS_EH: UNHANDL("R_MIPS_EH");
case R_MIPS_GNU_REL16_S2: UNHANDL("R_MIPS_GNU_REL16_S2");
case R_MIPS_GNU_VTINHERIT: UNHANDL("R_MIPS_GNU_VTINHERIT");
case R_MIPS_GNU_VTENTRY: UNHANDL("R_MIPS_GNU_VTENTRY");
}
}
// For arm group relocations related to ALU instructions
static ut32 convert_alu_group_mask(ut32 X, int n) {
ut32 residual = X;
ut32 encoded_g_n = 0;
for (int current_n = 0; current_n <= n; current_n++) {
int msb;
int shift;
if (residual == 0) {
shift = 0;
} else {
for (msb = 30; msb >= 0; msb -= 2) {
if (residual & (0x3 << msb)) {
break;
}
}
shift = ((msb - 6) < 0) ? 0 : (msb - 6);
}
ut32 g_n = residual & (0xFF << shift);
encoded_g_n = (g_n >> shift) | ((g_n <= 0xff ? 0 : (32 - shift) / 2) << 8);
residual &= ~g_n;
}
return encoded_g_n;
}
// For arm group relocations not related to ALU instructions
static ut32 convert_group_mask(ut32 X, int n) {
ut32 residual = X;
for (int current_n = 0; current_n <= n; current_n++) {
int msb;
int shift;
if (residual == 0) {
shift = 0;
} else {
for (msb = 30; msb >= 0; msb -= 2) {
if (residual & (0x3 << msb)) {
break;
}
}
shift = ((msb - 6) < 0) ? 0 : (msb - 6);
}
ut32 g_n = residual & (0xFF << shift);
residual &= ~g_n;
}
return residual;
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel The relocation elf structure.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_arm(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const RzBinElfReloc *rel, bool big_endian, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && rel && fs);
ut16 keephw1 = 0, keephw2 = 0;
ut32 nbytes = 4;
ut8 buf[4] = { 0 };
ut64 val = 0;
ut16 offset = 0;
switch (rel->type) {
case R_ARM_NONE:
return;
case R_ARM_THM_JUMP24:
/* fall-thru */
case R_ARM_THM_CALL:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
// I1 = NOT(J1 EOR S)
// I2 = NOT(J2 EOR S)
val = fs->S + fs->A;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
rz_write_ble16(&buf[0],
(keephw1 & 0xF800U) | // opcode
((val >> 14) & 0x0400U) | // sign
((val >> 12) & 0x03FFU), // imm 10
big_endian);
rz_write_ble16(&buf[2],
(keephw2 & 0xD000U) | // opcode
(((~(val >> 10)) ^ (val >> 11)) & 0x2000) | // J1
(((~(val >> 11)) ^ (val >> 13)) & 0x0800) | // J2
((val >> 1) & 0x07ff), // imm11
big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_ABS32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_REL32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->P;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_PC24:
/* fall through */
case R_ARM_PLT32:
/* fall through */
case R_ARM_CALL:
/* fall through */
case R_ARM_JUMP24:
val = fs->S + fs->A - fs->P;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x03FFFFFE, (val >> 2));
break;
case R_ARM_MOVW_PREL_NC:
val = fs->S + fs->A - fs->P;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x000F0FFF, val);
break;
case R_ARM_THM_MOVW_PREL_NC:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm4:i:imm3:imm8
val = fs->S + fs->A - fs->P;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBF0) |
((val & 0xF000) >> 12) | // imm4
((val & 0x0800) >> 1); // i
keephw2 = (keephw2 & 0x8F00) |
((val & 0x0700) << 4) | // imm3
((val & 0x00FF)); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_JUMP19:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = S:J1:J2:imm6:imm11:0
val = fs->S + fs->A - fs->P;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBC0) |
((val >> 10) & 0x0400) | // S
((val >> 12) & 0x003F); // imm6
keephw2 = (keephw2 & 0xD000) |
(((val >> 19) & 1) << 13) | // J1
(((val >> 18) & 1) << 11) | // J2
((val >> 1) & 0x07FF); // imm11
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_ALU_PREL_11_0:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = i:imm3:imm8
val = fs->S + fs->A - (fs->P & 0xFFFFFFFC); // S+A-Pa
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBFF) |
((val >> 1) & 0x0400); // i
keephw2 = (keephw2 & 0x8F00) |
((val << 4) & 0x7000) | // imm3
(val & 0x00FF); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_ABS16:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A;
rz_write_ble16(buf, (val & 0xFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_ABS12:
val = fs->S + fs->A;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, val);
break;
case R_ARM_THM_ABS5:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = ((fs->S + fs->A) & 0x7C) >> 2;
keephw1 = rz_read_ble16(buf, big_endian);
keephw1 = (keephw1 & 0xF83F) |
(val << 6);
rz_write_ble16(buf, keephw1, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_ABS8:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A;
rz_write_ble8(buf, (val & 0xFF));
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_SBREL32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->B;
rz_write_ble32(buf, (val & 0xFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_PC8:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - (fs->P & 0xFFFFFFFC);
val = (val & 0x3FC) >> 2;
keephw1 = rz_read_ble16(buf, big_endian);
keephw1 = (keephw1 & 0xFF00) | val;
rz_write_ble16(buf, keephw1, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_GOTOFF32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->GOT;
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_BASE_PREL:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
if (fs->S == 0) { // NUll symbol
val = fs->GOT + fs->A;
} else {
val = fs->B + fs->A;
}
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_GOT_BREL:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->G + fs->A;
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_BASE_ABS:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
rz_write_ble32(buf, (fs->A & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_PREL31:
val = (fs->S + fs->A - fs->P) >> 1;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x7FFFFFFF, val);
break;
case R_ARM_MOVW_ABS_NC:
// val = imm4:imm12
val = (fs->S + fs->A) & 0xFFFF;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x000F0FFF, val);
break;
case R_ARM_MOVT_ABS:
/* fall through */
case R_ARM_MOVT_PREL:
// val = imm4:imm12
val = (fs->S + fs->A) >> 16;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x000F0FFF, val);
break;
case R_ARM_THM_MOVW_ABS_NC:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm4:i:imm3:imm8
val = (fs->S + fs->A) & 0xFFFF;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBF0) |
((val >> 1) & 0x0400) | // i
((val >> 12) & 0x000F); // imm4
keephw2 = (keephw2 & 0x8F00) |
((val << 4) & 0x7000) | // imm3
(val & 0x00FF); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_MOVT_ABS:
/* fall through */
case R_ARM_THM_MOVT_PREL:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm4:i:imm3:imm8
val = (fs->S + fs->A) >> 16;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBF0) |
((val >> 1) & 0x0400) | // i
((val >> 12) & 0x000F); // imm4
keephw2 = (keephw2 & 0x8F00) |
((val << 4) & 0x7000) | // imm3
(val & 0x00FF); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_JUMP6:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = i:imm5
val = ((fs->S + fs->A) & 0x7E) >> 1;
keephw1 = rz_read_ble16(buf, big_endian);
keephw1 = (keephw1 & 0xFD07) |
((val << 4) & 0x0200) | // i
((val << 3) & 0x00F8); // imm5
rz_write_ble16(buf, keephw1, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_PC12:
// val = imm12
val = (fs->S + fs->A) & 0xFFF;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, val);
break;
case R_ARM_ABS32_NOI:
/* fall through */
case R_ARM_REL32_NOI:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A;
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_MOVW_BREL:
/* fall through */
case R_ARM_MOVW_BREL_NC:
// val = imm4:imm12
val = (fs->S + fs->A - fs->B) & 0xFFFF;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x000F0FFF, val);
break;
case R_ARM_MOVT_BREL:
val = (fs->S + fs->A) >> 16;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x000F0FFF, val);
break;
case R_ARM_THM_MOVW_BREL:
/* fall through */
case R_ARM_THM_MOVW_BREL_NC:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm4:i:imm3:imm8
val = (fs->S + fs->A - fs->B) & 0xFFFF;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBF0) |
((val >> 1) & 0x0400) | // i
((val >> 12) & 0x000F); // imm4
keephw2 = (keephw2 & 0x8F00) |
((val << 4) & 0x7000) | // imm3
(val & 0x00FF); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_MOVT_BREL:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm4:i:imm3:imm8
val = (fs->S + fs->A) >> 16;
keephw1 = rz_read_ble16(&buf[0], big_endian);
keephw2 = rz_read_ble16(&buf[2], big_endian);
keephw1 = (keephw1 & 0xFBF0) |
((val >> 1) & 0x0400) | // i
((val >> 12) & 0x000F); // imm4
keephw2 = (keephw2 & 0x8F00) |
((val << 4) & 0x7000) | // imm3
(val & 0x00FF); // imm8
rz_write_ble16(&buf[0], keephw1, big_endian);
rz_write_ble16(&buf[2], keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_GOT_PREL:
/* fall through */
case R_ARM_GOT_ABS:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->G + fs->GOT + fs->A;
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_GOT_BREL12:
/* fall through */
case R_ARM_TLS_IE12GP:
/* fall through */
case R_ARM_GOT_BREL12:
// val = imm12
val = (fs->G + fs->A) & 0xFFF; // G(S) + A - GOT_ORG
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, val);
break;
case R_ARM_GOTOFF12:
// val = imm12
val = (fs->S + fs->A) & 0xFFF;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, val);
break;
case R_ARM_THM_JUMP11:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val = imm11
val = ((fs->S + fs->A) & 0xFFE) >> 1;
keephw1 = rz_read_ble16(buf, big_endian);
keephw1 = (keephw1 & 0xF800) | val;
rz_write_ble16(buf, keephw1, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_THM_JUMP8:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
// val - imm8
val = ((fs->S + fs->A) & 0x1FE) >> 1;
keephw1 = rz_read_ble16(buf, big_endian);
keephw1 = (keephw1 & 0xFF00) | val;
rz_write_ble16(buf, keephw1, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_TLS_GD32:
/* fall through */
case R_ARM_TLS_LDM32:
/* fall through */
case R_ARM_TLS_IE32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->G + fs->GOT + fs->A;
rz_write_ble32(buf, (val & 0xFFFFFFFF), big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_ARM_ALU_PC_G0:
/* fall through */
case R_ARM_ALU_PC_G0_NC:
val = fs->S + fs->A - fs->P;
offset = convert_alu_group_mask(val, 0);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_ALU_PC_G1:
/* fall through */
case R_ARM_ALU_PC_G1_NC:
val = fs->S + fs->A - fs->P;
offset = convert_alu_group_mask(val, 1);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_ALU_PC_G2:
val = fs->S + fs->A - fs->P;
offset = convert_alu_group_mask(val, 2);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_LDR_SB_G0:
/* fall through */
case R_ARM_LDR_PC_G0:
val = fs->S + fs->A;
offset = convert_group_mask(val, 0);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_LDR_SB_G1:
/* fall through */
case R_ARM_LDR_PC_G1:
val = fs->S + fs->A;
offset = convert_group_mask(val, 1);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_LDR_SB_G2:
/* fall through */
case R_ARM_LDR_PC_G2:
val = fs->S + fs->A;
offset = convert_group_mask(val, 2);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_LDRS_SB_G0:
/* fall through */
case R_ARM_LDRS_PC_G0:
val = fs->S + fs->A;
offset = convert_group_mask(val, 0);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x0F0F, offset);
break;
case R_ARM_LDRS_SB_G1:
/* fall through */
case R_ARM_LDRS_PC_G1:
val = fs->S + fs->A;
offset = convert_group_mask(val, 1);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x0F0F, offset);
break;
case R_ARM_LDRS_SB_G2:
/* fall through */
case R_ARM_LDRS_PC_G2:
val = fs->S + fs->A;
offset = convert_group_mask(val, 2);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0x0F0F, offset);
break;
case R_ARM_LDC_SB_G0:
/* fall through */
case R_ARM_LDC_PC_G0:
val = fs->S + fs->A;
offset = convert_group_mask(val, 0);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFF, offset);
break;
case R_ARM_LDC_SB_G1:
/* fall through */
case R_ARM_LDC_PC_G1:
val = fs->S + fs->A;
offset = convert_group_mask(val, 1);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFF, offset);
break;
case R_ARM_LDC_SB_G2:
/* fall through */
case R_ARM_LDC_PC_G2:
val = fs->S + fs->A;
offset = convert_group_mask(val, 2);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFF, offset);
break;
case R_ARM_ALU_SB_G0:
/* fall through */
case R_ARM_ALU_SB_G0_NC:
val = fs->S + fs->A - fs->B;
offset = convert_alu_group_mask(val, 0);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_ALU_SB_G1:
/* fall through */
case R_ARM_ALU_SB_G1_NC:
val = fs->S + fs->A - fs->B;
offset = convert_alu_group_mask(val, 1);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
case R_ARM_ALU_SB_G2:
val = fs->S + fs->A - fs->B;
offset = convert_alu_group_mask(val, 2);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, 0xFFF, offset);
break;
/*
The following relocations are for Branch Future instructions in Armv8.1-M Mainline.
Check the docs: https://github.com/ARM-software/abi-aa/blob/main/aaelf32/aaelf32.rst#56114armv81-m-mainline-branch-future-relocations
*/
case R_ARM_THM_BF16:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = (fs->S + fs->A - fs->P) & 0x0001FFFE;
keephw1 = rz_read_ble16(buf, big_endian);
keephw2 = rz_read_ble16(buf + 2, big_endian);
// insn[10:1] = (val >> 2) & 0x3FF
// insn[11] = (val >> 1) & 0x1
// insn[20:16] = val >> 12
keephw1 = (keephw1 & 0xF800) | ((val >> 2) & 0x3FF) | (((val >> 1) & 0x1) << 11);
keephw2 = (keephw2 & 0xFFE0) | ((val >> 12) & 0x1F);
rz_write_ble16(buf, keephw1, big_endian);
rz_write_ble16(buf + 2, keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_ARM_THM_BF12:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->P;
val = val & 0x00001FFE;
keephw1 = rz_read_ble16(buf, big_endian);
keephw2 = rz_read_ble16(buf + 2, big_endian);
// insn[10:1] = (val >> 2) & 0x3FF
// insn[11] = (val >> 1) & 0x1
// insn[16] = val >> 12
keephw1 = (keephw1 & 0xF800) | ((val >> 2) & 0x3FF) | (((val >> 1) & 0x1) << 11);
keephw2 = (keephw2 & 0xFFFE) | ((val >> 12) & 0x1);
rz_write_ble16(buf, keephw1, big_endian);
rz_write_ble16(buf + 2, keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_ARM_THM_BF18:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->P;
val = val & 0x0007FFFE;
keephw1 = rz_read_ble16(buf, big_endian);
keephw2 = rz_read_ble16(buf + 2, big_endian);
// insn[10:1] = (val >> 2) & 0x3FF
// insn[11] = (val >> 1) & 0x1
// insn[22:16] = val >> 12
keephw1 = (keephw1 & 0xF800) | ((val >> 2) & 0x3FF) | (((val >> 1) & 0x1) << 11);
keephw2 = (keephw2 & 0xFF80) | ((val >> 12) & 0x7F);
rz_write_ble16(buf, keephw1, big_endian);
rz_write_ble16(buf + 2, keephw2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
default:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A;
if (!rel->sym && rel->mode == DT_REL) {
val += rz_read_ble32(buf, big_endian);
}
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel The relocation elf structure.
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_arm64(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const RzBinElfReloc *rel, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && rel && fs);
// AARCH64-specific defines
// Take the PAGE component of an address or offset.
#define PG(x) ((x) & ~0xFFFULL)
#define PG_OFFSET(x) ((x) & 0xFFFULL)
#define ADR_IMM_MASK1 (((1U << 2) - 1) << 29)
#define ADR_IMM_MASK2 (((1U << 19) - 1) << 5)
#define ADR_IMM_MASK3 (((1U << 19) - 1) << 2)
ut32 keep = 0;
ut32 nbytes = 4;
ut8 buf[8] = { 0 };
ut64 val = 0;
rz_buf_read_at(buf_patched, patch_addr, buf, 8);
switch (rel->type) {
case R_AARCH64_NONE:
return;
case R_AARCH64_ABS16:
val = fs->S + fs->A;
rz_write_le16(buf, val);
nbytes = 2;
break;
case R_AARCH64_ABS32:
val = fs->S + fs->A;
rz_write_le32(buf, val);
break;
case R_AARCH64_GLOB_DAT:
/* fall-thru */
case R_AARCH64_ABS64:
/* fall-thru */
case R_AARCH64_JUMP_SLOT:
val = fs->S + fs->A;
rz_write_le64(buf, val);
nbytes = 8;
break;
case R_AARCH64_PREL16:
val = fs->S + fs->A - fs->P;
rz_write_le16(buf, val);
nbytes = 2;
break;
case R_AARCH64_PREL32:
val = fs->S + fs->A - fs->P;
rz_write_le32(buf, val);
break;
case R_AARCH64_PREL64:
val = fs->S + fs->A - fs->P;
rz_write_le64(buf, val);
nbytes = 8;
break;
case R_AARCH64_RELATIVE:
val = fs->B + fs->A;
rz_write_le64(buf, val);
nbytes = 8;
break;
case R_AARCH64_ADR_PREL_PG_HI21:
/* fall-thru */
case R_AARCH64_ADR_PREL_PG_HI21_NC:
/* fall-thru */
case R_AARCH64_ADR_GOT_PAGE:
// Reencode ADR imm
keep = rz_read_le32(buf) & ~(ADR_IMM_MASK1 | ADR_IMM_MASK2);
val = ((st64)(PG(fs->S + fs->A) - PG(fs->P))) >> 12;
rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(2, 0)) << 29) | ((val & ADR_IMM_MASK3) << 3));
break;
case R_AARCH64_JUMP26:
/* fall-thru */
case R_AARCH64_CALL26:
// Reencode 26 bits of the offset
keep = rz_read_le32(buf) & ~RZ_BIT_MASK32(26, 0);
val = ((st64)(fs->S + fs->A - fs->P)) >> 2;
rz_write_le32(buf, keep | (val & RZ_BIT_MASK32(26, 0)));
break;
case R_AARCH64_LDST8_ABS_LO12_NC:
/* fall-thru */
case R_AARCH64_ADD_ABS_LO12_NC:
keep = rz_read_le32(buf) & ~(RZ_BIT_MASK32(12, 0) << 10);
val = PG_OFFSET(fs->S + fs->A);
rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(12, 0)) << 10));
break;
case R_AARCH64_LD64_GOT_LO12_NC:
/* fall-thru */
case R_AARCH64_LDST64_ABS_LO12_NC:
// Reencode LD/ST imm
keep = rz_read_le32(buf) & ~(RZ_BIT_MASK32(12, 0) << 10);
val = PG_OFFSET(fs->S + fs->A) >> 3;
rz_write_le32(buf, keep | ((val & RZ_BIT_MASK32(12, 0)) << 10));
break;
case R_AARCH64_TLSDESC:
// R_AARCH64_TLSDESC is a relocation type handled by the
// dynamic linker. We intentionally do not handle do anything.
break;
default:
UNHANDL_DEF("AArch64", rel->type);
return;
}
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
#undef PG
#undef PG_OFFSET
#undef ADR_IMM_MASK1
#undef ADR_IMM_MASK2
#undef ADR_IMM_MASK3
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
* https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#RELOC-TYPE
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_ppc64(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[8] = { 0 };
ut64 val = 0;
ut32 low = 0, word = 0;
switch (rel_type) {
case R_PPC64_NONE:
return;
case R_PPC64_ADDR24:
low = 24;
val = (fs->S + fs->A) >> 2;
break;
case R_PPC64_ADDR16_HI:
word = 2;
val = (fs->S + fs->A) >> 16;
break;
case R_PPC64_ADDR16_HA:
word = 2;
val = (fs->S + fs->A + 0x8000) >> 16;
break;
case R_PPC64_REL16_HA:
word = 2;
val = (fs->S + fs->A - fs->P + 0x8000) >> 16;
break;
case R_PPC64_ADDR16_LO:
word = 2;
val = (fs->S + fs->A) & 0xffff;
break;
case R_PPC64_RELATIVE:
// R_PPC64_RELATIVE 22 doubleword64 B + A
word = 8;
val = (fs->B + fs->A);
break;
case R_PPC64_ADDR64:
// R_PPC64_ADDR64 38 doubleword64 S + A
word = 8;
val = (fs->S + fs->A);
break;
case R_PPC64_REL16_LO:
word = 2;
val = (fs->S + fs->A - fs->P) & 0xffff;
break;
case R_PPC64_REL14:
low = 14;
val = (st64)(fs->S + fs->A - fs->P) >> 2;
break;
case R_PPC64_REL24:
low = 24;
val = (st64)(fs->S + fs->A - fs->P) >> 2;
break;
case R_PPC64_REL32:
word = 4;
val = fs->S + fs->A - fs->P;
break;
default:
UNHANDL_DEF("PowerPC 64", rel_type);
return;
}
if (low) {
switch (low) {
case 14:
val &= (1 << 14) - 1;
rz_buf_read_at(buf_patched, patch_addr, buf, 2);
rz_write_ble32(buf, (rz_read_ble32(buf, big_endian) & ~(RZ_BIT_MASK32(16, 2))) | val << 2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
break;
case 24:
val &= (1 << 24) - 1;
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
rz_write_ble32(buf, (rz_read_ble32(buf, big_endian) & ~(RZ_BIT_MASK32(26, 2))) | val << 2, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
default:
RZ_LOG_WARN("PowerPC 64: Unhandled patching case for relocation %d with low %u bits.\n", rel_type, low);
return;
}
} else if (word) {
switch (word) {
case 2:
rz_write_ble16(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
break;
case 4:
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case 8:
rz_write_ble64(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 8);
break;
default:
RZ_LOG_WARN("PowerPC 64: Unhandled patching case for relocation %d with word size %u.\n", rel_type, word);
return;
}
} else {
UNHANDL_DEF("PowerPC 64", rel_type);
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_x86_32(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[4] = { 0 };
ut64 val = 0;
switch (rel_type) {
case R_386_NONE:
return;
case R_386_32:
/* fall-thru */
case R_386_PC32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = rz_read_le32(buf) + fs->S + fs->A;
if (rel_type == R_386_PC32) {
val -= fs->P;
}
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_GOT32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->G + fs->A - fs->GOT;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_PLT32:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->L + fs->A - fs->P;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_GLOB_DAT:
/* fall through */
case R_386_JMP_SLOT:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_RELATIVE:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->B + fs->A;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_GOTOFF:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->S + fs->A - fs->GOT;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_GOTPC:
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = fs->GOT + fs->A - fs->P;
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case R_386_16:
/* fall through */
case R_386_PC16:
val = fs->S + fs->A;
rz_buf_read_at(buf_patched, patch_addr, buf, 2);
if (rel_type == R_386_PC16) {
val -= fs->P;
}
rz_write_le16(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
break;
case R_386_8:
/* fall through */
case R_386_PC8:
val = fs->S + fs->A;
rz_buf_read_at(buf_patched, patch_addr, buf, 1);
if (rel_type == R_386_PC16) {
val -= fs->P;
}
rz_write_le8(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 1);
break;
default:
UNHANDL_DEF("x86_32", rel_type);
return;
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_x86_64(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[8] = { 0 };
ut64 val = 0;
int word = 0;
switch (rel_type) {
case R_X86_64_NONE:
/* fall-thru */
case R_X86_64_COPY:
return;
case R_X86_64_8:
word = 1;
val = fs->S + fs->A;
break;
case R_X86_64_16:
word = 2;
val = fs->S + fs->A;
break;
case R_X86_64_32:
/* fall-thru */
case R_X86_64_32S:
word = 4;
val = fs->S + fs->A;
break;
case R_X86_64_64:
word = 8;
val = fs->S + fs->A;
break;
case R_X86_64_GLOB_DAT:
/* fall-thru */
case R_X86_64_JUMP_SLOT:
word = 4;
val = fs->S;
break;
case R_X86_64_PC8:
word = 1;
val = fs->S + fs->A - fs->P;
break;
case R_X86_64_PC16:
word = 2;
val = fs->S + fs->A - fs->P;
break;
case R_X86_64_PC32:
word = 4;
val = fs->S + fs->A - fs->P;
break;
case R_X86_64_PC64:
word = 8;
val = fs->S + fs->A - fs->P;
break;
case R_X86_64_PLT32:
word = 4;
val = fs->L + fs->A - fs->P;
break;
case R_X86_64_RELATIVE64:
/* fall-thru */
case R_X86_64_RELATIVE:
word = 8;
val = fs->B + fs->A;
break;
case R_X86_64_GOT32:
word = 4;
val = fs->G + fs->A;
break;
case R_X86_64_GOTPCREL64:
/* fall thru */
case R_X86_64_GOTPCREL:
/* fall thru */
case R_X86_64_GOTPCRELX:
/* fall thru */
case R_X86_64_REX_GOTPCRELX:
/* fall thru */
case R_X86_64_CODE_4_GOTPCRELX:
/* fall thru */
case R_X86_64_CODE_5_GOTPCRELX:
/* fall thru */
case R_X86_64_CODE_6_GOTPCRELX:
word = 4;
val = fs->G + fs->GOT + fs->A - fs->P;
break;
case R_X86_64_GOTOFF64:
word = 8;
val = fs->S + fs->A - fs->GOT;
break;
case R_X86_64_GOTPC32:
word = 4;
val = fs->GOT + fs->A - fs->P;
break;
case R_X86_64_GOT64:
word = 8;
val = fs->G + fs->A;
break;
case R_X86_64_GOTPC64:
word = 8;
val = fs->GOT - fs->P + fs->A;
break;
case R_X86_64_PLTOFF64:
word = 8;
val = fs->L - fs->GOT + fs->A;
break;
default:
UNHANDL_DEF("x86_64", rel_type);
return;
}
switch (word) {
default:
break;
case 1:
buf[0] = val;
rz_buf_write_at(buf_patched, patch_addr, buf, 1);
break;
case 2:
rz_write_le16(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
break;
case 4:
rz_write_le32(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
case 8:
rz_write_le64(buf, val);
rz_buf_write_at(buf_patched, patch_addr, buf, 8);
break;
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_rx(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[4] = { 0 };
ut64 val = 0;
// no dynamic for rx-elf program, handle rx elf object reloc type (emulate linkage map)
// and no GOT/PLT for existed for rx-elf, leave no imports info for extern symbol
switch (rel_type) {
// simply use rizin default symbol resolution to map OBJECT variable symbol to vaddr
case R_RX_NONE:
return;
case R_RX_DIR32:
val = fs->S + fs->A;
rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
break;
case R_RX_DIR24S_PCREL:
val = fs->S + fs->A - fs->P + 1;
if (big_endian) {
buf[2] = val;
buf[1] = val >> 8;
buf[0] = val >> 16;
} else {
buf[0] = val;
buf[1] = val >> 8;
buf[2] = val >> 16;
}
// write 3 Bytes
rz_buf_write_at(buf_patched, patch_addr, buf, 3);
break;
default:
UNHANDL_DEF("Renesas RX", rel_type);
return;
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_alpha(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[4] = { 0 };
ut64 val = 0;
switch (rel_type) {
case R_ALPHA_NONE:
return;
case R_ALPHA_REFLONG:
val = fs->S + fs->A;
rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
break;
case R_ALPHA_REFQUAD:
val = fs->S + fs->A;
rz_buf_write_ble64_at(buf_patched, patch_addr, val, big_endian);
break;
case R_ALPHA_SREL16:
val = fs->S + fs->A - fs->P + 1;
if (big_endian) {
buf[1] = val;
buf[0] = val >> 8;
} else {
buf[0] = val;
buf[1] = val >> 8;
}
rz_buf_write_at(buf_patched, patch_addr, buf, 2);
break;
case R_ALPHA_SREL32:
val = fs->S + fs->A - fs->P + 1;
if (big_endian) {
buf[3] = val;
buf[2] = val >> 8;
buf[1] = val >> 16;
buf[0] = val >> 24;
} else {
buf[0] = val;
buf[1] = val >> 8;
buf[2] = val >> 16;
buf[3] = val >> 24;
}
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
break;
default:
UNHANDL_DEF("Alpha", rel_type);
return;
}
}
/**
* \brief Patches the opcode at a given address depending on the relocation type.
*
* NOTE: Some relocation symbols are not yet implemented
*
* \param buf_patched Buffer from which the opcode is read and the patched opcode is written to.
* \param patch_addr The address of the opcode being patched.
* \param rel_type The relocation type.
* \param big_endian The endianness - true if BE, false if LE
* \param fs Formular values to calculate the new relocation value.
*/
static void patch_reloc_parisc(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[8] = { 0 };
ut64 val = 0;
switch (rel_type) {
default:
UNHANDL_DEF("PARISC", rel_type);
return;
case R_PARISC_COPY:
/* fall-thru */
case R_PARISC_NONE:
return;
case R_PARISC_DIR32: // S + A
rz_buf_read_at(buf_patched, patch_addr, buf, 4);
val = rz_read_ble32(buf, big_endian);
val += fs->S + fs->A;
rz_write_ble32(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 4);
return;
case R_PARISC_DIR64: // S + A
rz_buf_read_at(buf_patched, patch_addr, buf, 8);
val = rz_read_ble64(buf, big_endian);
val += fs->S + fs->A;
rz_write_ble64(buf, val, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, 8);
return;
}
}
static void patch_reloc_avr(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs) {
rz_return_if_fail(buf_patched && fs);
ut8 buf[2] = { 0 };
st64 offset = 0;
ut16 opcode = 0;
ut32 nbytes = 2;
ut64 val = fs->S + fs->A;
switch (rel_type) {
case R_AVR_NONE:
return;
case R_AVR_32:
rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
break;
case R_AVR_7_PCREL:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val - fs->P - 2) / 2;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x3F8, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_13_PCREL:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val - fs->P - 2) / 2;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xFFF, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_16:
rz_buf_write_ble16_at(buf_patched, patch_addr, val, big_endian);
break;
case R_AVR_16_PM:
rz_buf_write_ble16_at(buf_patched, patch_addr, val / 2, big_endian);
break;
case R_AVR_LO8_LDI:
/* fall through */
case R_AVR_LDI:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = val & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HI8_LDI:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val >> 8) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HH8_LDI:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val >> 16) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_LO8_LDI_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (-val) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HI8_LDI_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = ((-val) >> 8) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HH8_LDI_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = ((-val) >> 16) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_LO8_LDI_PM:
/* fall through */
case R_AVR_LO8_LDI_GS:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = val & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HI8_LDI_PM:
/* fall through */
case R_AVR_HI8_LDI_GS:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val >> 8) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HH8_LDI_PM:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val >> 16) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_LO8_LDI_PM_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (-val) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HI8_LDI_PM_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = ((-val) >> 8) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_HH8_LDI_PM_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = ((-val) >> 16) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset / 2);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_CALL:
nbytes = 4;
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
val = val / 2;
break;
case R_AVR_6:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x2C07, val);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_6_ADIW:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xCF, val);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_MS8_LDI:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val >> 24) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_MS8_LDI_NEG:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = ((-val) >> 24) & 0xFF;
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF0F, offset);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_8:
/* fall through */
case R_AVR_8_LO8:
offset = val & 0xFF;
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
break;
case R_AVR_8_HI8:
offset = (val >> 8) & 0xFF;
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
break;
case R_AVR_8_HLO8:
offset = (val >> 16) & 0xFF;
rz_buf_write_ble32_at(buf_patched, patch_addr, offset, big_endian);
break;
case R_AVR_DIFF8:
/* fall through */
case R_AVR_DIFF16:
/* fall through */
case R_AVR_DIFF32:
/* Value already written by assembler */
break;
case R_AVR_LDS_STS_16:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
offset = (val - 0x40) & 0x7F;
offset = (val & 0x0f) | ((val & 0x30) << 5) | ((val & 0x40) << 2);
opcode = rz_read_ble16(buf, big_endian) | offset;
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_PORT6:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0x60F, val);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_PORT5:
rz_buf_read_at(buf_patched, patch_addr, buf, nbytes);
opcode = rz_read_ble16(buf, big_endian) | rz_bits_spread(0xF8, val);
rz_write_ble16(buf, opcode, big_endian);
rz_buf_write_at(buf_patched, patch_addr, buf, nbytes);
break;
case R_AVR_32_PCREL:
rz_buf_write_ble32_at(buf_patched, patch_addr, val - fs->P, big_endian);
break;
default:
UNHANDL_DEF("AVR", rel_type);
break;
}
}
// U-Type: 32-bit instructions that store a 20-bit immediate in their upper 20 bit
static const ut32 RISCV_U_TYPE_IMM_MASK = ((1ULL << 20) - 1) << 12;
// I-Type: 32-bit instructions that store a 12-bit immediate in their upper 12 bit
static const ut32 RISCV_I_TYPE_IMM_MASK = ((1ULL << 12) - 1) << 20;
// S-Type: 32-bit instructions that store a 12-bit immediate scattered over 2 places but still in relative order
static const ut32 RISCV_S_TYPE_IMM_MASK = ((0x7F << 25) | (0x1F << 7));
// B-TYPE: 32-bit instructions that store an 11-bit immediate scattered all over and out of order
static const ut32 RISCV_B_TYPE_IMM_MASKS[] = {
1ULL << 31, // bit 31: imm[12]
0x3fULL << 25, // bits 30-25: imm[10:5]
0xfULL << 8, // bits 11-8: imm[4:1]
1ULL << 7 // bit 7: imm[11]
};
// J-TYPE: 32-bit instructions (JAL) that store a 20-bit immediate scattered all over and out of order
static const ut32 RISCV_J_TYPE_IMM_MASKS[] = {
1ULL << 31, // bit 31: imm[20]
0x3ffULL << 21, // bits 30-21: imm[10:1]
1ULL << 20, // bit 20: imm[11]
0xffULL << 12 // bits 19-12: imm[19:12]
};
// CB-Type: 16-bit instructions that store an 8-bit immediate scattered all over and out of order
// the immediate is effectively 9 bit with bit 0 implied and always zero
static const ut16 RISCV_CB_TYPE_IMM_MASKS[] = {
(1 << 12), // bit 12: imm[8]
(3 << 10), // bits 11-10: imm[4:3]
(3 << 5), // bits 6-5: imm[7:6]
(3 << 3), // bits 4-3: imm[2:1]
(1 << 2) // bit 2: imm[5]
};
// CJ-Type: 16-bit instructions that store an 11-bit immediate scattered all over and out of order
// the immediate is effectively 12 bit with bit 0 implied and always zero
static const ut16 RISCV_CJ_TYPE_IMM_MASKS[] = {
(1 << 12), // bit 12: imm[11]
(1 << 11), // bit 11: imm[4]
(3 << 9), // bits 10:9: imm[9:8]
(1 << 8), // bit 8: imm[10]
(1 << 7), // bit 7: imm[6]
(1 << 6), // bit 6: imm[7]
(7 << 3), // bits 5:3: imm[3:1]
(1 << 2) // bit 2: imm[5]
};
// CI-type: 16-bit instructions that store a 6-bit immediate with the 6th bit scattered from the rest but still in relative order
static const ut16 RISCV_CI_TYPE_IMM_MASK = (1 << 12) | (0x1f << 2);
#define RISCV_HI20(i) ((i) + 0x800) >> 12
#define RISCV_LO12(i) ((i) & 0xfff)
#define RISCV_CHECK_NARROWING_32(i, w) \
if (w == 32) { \
i = ((ut32)i); \
}
#define RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, type) \
if (!success) { \
RZ_LOG_ERROR("Failed to successfully patch a %s reloc at %" PFMT64x " (S: %" PFMT64x ", A: %" PFMT64x ", B: %" PFMT64x ", P: %" PFMT64x ")", type, patch_addr, S, A, B, P); \
return; \
}
static void patch_reloc_riscv(RZ_INOUT RzBuffer *buf_patched, const ut64 patch_addr, const int rel_type, bool big_endian, const RelocFormularSymbols *fs, const int bits) {
rz_return_if_fail(buf_patched && fs);
ut64 val = 0;
// narrow address values for 32-bit binaries
ut64 S = (bits == 32) ? ((ut32)fs->S) : fs->S;
ut64 A = (bits == 32) ? ((ut32)fs->A) : fs->A;
ut64 B = (bits == 32) ? ((ut32)fs->B) : fs->B;
ut64 P = (bits == 32) ? ((ut32)fs->P) : fs->P;
switch (rel_type) {
case R_RISCV_NONE:
return;
case R_RISCV_32: {
val = S + A;
bool success = rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_32");
break;
}
case R_RISCV_64: {
val = S + A;
bool success = rz_buf_write_ble64_at(buf_patched, patch_addr, val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_64");
break;
}
case R_RISCV_RELATIVE:
val = A + B;
switch (bits) {
case 32: {
bool success = rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_RELATIVE 32");
break;
}
case 64: {
bool success = rz_buf_write_ble64_at(buf_patched, patch_addr, val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_RELATIVE 64");
break;
}
default:
RZ_LOG_WARN("Unsupported number of bits for R_RISCV_RELATIVE: %d, only 32 bits and 64 bits are supported", bits);
return;
}
break;
case R_RISCV_BRANCH: {
val = S + A - P;
ut64 imm12 = ((val >> 12) & 0x1); // inst[31] = imm[12]
ut64 imm10_5 = ((val >> 5) & 0x3f); // inst[30:25] = imm[10:5]
ut64 imm4_1 = ((val >> 1) & 0xf); // inst[11:8] = imm[4:1]
ut64 imm11 = ((val >> 11) & 0x1); // inst[7] = imm[11]
ut64 imms[4] = { imm12, imm10_5, imm4_1, imm11 };
for (int i = 0; i < sizeof(RISCV_B_TYPE_IMM_MASKS) / sizeof(RISCV_B_TYPE_IMM_MASKS[0]); i++) {
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_B_TYPE_IMM_MASKS[i], imms[i]);
}
break;
}
case R_RISCV_JAL: {
val = S + A - P;
RISCV_CHECK_NARROWING_32(val, bits);
ut64 imm20 = ((val >> 20) & 0x1); // inst[31] = imm[20]
ut64 imm10_1 = ((val >> 1) & 0x3ff); // inst[30:21] = imm[10:1]
ut64 imm11 = ((val >> 11) & 0x1); // inst[20] = imm[11]
ut64 imm19_12 = ((val >> 12) & 0xff); // inst[19:12] = imm[19:12]
ut64 imms[4] = { imm20, imm10_1, imm11, imm19_12 };
for (int i = 0; i < sizeof(RISCV_J_TYPE_IMM_MASKS) / sizeof(RISCV_J_TYPE_IMM_MASKS[0]); i++) {
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_J_TYPE_IMM_MASKS[i], imms[i]);
}
break;
}
// both handled by the same formula
// TODO: CALL_PLT is more complex if the symbol is outside the same object file
case R_RISCV_CALL:
case R_RISCV_CALL_PLT: {
ut64 result = S + A - P;
ut32 hi20 = RISCV_HI20(result);
ut32 lo12 = RISCV_LO12(result);
// the AUIPC part of the call sequence takes the upper 20 bits of the address
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_U_TYPE_IMM_MASK, hi20);
// the JALR part of the call sequence takes the lower 12 bits of the address;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr + 4, RISCV_I_TYPE_IMM_MASK, lo12);
break;
}
case R_RISCV_JUMP_SLOT:
switch (bits) {
case 32: {
bool success = rz_buf_write_ble32_at(buf_patched, patch_addr, S, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_JUMP_SLOT 32");
break;
}
case 64: {
bool success = rz_buf_write_ble64_at(buf_patched, patch_addr, S, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_JUMP_SLOT 64");
break;
}
default:
RZ_LOG_WARN("Unsupported number of bits for R_RISCV_JUMP_SLOT: %d, only 32 bits and 64 bits are supported", bits);
break;
}
break;
case R_RISCV_32_PCREL: {
val = S + A - P;
bool success = rz_buf_write_ble32_at(buf_patched, patch_addr, val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_32_PCREL");
break;
}
case R_RISCV_GOT_HI20: {
val = fs->G + fs->GOT + A - P;
ut32 hi20 = RISCV_HI20(val);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_U_TYPE_IMM_MASK, hi20);
break;
}
case R_RISCV_PCREL_HI20: {
val = S + A - P;
ut32 hi20 = RISCV_HI20(val);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_U_TYPE_IMM_MASK, hi20);
break;
}
case R_RISCV_PCREL_LO12_I:
case R_RISCV_PCREL_LO12_S: {
val = S + A - P;
ut32 lo12 = RISCV_LO12(val);
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, (rel_type == R_RISCV_PCREL_LO12_I) ? RISCV_I_TYPE_IMM_MASK : RISCV_S_TYPE_IMM_MASK, lo12);
break;
}
case R_RISCV_HI20: {
val = S + A;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, RISCV_U_TYPE_IMM_MASK, RISCV_HI20(val));
break;
}
case R_RISCV_LO12_I:
case R_RISCV_LO12_S: {
val = S + A;
patch_val_over_mask_32(buf_patched, big_endian, patch_addr, (rel_type == R_RISCV_LO12_I) ? RISCV_I_TYPE_IMM_MASK : RISCV_S_TYPE_IMM_MASK, RISCV_LO12(val));
break;
}
case R_RISCV_RVC_BRANCH: {
val = S + A - P;
uint16_t imms[] = {
((val >> 8) & 0x1), // imm[8]
((val >> 3) & 0x3), // imm[4:3]
((val >> 6) & 0x3), // imm[7:6]
((val >> 1) & 0x3), // imm[2:1]
((val >> 5) & 0x1) // imm[5]
};
for (int i = 0; i < sizeof(RISCV_CB_TYPE_IMM_MASKS) / sizeof(RISCV_CB_TYPE_IMM_MASKS[0]); i++) {
patch_val_over_mask_16(buf_patched, big_endian, patch_addr, RISCV_CB_TYPE_IMM_MASKS[i], imms[i]);
}
break;
}
case R_RISCV_RVC_JUMP: {
val = S + A - P;
uint16_t imms[] = {
((val >> 11) & 0x1), // imm[11]
((val >> 4) & 0x1), // imm[4]
((val >> 8) & 0x3), // imm[9:8]
((val >> 10) & 0x1), // imm[10]
((val >> 6) & 0x1), // imm[6]
((val >> 7) & 0x1), // imm[7]
((val >> 1) & 0x7), // imm[3:1]
((val >> 5) & 0x1), // imm[5]
};
for (int i = 0; i < sizeof(RISCV_CJ_TYPE_IMM_MASKS) / sizeof(RISCV_CJ_TYPE_IMM_MASKS[0]); i++) {
patch_val_over_mask_16(buf_patched, big_endian, patch_addr, RISCV_CJ_TYPE_IMM_MASKS[i], imms[i]);
}
break;
}
case R_RISCV_RVC_LUI:
val = S + A;
patch_val_over_mask_16(buf_patched, big_endian, patch_addr, RISCV_CI_TYPE_IMM_MASK, val >> 12);
break;
case R_RISCV_ADD8: {
ut8 old_val = 0;
rz_buf_read_ble8_at(buf_patched, patch_addr, &old_val, big_endian);
ut64 result = ((ut64)old_val) + S + A;
ut64 addr = patch_addr;
bool success = rz_buf_write_ble8_offset(buf_patched, &addr, (ut8)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD8");
break;
}
case R_RISCV_ADD16: {
ut16 old_val = 0;
bool success = rz_buf_read_ble16_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD16 [r]");
ut64 result = ((ut64)old_val) + S + A;
success = rz_buf_write_ble16_at(buf_patched, patch_addr, (ut16)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD16 [w]");
break;
}
case R_RISCV_ADD32: {
ut32 old_val = 0;
bool success = rz_buf_read_ble32_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD32 [r]");
ut64 result = ((ut64)old_val) + S + A;
success = rz_buf_write_ble32_at(buf_patched, patch_addr, (ut32)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD32 [w]");
break;
}
case R_RISCV_ADD64: {
ut64 old_val = 0;
bool success = rz_buf_read_ble64_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD64 [r]");
ut64 result = old_val + S + A;
success = rz_buf_write_ble64_at(buf_patched, patch_addr, result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_ADD64 [w]");
break;
}
case R_RISCV_SUB8: {
ut8 old_val = 0;
bool success = rz_buf_read_ble8_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB8 [r]");
ut64 result = ((ut64)old_val) - S - A;
ut64 addr = patch_addr;
success = rz_buf_write_ble8_offset(buf_patched, &addr, (ut8)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB8 [w]");
break;
}
case R_RISCV_SUB16: {
ut16 old_val = 0;
bool success = rz_buf_read_ble16_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB16 [r]");
ut64 result = ((ut64)old_val) - S - A;
success = rz_buf_write_ble16_at(buf_patched, patch_addr, (ut16)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB16 [w]");
break;
}
case R_RISCV_SUB32: {
ut32 old_val = 0;
bool success = rz_buf_read_ble32_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB32 [r]");
ut64 result = ((ut64)old_val) - S - A;
success = rz_buf_write_ble32_at(buf_patched, patch_addr, (ut32)result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB32 [w]");
break;
}
case R_RISCV_SUB64: {
ut64 old_val = 0;
bool success = rz_buf_read_ble64_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB64 [r]");
ut64 result = ((ut64)old_val) - S - A;
success = rz_buf_write_ble64_at(buf_patched, patch_addr, result, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SUB64 [w]");
break;
}
case R_RISCV_SET8: {
val = S + A;
ut64 addr = patch_addr;
bool success = rz_buf_write_ble8_offset(buf_patched, &addr, (ut8)val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SET8");
break;
}
case R_RISCV_SET16: {
val = S + A;
bool success = rz_buf_write_ble16_at(buf_patched, patch_addr, (ut16)val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SET16");
break;
}
case R_RISCV_SET32: {
val = S + A;
bool success = rz_buf_write_ble32_at(buf_patched, patch_addr, (ut32)val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, "R_RISCV_SET32");
break;
}
case R_RISCV_SET6:
case R_RISCV_SUB6: {
ut8 old_val = 0;
bool success = rz_buf_read_ble8_at(buf_patched, patch_addr, &old_val, big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, rel_type == R_RISCV_SET6 ? "R_RISCV_SET6 [r]" : "R_RISCV_SUB6 [r]");
val = S + A;
ut8 result = (rel_type == R_RISCV_SET6) ? val : ((old_val & 0x3F) - val);
success = rz_buf_write_ble8_at(buf_patched, patch_addr, (old_val & 0xC0) | (result & 0x3F), big_endian);
RISCV_CHECK_SUCCESS_RET_IF_FAIL(success, rel_type == R_RISCV_SET6 ? "R_RISCV_SET6 [w]" : "R_RISCV_SUB6 [w]");
break;
}
/*************************************************** UNIMPLEMENTED ***************************************************/
case R_RISCV_TLS_DTPMOD32:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_DTPMOD32 UNIMPLEMENTED");
break;
case R_RISCV_TLS_DTPMOD64:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_DTPMOD64 UNIMPLEMENTED");
break;
case R_RISCV_TLS_TPREL32:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_TPREL32 UNIMPLEMENTED");
break;
case R_RISCV_TLS_TPREL64:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_TPREL64 UNIMPLEMENTED");
break;
case R_RISCV_TLS_GD_HI20:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_GD_HI20 UNIMPLEMENTED");
break;
case R_RISCV_TLS_GOT_HI20:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_GOT_HI20 UNIMPLEMENTED");
break;
case R_RISCV_TLS_DTPREL32:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_DTPREL32 UNIMPLEMENTED");
break;
case R_RISCV_TLS_DTPREL64:
UNHANDL_DEF("RISCV", rel_type);
RZ_LOG_WARN("RISCV Relocations: TLS_DTPREL64 UNIMPLEMENTED");
break;
default:
UNHANDL_DEF("RISC-V", rel_type);
return;
}
}
#undef RISCV_CHECK_SUCCESS_RET_IF_FAIL
#undef UNHANDL
#undef UNHANDL_DEF
#define ARCH_MISSING(NAME) \
RZ_LOG_WARN("Relocation patching for " NAME " is not implemented.\n"); \
return
void Elf_(rz_bin_elf_patch_relocation)(RZ_NONNULL ELFOBJ *bin, RZ_NONNULL RzBinElfReloc *rel, ut64 S, ut64 Z, ut64 B, ut64 L, ut64 GOT, RZ_NONNULL ut64 *AHL) {
rz_return_if_fail(bin && rel && AHL);
ut16 e_machine = bin->ehdr.e_machine;
RelocFormularSymbols formular_sym = {
.A = rel->addend,
.B = B,
.GOT = GOT,
.L = L,
.S = S,
.Z = Z,
.P = rel->vaddr,
.MB = 0,
.G = Elf_(rz_bin_get_reloc_sym_offset_in_got)(bin, rel->sym),
.GP = 0,
.T = 0,
.TLS = 0,
.AHL = *AHL,
.O = rel->sparc_secondary_addend,
};
ut64 patch_addr = rel->paddr != UT64_MAX ? rel->paddr : Elf_(rz_bin_elf_v2p)(bin, rel->vaddr);
bool big_endian = bin->big_endian;
switch (e_machine) {
case EM_QDSP6:
patch_reloc_hexagon(bin->buf_patched, patch_addr, rel->type, &formular_sym);
break;
case EM_ARM:
patch_reloc_arm(bin->buf_patched, patch_addr, rel, big_endian, &formular_sym);
break;
case EM_AARCH64:
patch_reloc_arm64(bin->buf_patched, patch_addr, rel, &formular_sym);
break;
case EM_PPC64:
patch_reloc_ppc64(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_MIPS_X:
/* fall-thru */
case EM_MIPS_RS3_LE:
/* fall-thru */
case EM_MIPS:
patch_reloc_mips(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
// This is a special value used only in mips
// An R_MIPS_HI16 must be followed immediately by an R_MIPS_LO16 relocation record in a SHT_REL section.
// The contents of the two fields to be relocated are combined to form a full 32-bit addend AHL.
*AHL = formular_sym.AHL;
break;
case EM_386:
patch_reloc_x86_32(bin->buf_patched, patch_addr, rel->type, &formular_sym);
break;
case EM_X86_64:
patch_reloc_x86_64(bin->buf_patched, patch_addr, rel->type, &formular_sym);
break;
case EM_RX:
patch_reloc_rx(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_ALPHA:
patch_reloc_alpha(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_SPARC:
case EM_SPARC32PLUS:
case EM_SPARCV9:
patch_reloc_sparc(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_PARISC:
patch_reloc_parisc(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_AVR:
patch_reloc_avr(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym);
break;
case EM_RISCV:
patch_reloc_riscv(bin->buf_patched, patch_addr, rel->type, big_endian, &formular_sym, bin->bits);
break;
case EM_M32: ARCH_MISSING("EM_M32");
case EM_68K: ARCH_MISSING("EM_68K");
case EM_88K: ARCH_MISSING("EM_88K");
case EM_IAMCU: ARCH_MISSING("EM_IAMCU");
case EM_860: ARCH_MISSING("EM_860");
case EM_S370: ARCH_MISSING("EM_S370");
case EM_VPP500: ARCH_MISSING("EM_VPP500");
case EM_960: ARCH_MISSING("EM_960");
case EM_PPC: ARCH_MISSING("EM_PPC");
case EM_S390: ARCH_MISSING("EM_S390");
case EM_SPU: ARCH_MISSING("EM_SPU");
case EM_V800: ARCH_MISSING("EM_V800");
case EM_FR20: ARCH_MISSING("EM_FR20");
case EM_RH32: ARCH_MISSING("EM_RH32");
case EM_RCE: ARCH_MISSING("EM_RCE");
case EM_FAKE_ALPHA: ARCH_MISSING("EM_FAKE_ALPHA");
case EM_SH: ARCH_MISSING("EM_SH");
case EM_TRICORE: ARCH_MISSING("EM_TRICORE");
case EM_ARC: ARCH_MISSING("EM_ARC");
case EM_H8_300: ARCH_MISSING("EM_H8_300");
case EM_H8_300H: ARCH_MISSING("EM_H8_300H");
case EM_H8S: ARCH_MISSING("EM_H8S");
case EM_H8_500: ARCH_MISSING("EM_H8_500");
case EM_IA_64: ARCH_MISSING("EM_IA_64");
case EM_COLDFIRE: ARCH_MISSING("EM_COLDFIRE");
case EM_68HC12: ARCH_MISSING("EM_68HC12");
case EM_MMA: ARCH_MISSING("EM_MMA");
case EM_PCP: ARCH_MISSING("EM_PCP");
case EM_NCPU: ARCH_MISSING("EM_NCPU");
case EM_NDR1: ARCH_MISSING("EM_NDR1");
case EM_STARCORE: ARCH_MISSING("EM_STARCORE");
case EM_ME16: ARCH_MISSING("EM_ME16");
case EM_ST100: ARCH_MISSING("EM_ST100");
case EM_TINYJ: ARCH_MISSING("EM_TINYJ");
case EM_PDSP: ARCH_MISSING("EM_PDSP");
case EM_PDP10: ARCH_MISSING("EM_PDP10");
case EM_PDP11: ARCH_MISSING("EM_PDP11");
case EM_FX66: ARCH_MISSING("EM_FX66");
case EM_ST9PLUS: ARCH_MISSING("EM_ST9PLUS");
case EM_ST7: ARCH_MISSING("EM_ST7");
case EM_68HC16: ARCH_MISSING("EM_68HC16");
case EM_68HC11: ARCH_MISSING("EM_68HC11");
case EM_68HC08: ARCH_MISSING("EM_68HC08");
case EM_68HC05: ARCH_MISSING("EM_68HC05");
case EM_SVX: ARCH_MISSING("EM_SVX");
case EM_ST19: ARCH_MISSING("EM_ST19");
case EM_VAX: ARCH_MISSING("EM_VAX");
case EM_CRIS: ARCH_MISSING("EM_CRIS");
case EM_JAVELIN: ARCH_MISSING("EM_JAVELIN");
case EM_FIREPATH: ARCH_MISSING("EM_FIREPATH");
case EM_ZSP: ARCH_MISSING("EM_ZSP");
case EM_MMIX: ARCH_MISSING("EM_MMIX");
case EM_HUANY: ARCH_MISSING("EM_HUANY");
case EM_PRISM: ARCH_MISSING("EM_PRISM");
case EM_FR30: ARCH_MISSING("EM_FR30");
case EM_D10V: ARCH_MISSING("EM_D10V");
case EM_D30V: ARCH_MISSING("EM_D30V");
case EM_V850: ARCH_MISSING("EM_V850");
case EM_M32R: ARCH_MISSING("EM_M32R");
case EM_MN10300: ARCH_MISSING("EM_MN10300");
case EM_MN10200: ARCH_MISSING("EM_MN10200");
case EM_PJ: ARCH_MISSING("EM_PJ");
case EM_OR1K: ARCH_MISSING("EM_OR1K");
case EM_ARC_COMPACT: ARCH_MISSING("EM_ARC_COMPACT");
case EM_XTENSA: ARCH_MISSING("EM_XTENSA");
case EM_VIDEOCORE: ARCH_MISSING("EM_VIDEOCORE");
case EM_TMM_GPP: ARCH_MISSING("EM_TMM_GPP");
case EM_NS32K: ARCH_MISSING("EM_NS32K");
case EM_TPC: ARCH_MISSING("EM_TPC");
case EM_SNP1K: ARCH_MISSING("EM_SNP1K");
case EM_ST200: ARCH_MISSING("EM_ST200");
case EM_IP2K: ARCH_MISSING("EM_IP2K");
case EM_MAX: ARCH_MISSING("EM_MAX");
case EM_CR: ARCH_MISSING("EM_CR");
case EM_F2MC16: ARCH_MISSING("EM_F2MC16");
case EM_MSP430: ARCH_MISSING("EM_MSP430");
case EM_BLACKFIN: ARCH_MISSING("EM_BLACKFIN");
case EM_SE_C33: ARCH_MISSING("EM_SE_C33");
case EM_SEP: ARCH_MISSING("EM_SEP");
case EM_ARCA: ARCH_MISSING("EM_ARCA");
case EM_UNICORE: ARCH_MISSING("EM_UNICORE");
case EM_EXCESS: ARCH_MISSING("EM_EXCESS");
case EM_DXP: ARCH_MISSING("EM_DXP");
case EM_ALTERA_NIOS2: ARCH_MISSING("EM_ALTERA_NIOS2");
case EM_CRX: ARCH_MISSING("EM_CRX");
case EM_XGATE: ARCH_MISSING("EM_XGATE");
case EM_C166: ARCH_MISSING("EM_C166");
case EM_M16C: ARCH_MISSING("EM_M16C");
case EM_DSPIC30F: ARCH_MISSING("EM_DSPIC30F");
case EM_CE: ARCH_MISSING("EM_CE");
case EM_M32C: ARCH_MISSING("EM_M32C");
case EM_TSK3000: ARCH_MISSING("EM_TSK3000");
case EM_RS08: ARCH_MISSING("EM_RS08");
case EM_SHARC: ARCH_MISSING("EM_SHARC");
case EM_ECOG2: ARCH_MISSING("EM_ECOG2");
case EM_SCORE7: ARCH_MISSING("EM_SCORE7");
case EM_DSP24: ARCH_MISSING("EM_DSP24");
case EM_VIDEOCORE3: ARCH_MISSING("EM_VIDEOCORE3");
case EM_LATTICEMICO32: ARCH_MISSING("EM_LATTICEMICO32");
case EM_SE_C17: ARCH_MISSING("EM_SE_C17");
case EM_TI_C6000: ARCH_MISSING("EM_TI_C6000");
case EM_TI_C2000: ARCH_MISSING("EM_TI_C2000");
case EM_TI_C5500: ARCH_MISSING("EM_TI_C5500");
case EM_TI_ARP32: ARCH_MISSING("EM_TI_ARP32");
case EM_TI_PRU: ARCH_MISSING("EM_TI_PRU");
case EM_MMDSP_PLUS: ARCH_MISSING("EM_MMDSP_PLUS");
case EM_CYPRESS_M8C: ARCH_MISSING("EM_CYPRESS_M8C");
case EM_R32C: ARCH_MISSING("EM_R32C");
case EM_TRIMEDIA: ARCH_MISSING("EM_TRIMEDIA");
case EM_8051: ARCH_MISSING("EM_8051");
case EM_STXP7X: ARCH_MISSING("EM_STXP7X");
case EM_NDS32: ARCH_MISSING("EM_NDS32");
case EM_ECOG1X: ARCH_MISSING("EM_ECOG1X");
case EM_MAXQ30: ARCH_MISSING("EM_MAXQ30");
case EM_XIMO16: ARCH_MISSING("EM_XIMO16");
case EM_MANIK: ARCH_MISSING("EM_MANIK");
case EM_CRAYNV2: ARCH_MISSING("EM_CRAYNV2");
case EM_METAG: ARCH_MISSING("EM_METAG");
case EM_MCST_ELBRUS: ARCH_MISSING("EM_MCST_ELBRUS");
case EM_ECOG16: ARCH_MISSING("EM_ECOG16");
case EM_CR16: ARCH_MISSING("EM_CR16");
case EM_ETPU: ARCH_MISSING("EM_ETPU");
case EM_SLE9X: ARCH_MISSING("EM_SLE9X");
case EM_L10M: ARCH_MISSING("EM_L10M");
case EM_K10M: ARCH_MISSING("EM_K10M");
case EM_AVR32: ARCH_MISSING("EM_AVR32");
case EM_STM8: ARCH_MISSING("EM_STM8");
case EM_TILE64: ARCH_MISSING("EM_TILE64");
case EM_TILEPRO: ARCH_MISSING("EM_TILEPRO");
case EM_MICROBLAZE: ARCH_MISSING("EM_MICROBLAZE");
case EM_CUDA: ARCH_MISSING("EM_CUDA");
case EM_TILEGX: ARCH_MISSING("EM_TILEGX");
case EM_CLOUDSHIELD: ARCH_MISSING("EM_CLOUDSHIELD");
case EM_COREA_1ST: ARCH_MISSING("EM_COREA_1ST");
case EM_COREA_2ND: ARCH_MISSING("EM_COREA_2ND");
case EM_ARCV2: ARCH_MISSING("EM_ARCV2");
case EM_OPEN8: ARCH_MISSING("EM_OPEN8");
case EM_RL78: ARCH_MISSING("EM_RL78");
case EM_VIDEOCORE5: ARCH_MISSING("EM_VIDEOCORE5");
case EM_78KOR: ARCH_MISSING("EM_78KOR");
case EM_56800EX: ARCH_MISSING("EM_56800EX");
case EM_BA1: ARCH_MISSING("EM_BA1");
case EM_BA2: ARCH_MISSING("EM_BA2");
case EM_XCORE: ARCH_MISSING("EM_XCORE");
case EM_MCHP_PIC: ARCH_MISSING("EM_MCHP_PIC");
case EM_KM32: ARCH_MISSING("EM_KM32");
case EM_KMX32: ARCH_MISSING("EM_KMX32");
case EM_EMX16: ARCH_MISSING("EM_EMX16");
case EM_EMX8: ARCH_MISSING("EM_EMX8");
case EM_KVARC: ARCH_MISSING("EM_KVARC");
case EM_CDP: ARCH_MISSING("EM_CDP");
case EM_COGE: ARCH_MISSING("EM_COGE");
case EM_COOL: ARCH_MISSING("EM_COOL");
case EM_NORC: ARCH_MISSING("EM_NORC");
case EM_CSR_KALIMBA: ARCH_MISSING("EM_CSR_KALIMBA");
case EM_Z80: ARCH_MISSING("EM_Z80");
case EM_VISIUM: ARCH_MISSING("EM_VISIUM");
case EM_FT32: ARCH_MISSING("EM_FT32");
case EM_MOXIE: ARCH_MISSING("EM_MOXIE");
case EM_AMDGPU: ARCH_MISSING("EM_AMDGPU");
case EM_LANAI_OLD: ARCH_MISSING("EM_LANAI_OLD");
case EM_CEVA: ARCH_MISSING("EM_CEVA");
case EM_CEVA_X2: ARCH_MISSING("EM_CEVA_X2");
case EM_BPF: ARCH_MISSING("EM_BPF");
case EM_GRAPHCORE_IPU: ARCH_MISSING("EM_GRAPHCORE_IPU");
case EM_IMG1: ARCH_MISSING("EM_IMG1");
case EM_NFP: ARCH_MISSING("EM_NFP");
case EM_VE: ARCH_MISSING("EM_VE");
case EM_CSKY: ARCH_MISSING("EM_CSKY");
case EM_ARC_COMPACT3_64: ARCH_MISSING("EM_ARC_COMPACT3_64");
case EM_MCS6502: ARCH_MISSING("EM_MCS6502");
case EM_ARC_COMPACT3: ARCH_MISSING("EM_ARC_COMPACT3");
case EM_KVX: ARCH_MISSING("EM_KVX");
case EM_65816: ARCH_MISSING("EM_65816");
case EM_LOONGARCH: ARCH_MISSING("EM_LOONGARCH");
case EM_KF32: ARCH_MISSING("EM_KF32");
case EM_U16_U8CORE: ARCH_MISSING("EM_U16_U8CORE");
case EM_TACHYUM: ARCH_MISSING("EM_TACHYUM");
case EM_56800EF: ARCH_MISSING("EM_56800EF");
case EM_AVR_OLD: ARCH_MISSING("EM_AVR_OLD");
case EM_MSP430_OLD: ARCH_MISSING("EM_MSP430_OLD");
case EM_MT: ARCH_MISSING("EM_MT");
case EM_CYGNUS_FR30: ARCH_MISSING("EM_CYGNUS_FR30");
case EM_WEBASSEMBLY: ARCH_MISSING("EM_WEBASSEMBLY");
case EM_S12Z: ARCH_MISSING("EM_S12Z");
case EM_DLX: ARCH_MISSING("EM_DLX");
case EM_CYGNUS_FRV: ARCH_MISSING("EM_CYGNUS_FRV");
case EM_XC16X: ARCH_MISSING("EM_XC16X");
case EM_CYGNUS_D10V: ARCH_MISSING("EM_CYGNUS_D10V");
case EM_CYGNUS_D30V: ARCH_MISSING("EM_CYGNUS_D30V");
case EM_IP2K_OLD: ARCH_MISSING("EM_IP2K_OLD");
case EM_CYGNUS_POWERPC: ARCH_MISSING("EM_CYGNUS_POWERPC");
case EM_CYGNUS_M32R: ARCH_MISSING("EM_CYGNUS_M32R");
case EM_CYGNUS_V850: ARCH_MISSING("EM_CYGNUS_V850");
case EM_S390_OLD: ARCH_MISSING("EM_S390_OLD");
case EM_XTENSA_OLD: ARCH_MISSING("EM_XTENSA_OLD");
case EM_XSTORMY16: ARCH_MISSING("EM_XSTORMY16");
case EM_CYGNUS_MN10300: ARCH_MISSING("EM_CYGNUS_MN10300");
case EM_CYGNUS_MN10200: ARCH_MISSING("EM_CYGNUS_MN10200");
case EM_M32C_OLD: ARCH_MISSING("EM_M32C_OLD");
case EM_IQ2000: ARCH_MISSING("EM_IQ2000");
case EM_NIOS32: ARCH_MISSING("EM_NIOS32");
case EM_CYGNUS_MEP: ARCH_MISSING("EM_CYGNUS_MEP");
case EM_MOXIE_OLD: ARCH_MISSING("EM_MOXIE_OLD");
case EM_MICROBLAZE_OLD: ARCH_MISSING("EM_MICROBLAZE_OLD");
case EM_ADAPTEVA_EPIPHANY: ARCH_MISSING("EM_ADAPTEVA_EPIPHANY");
case EM_V810: ARCH_MISSING("EM_V810");
default:
RZ_LOG_INFO("Relocation patching for machine %d is not implemented.\n", (int)e_machine);
return;
}
}
#undef ARCH_MISSING