Renesas RL78 disassembler plugin (#3649)

This commit is contained in:
Bastian Engel
2023-10-14 00:15:03 +08:00
committed by GitHub
parent 908b8805c7
commit 6df64dbbe8
18 changed files with 5399 additions and 2 deletions
+7 -1
View File
@@ -29,6 +29,7 @@ analysis_plugins_list = [
'ppc_cs',
'propeller',
'pyc',
'rl78',
'rsp',
'snes',
'sparc_cs',
@@ -139,6 +140,7 @@ rz_analysis_sources = [
'p/analysis_ppc_cs.c',
'p/analysis_propeller.c',
'p/analysis_pyc.c',
'p/analysis_rl78.c',
'p/analysis_rsp.c',
'p/analysis_snes.c',
'p/analysis_sparc_cs.c',
@@ -230,7 +232,11 @@ rz_analysis_sources = [
'../asm/arch/luac/v54/analysis_54.c',
'../asm/arch/luac/v54/opcode_54.c',
'../asm/arch/luac/v53/analysis_53.c',
'../asm/arch/luac/v53/opcode_53.c'
'../asm/arch/luac/v53/opcode_53.c',
'../asm/arch/rl78/rl78_instr.c',
'../asm/arch/rl78/rl78_maps.c',
'../asm/arch/rl78/rl78_operand.c',
'../asm/arch/rl78/rl78.c'
]
if capstone_dep.version() == 'next' or capstone_dep.version().split('.')[0].to_int() > 4
+275
View File
@@ -0,0 +1,275 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include <rz_analysis.h>
#include "../../asm/arch/rl78/rl78_instr.h"
#include "../../asm/arch/rl78/rl78.h"
static int rl78_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
const ut8 *buf, int len, RzAnalysisOpMask mask);
static void populate_jump_fields(const RL78Instr *instr, size_t instr_size, ut64 addr, RzAnalysisOp *op);
static char *get_reg_profile(RzAnalysis *analysis);
static int rl78_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
const ut8 *buf, int len, RzAnalysisOpMask mask) {
op->addr = addr;
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
RL78Instr instr = { 0 };
size_t bytes_read = 0;
if (!rl78_dis(&instr, &bytes_read, buf, len)) {
op->size = bytes_read;
return bytes_read;
} else {
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
}
op->size = bytes_read;
op->addr = addr;
switch (instr.operation) {
case RL78_OPERATION_ADD:
case RL78_OPERATION_ADDC:
case RL78_OPERATION_ADDW:
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
break;
case RL78_OPERATION_AND:
case RL78_OPERATION_AND1:
op->type = RZ_ANALYSIS_OP_TYPE_AND;
break;
case RL78_OPERATION_BC:
case RL78_OPERATION_BF:
case RL78_OPERATION_BH:
case RL78_OPERATION_BNC:
case RL78_OPERATION_BNH:
case RL78_OPERATION_BNZ:
case RL78_OPERATION_BT:
case RL78_OPERATION_BTCLR:
case RL78_OPERATION_BZ:
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
populate_jump_fields(&instr, bytes_read, addr, op);
break;
case RL78_OPERATION_BR:
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
populate_jump_fields(&instr, bytes_read, addr, op);
break;
// conditional skip instructions
case RL78_OPERATION_SKC:
case RL78_OPERATION_SKH:
case RL78_OPERATION_SKNC:
case RL78_OPERATION_SKNH:
case RL78_OPERATION_SKNZ:
case RL78_OPERATION_SKZ:
// TODO set op->jump to instruction after next (i.e. skip)
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
break;
case RL78_OPERATION_BRK:
op->type = RZ_ANALYSIS_OP_TYPE_SWI;
break;
case RL78_OPERATION_CALL:
case RL78_OPERATION_CALLT:
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
populate_jump_fields(&instr, bytes_read, addr, op);
break;
case RL78_OPERATION_CLRB:
case RL78_OPERATION_CLRW:
case RL78_OPERATION_CLR1:
// TODO (byte/word/bitclear)
break;
case RL78_OPERATION_CMP:
case RL78_OPERATION_CMPS:
case RL78_OPERATION_CMPW:
case RL78_OPERATION_CMP0:
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
break;
case RL78_OPERATION_DEC:
case RL78_OPERATION_DECW:
case RL78_OPERATION_SUB:
case RL78_OPERATION_SUBC:
case RL78_OPERATION_SUBW:
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
break;
case RL78_OPERATION_EI:
case RL78_OPERATION_DI:
// TODO (interrupt enable/disable)
break;
case RL78_OPERATION_DIVHU:
case RL78_OPERATION_DIVWU:
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
break;
case RL78_OPERATION_HALT:
// TODO (halt)
break;
case RL78_OPERATION_INC:
case RL78_OPERATION_INCW:
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
break;
case RL78_OPERATION_MULH:
case RL78_OPERATION_MULHU:
case RL78_OPERATION_MULU:
// multiply-and-accumulate
case RL78_OPERATION_MACH:
case RL78_OPERATION_MACHU:
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
break;
case RL78_OPERATION_MOV:
case RL78_OPERATION_MOVS:
case RL78_OPERATION_MOVW:
case RL78_OPERATION_MOV1:
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
break;
case RL78_OPERATION_NOP:
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
break;
case RL78_OPERATION_NOT1:
op->type = RZ_ANALYSIS_OP_TYPE_NOT;
break;
case RL78_OPERATION_ONEB:
case RL78_OPERATION_ONEW:
// TODO (byte/word set to 1)
break;
case RL78_OPERATION_OR:
case RL78_OPERATION_OR1:
op->type = RZ_ANALYSIS_OP_TYPE_OR;
break;
case RL78_OPERATION_POP:
op->type = RZ_ANALYSIS_OP_TYPE_POP;
break;
case RL78_OPERATION_PUSH:
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
break;
case RL78_OPERATION_RET:
op->type = RZ_ANALYSIS_OP_TYPE_RET;
break;
case RL78_OPERATION_RETB:
case RL78_OPERATION_RETI:
// TODO (return from software/hardware vectored interrupt)
break;
case RL78_OPERATION_ROL:
case RL78_OPERATION_ROLC:
case RL78_OPERATION_ROLWC:
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
break;
case RL78_OPERATION_ROR:
case RL78_OPERATION_RORC:
op->type = RZ_ANALYSIS_OP_TYPE_ROR;
break;
case RL78_OPERATION_SAR:
case RL78_OPERATION_SARW:
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
break;
case RL78_OPERATION_SEL:
case RL78_OPERATION_SET1:
case RL78_OPERATION_SHL:
case RL78_OPERATION_SHLW:
case RL78_OPERATION_SHR:
case RL78_OPERATION_SHRW:
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
break;
case RL78_OPERATION_STOP:
// TODO (stop mode set)
break;
case RL78_OPERATION_XCH:
case RL78_OPERATION_XCHW:
op->type = RZ_ANALYSIS_OP_TYPE_XCHG;
break;
case RL78_OPERATION_XOR:
case RL78_OPERATION_XOR1:
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
break;
default:
rz_warn_if_reached();
break;
}
return op->size;
}
static void populate_jump_fields(const RL78Instr *instr, size_t instr_size, ut64 addr, RzAnalysisOp *op) {
const RL78Operand *target = &instr->op0;
if (instr->operation == RL78_OPERATION_BT ||
instr->operation == RL78_OPERATION_BF ||
instr->operation == RL78_OPERATION_BTCLR) {
target = &instr->op1;
}
switch (target->type) {
case RL78_OP_TYPE_ABSOLUTE_ADDR_20:
case RL78_OP_TYPE_ABSOLUTE_ADDR_16:
op->jump = target->v0;
break;
case RL78_OP_TYPE_RELATIVE_ADDR_16:
case RL78_OP_TYPE_RELATIVE_ADDR_8:
op->jump = addr + target->v0;
case RL78_OP_TYPE_SYMBOL:
// TODO indirect call to symbol (CALL AX)
break;
default:
rz_warn_if_reached();
break;
}
if (op->type == RZ_ANALYSIS_OP_TYPE_CJMP) {
op->fail = addr + instr_size;
}
}
static char *get_reg_profile(RzAnalysis *analysis) {
const char *p =
"=PC pc\n"
"=SP sp\n"
"=ZF z\n"
"=CF cy\n"
"=SN %s\n" // x8 on linux or android, x16 for the rest
// ABI: https://www.renesas.com/eu/en/document/mat/cc-rl-compiler-users-manual
"=A0 ax\n"
"=A1 bc\n"
"=A2 de\n"
// general-purpose registers
"gpr hl .16 0 0\n"
"gpr de .16 0 0\n"
"gpr bc .16 0 0\n"
"gpr ax .16 0 0\n"
"gpr h .8 0 0\n"
"gpr l .8 0 0\n"
"gpr d .8 0 0\n"
"gpr e .8 0 0\n"
"gpr b .8 0 0\n"
"gpr c .8 0 0\n"
"gpr a .8 0 0\n"
"gpr x .8 0 0\n"
// flags
"flg psw .8 0 0 ie_z_rbs1_ac_rbs0_isp1_isp0_cy\n"
"flg ie .1 0 0 interrupt_enable\n"
"flg z .1 0 0 zero\n"
"flg rbs1 .1 0 0 register_bank_select_bit_1\n"
"flg ac .1 0 0 auxiliary_carry\n" // set if carry or borrow at bit 3
"flg rbs0 .1 0 0 register_bank_select_bit_0\n"
"flg isp1 .1 0 0 in_service_priority_flags_bit_1\n"
"flg isp0 .1 0 0 in_service_priority_flags_bit_0\n"
"flg cy .1 0 0 carry\n";
return strdup(p);
}
RzAnalysisPlugin rz_analysis_plugin_rl78 = {
.name = "rl78",
.desc = "Renesas RL78 analysis plugin",
.license = "LGPL3",
.arch = "rl78",
.bits = 16,
.op = &rl78_op,
.get_reg_profile = &get_reg_profile
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ANALYSIS,
.data = &rz_analysis_plugin_rl78,
.version = RZ_VERSION
};
#endif
+271
View File
@@ -0,0 +1,271 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rl78.h"
#include "rl78_maps.h"
#include <stdio.h>
#define CHECK_BOUNDS(p, len) \
if (*p >= len) { \
return false; \
}
static bool parse_operand(RL78Operand RZ_INOUT *operand, size_t RZ_INOUT *next_byte_p,
const ut8 RZ_BORROW *buf, size_t buf_len);
static inline bool optype_es_applies(RL78OperandType type);
// used to decide whether an operand could resolve to a symbol
static inline bool final_value_known(RL78OperandType type);
static inline RL78Label addr_to_symbol(int addr);
/**
* \brief Disassemble a byte sequence into an rl78_instr
* \param instr Resulting instruction
* \param byte_read Number of bytes disassembled
* \param buf Byte buffer
* \param buf_len Length of the buffer
* \return false if byte sequence does not represent a valid instruction
*/
bool rl78_dis(RL78Instr RZ_OUT *instr, size_t RZ_OUT *bytes_read,
const ut8 *buf, size_t buf_len) {
if (buf_len == 0) {
*bytes_read = 0;
return false;
}
size_t next_byte_p = 0;
int byte = buf[next_byte_p++];
bool extension_addressing = false;
if (byte == 0x11) {
extension_addressing = true;
if (next_byte_p >= buf_len) {
*bytes_read = next_byte_p;
return false;
}
byte = buf[next_byte_p++];
}
if (next_byte_p + 1 < buf_len) {
// MULHU, MULH...
if (byte == 0xCE && buf[next_byte_p] == 0xFB) {
switch (buf[next_byte_p + 1]) {
case 0x01: instr->operation = RL78_OPERATION_MULHU; break;
case 0x02: instr->operation = RL78_OPERATION_MULH; break;
case 0x03: instr->operation = RL78_OPERATION_DIVHU; break;
case 0x0B: instr->operation = RL78_OPERATION_DIVWU; break;
case 0x05: instr->operation = RL78_OPERATION_MACHU; break;
case 0x06: instr->operation = RL78_OPERATION_MACH; break;
default: break;
}
}
// EI/DI aliases for set1 psw.7/clr1 psw.7
if (byte == 0x71 && buf[next_byte_p + 1] == 0xFA) {
switch (buf[next_byte_p]) {
case 0x7A: instr->operation = RL78_OPERATION_EI; break;
case 0x7B: instr->operation = RL78_OPERATION_DI; break;
default: break;
}
}
if (instr->operation != RL78_OPERATION_NONE) {
*bytes_read = next_byte_p + 2;
return true;
}
}
// regular processing (get correct map, extract instruction and parse operands)
int map = 0;
switch (byte) {
case 0x31:
// 4th map
map = 3;
break;
case 0x61:
// 2nd map
map = 1;
break;
case 0x71:
// 3rd map
map = 2;
break;
default:
break;
}
// get next byte if other map was chosen
if (map > 0) {
if (next_byte_p >= buf_len) {
*bytes_read = next_byte_p;
return false;
}
byte = buf[next_byte_p++];
}
*instr = rl78_instr_maps[(map * 256) + byte];
// an empty slot was indexed
if (instr->operation == RL78_OPERATION_NONE) {
*bytes_read = next_byte_p;
return false;
}
if (!parse_operand(&instr->op0, &next_byte_p, buf, buf_len) ||
!parse_operand(&instr->op1, &next_byte_p, buf, buf_len)) {
*bytes_read = next_byte_p;
return false;
}
if (extension_addressing) {
if (optype_es_applies(instr->op0.type)) {
instr->op0.flags |= RL78_OP_FLAG_ES;
} else if (optype_es_applies(instr->op1.type)) {
instr->op1.flags |= RL78_OP_FLAG_ES;
}
}
*bytes_read = next_byte_p;
return true;
}
static bool parse_operand(RL78Operand RZ_INOUT *operand, size_t RZ_INOUT *next_byte_p,
const ut8 RZ_BORROW *buf, size_t buf_len) {
switch (operand->type) {
// byte-sized operands
case RL78_OP_TYPE_IMMEDIATE_8:
case RL78_OP_TYPE_RELATIVE_ADDR_8:
case RL78_OP_TYPE_BASED_ADDR_8:
// already has value
if (operand->v1 != 0) {
return true;
}
CHECK_BOUNDS(next_byte_p, buf_len);
if (operand->type == RL78_OP_TYPE_BASED_ADDR_8) {
// write to v1 since v0 already has base register
operand->v1 = buf[*next_byte_p];
} else {
operand->v0 = buf[*next_byte_p];
}
(*next_byte_p)++;
break;
case RL78_OP_TYPE_SFR:
if (operand->v0 != 0) {
// already has value
return true;
}
CHECK_BOUNDS(next_byte_p, buf_len);
operand->v0 = 0xFFF00 + buf[*next_byte_p];
(*next_byte_p)++;
break;
case RL78_OP_TYPE_SADDR:
CHECK_BOUNDS(next_byte_p, buf_len);
operand->v0 = 0xFFE20 + buf[*next_byte_p];
(*next_byte_p)++;
break;
// word-sized operands
case RL78_OP_TYPE_IMMEDIATE_16:
case RL78_OP_TYPE_ABSOLUTE_ADDR_16:
case RL78_OP_TYPE_RELATIVE_ADDR_16:
case RL78_OP_TYPE_BASED_ADDR_16:
CHECK_BOUNDS(next_byte_p, buf_len);
int word = buf[*next_byte_p];
(*next_byte_p)++;
CHECK_BOUNDS(next_byte_p, buf_len);
word |= (int)buf[*next_byte_p] << 8;
(*next_byte_p)++;
if (operand->type == RL78_OP_TYPE_BASED_ADDR_16) {
// write to v1 since v0 already has base register
operand->v1 = word;
} else {
operand->v0 = word;
}
break;
// 20 bit
case RL78_OP_TYPE_ABSOLUTE_ADDR_20:
CHECK_BOUNDS(next_byte_p, buf_len);
int val = buf[*next_byte_p];
(*next_byte_p)++;
CHECK_BOUNDS(next_byte_p, buf_len);
val |= (int)buf[*next_byte_p] << 8;
(*next_byte_p)++;
CHECK_BOUNDS(next_byte_p, buf_len);
val |= (int)(buf[*next_byte_p] & 0xf) << 16;
(*next_byte_p)++;
operand->v0 = val;
break;
default: // no need to get additional data (NONE, SYMBOL, ...)
break;
}
if (final_value_known(operand->type)) {
// try resolving address to symbol for known fixed addresses
RL78Label symbol = addr_to_symbol(operand->v0);
if (rl78_symbol_valid(symbol)) {
operand->v0 = symbol;
}
}
return true;
}
static inline bool optype_es_applies(RL78OperandType type) {
return type == RL78_OP_TYPE_INDIRECT_ADDR ||
type == RL78_OP_TYPE_BASED_ADDR_8 ||
type == RL78_OP_TYPE_BASED_ADDR_16 ||
type == RL78_OP_TYPE_ABSOLUTE_ADDR_16 ||
type == RL78_OP_TYPE_BASED_INDEX_ADDR;
}
static inline bool final_value_known(RL78OperandType type) {
return type == RL78_OP_TYPE_ABSOLUTE_ADDR_16 ||
type == RL78_OP_TYPE_ABSOLUTE_ADDR_20 ||
type == RL78_OP_TYPE_SFR ||
type == RL78_OP_TYPE_SADDR;
}
static inline RL78Label addr_to_symbol(int addr) {
switch (addr) {
// TODO add general-purpose registers
case 0xFFFF8: return RL78_SFR_SPL;
case 0xFFFF9: return RL78_SFR_SPH;
case 0xFFFFA:
return RL78_SFR_PSW;
// case 0xFB: (reserved)
case 0xFFFFC: return RL78_SFR_CS;
case 0xFFFFD: return RL78_SFR_ES;
case 0xFFFFE: return RL78_SFR_PMC;
case 0xFFFFF: return RL78_SFR_MEM;
default:
// invalid
return _RL78_SYMBOL_COUNT;
}
}
+15
View File
@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RL78_H
#define RL78_H
#include "rl78_instr.h"
#include <rz_util.h>
#include <rz_types.h>
bool rl78_dis(RL78Instr RZ_OUT *instr, size_t RZ_OUT *bytes_read,
const ut8 *buf, size_t buf_len);
#endif
+123
View File
@@ -0,0 +1,123 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rl78_instr.h"
#include <rz_util.h>
#include <rz_types.h>
static const char *RL78_STRINGS_OPERATIONS[] = {
[RL78_OPERATION_ADD] = "add",
[RL78_OPERATION_ADDC] = "addc",
[RL78_OPERATION_ADDW] = "addw",
[RL78_OPERATION_AND] = "and",
[RL78_OPERATION_AND1] = "and1",
[RL78_OPERATION_BC] = "bc",
[RL78_OPERATION_BF] = "bf",
[RL78_OPERATION_BH] = "bh",
[RL78_OPERATION_BNC] = "bnc",
[RL78_OPERATION_BNH] = "bnh",
[RL78_OPERATION_BNZ] = "bnz",
[RL78_OPERATION_BR] = "br",
[RL78_OPERATION_BRK] = "brk",
[RL78_OPERATION_BT] = "bt",
[RL78_OPERATION_BTCLR] = "btclr",
[RL78_OPERATION_BZ] = "bz",
[RL78_OPERATION_CALL] = "call",
[RL78_OPERATION_CALLT] = "callt",
[RL78_OPERATION_CLRB] = "clrb",
[RL78_OPERATION_CLRW] = "clrw",
[RL78_OPERATION_CLR1] = "clr1",
[RL78_OPERATION_CMP] = "cmp",
[RL78_OPERATION_CMPS] = "cmps",
[RL78_OPERATION_CMPW] = "cmpw",
[RL78_OPERATION_CMP0] = "cmp0",
[RL78_OPERATION_DEC] = "dec",
[RL78_OPERATION_DECW] = "decw",
[RL78_OPERATION_DI] = "di",
[RL78_OPERATION_DIVHU] = "divhu",
[RL78_OPERATION_DIVWU] = "divwu",
[RL78_OPERATION_EI] = "ei",
[RL78_OPERATION_HALT] = "halt",
[RL78_OPERATION_INC] = "inc",
[RL78_OPERATION_INCW] = "incw",
[RL78_OPERATION_MACH] = "mach",
[RL78_OPERATION_MACHU] = "machu",
[RL78_OPERATION_MOV] = "mov",
[RL78_OPERATION_MOVS] = "movs",
[RL78_OPERATION_MOVW] = "movw",
[RL78_OPERATION_MOV1] = "mov1",
[RL78_OPERATION_MULH] = "mulh",
[RL78_OPERATION_MULHU] = "mulhu",
[RL78_OPERATION_MULU] = "mulu",
[RL78_OPERATION_NOP] = "nop",
[RL78_OPERATION_NOT1] = "not1",
[RL78_OPERATION_ONEB] = "oneb",
[RL78_OPERATION_ONEW] = "onew",
[RL78_OPERATION_OR] = "or",
[RL78_OPERATION_OR1] = "or1",
[RL78_OPERATION_POP] = "pop",
[RL78_OPERATION_PUSH] = "push",
[RL78_OPERATION_RET] = "ret",
[RL78_OPERATION_RETB] = "retb",
[RL78_OPERATION_RETI] = "reti",
[RL78_OPERATION_ROL] = "rol",
[RL78_OPERATION_ROLC] = "rolc",
[RL78_OPERATION_ROLWC] = "rolwc",
[RL78_OPERATION_ROR] = "ror",
[RL78_OPERATION_RORC] = "rorc",
[RL78_OPERATION_SAR] = "sar",
[RL78_OPERATION_SARW] = "sarw",
[RL78_OPERATION_SEL] = "sel",
[RL78_OPERATION_SET1] = "set1",
[RL78_OPERATION_SHL] = "shl",
[RL78_OPERATION_SHLW] = "shlw",
[RL78_OPERATION_SHR] = "shr",
[RL78_OPERATION_SHRW] = "shrw",
[RL78_OPERATION_SKC] = "skc",
[RL78_OPERATION_SKH] = "skh",
[RL78_OPERATION_SKNC] = "sknc",
[RL78_OPERATION_SKNH] = "sknh",
[RL78_OPERATION_SKNZ] = "sknz",
[RL78_OPERATION_SKZ] = "skz",
[RL78_OPERATION_STOP] = "stop",
[RL78_OPERATION_SUB] = "sub",
[RL78_OPERATION_SUBC] = "subc",
[RL78_OPERATION_SUBW] = "subw",
[RL78_OPERATION_XCH] = "xch",
[RL78_OPERATION_XCHW] = "xchw",
[RL78_OPERATION_XOR] = "xor",
[RL78_OPERATION_XOR1] = "xor1",
};
bool rl78_instr_to_string(RzStrBuf RZ_OUT *dst, const RL78Instr RZ_BORROW *instr) {
rz_return_val_if_fail(instr->operation > 0 &&
instr->operation < _RL78_OPERATION_COUNT,
false);
// 16 characters suffice for each operand
RzStrBuf buf_op0, buf_op1;
bool has_op0 = instr->op0.type != RL78_OP_TYPE_NONE;
bool has_op1 = instr->op1.type != RL78_OP_TYPE_NONE;
rz_return_val_if_fail(!has_op0 || rl78_operand_to_string(&buf_op0, &instr->op0),
false);
rz_return_val_if_fail(!has_op1 || rl78_operand_to_string(&buf_op1, &instr->op1),
false);
if (has_op0 && has_op1) {
rz_strbuf_appendf(dst, "%s %s, %s",
RL78_STRINGS_OPERATIONS[instr->operation],
buf_op0.buf, buf_op1.buf);
} else if (has_op0) {
rz_strbuf_appendf(dst, "%s %s",
RL78_STRINGS_OPERATIONS[instr->operation],
buf_op0.buf);
} else {
rz_strbuf_appendf(dst, "%s",
RL78_STRINGS_OPERATIONS[instr->operation]);
}
return true;
}
+116
View File
@@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RL78_INSTR_H
#define RL78_INSTR_H
#include "rl78_operand.h"
#include <rz_util.h>
#include <rz_types.h>
typedef enum RL78Operation {
RL78_OPERATION_NONE,
RL78_OPERATION_ADD,
RL78_OPERATION_ADDC,
RL78_OPERATION_ADDW,
RL78_OPERATION_AND,
RL78_OPERATION_AND1,
RL78_OPERATION_BC,
RL78_OPERATION_BF,
RL78_OPERATION_BH,
RL78_OPERATION_BNC,
RL78_OPERATION_BNH,
RL78_OPERATION_BNZ,
RL78_OPERATION_BR,
RL78_OPERATION_BRK,
RL78_OPERATION_BT,
RL78_OPERATION_BTCLR,
RL78_OPERATION_BZ,
RL78_OPERATION_CALL,
RL78_OPERATION_CALLT,
RL78_OPERATION_CLRB,
RL78_OPERATION_CLRW,
RL78_OPERATION_CLR1,
RL78_OPERATION_CMP,
RL78_OPERATION_CMPS,
RL78_OPERATION_CMPW,
RL78_OPERATION_CMP0,
RL78_OPERATION_DEC,
RL78_OPERATION_DECW,
RL78_OPERATION_DI,
RL78_OPERATION_DIVHU,
RL78_OPERATION_DIVWU,
RL78_OPERATION_EI,
RL78_OPERATION_HALT,
RL78_OPERATION_INC,
RL78_OPERATION_INCW,
RL78_OPERATION_MACH,
RL78_OPERATION_MACHU,
RL78_OPERATION_MOV,
RL78_OPERATION_MOVS,
RL78_OPERATION_MOVW,
RL78_OPERATION_MOV1,
RL78_OPERATION_MULH,
RL78_OPERATION_MULHU,
RL78_OPERATION_MULU,
RL78_OPERATION_NOP,
RL78_OPERATION_NOT1,
RL78_OPERATION_ONEB,
RL78_OPERATION_ONEW,
RL78_OPERATION_OR,
RL78_OPERATION_OR1,
RL78_OPERATION_POP,
RL78_OPERATION_PUSH,
RL78_OPERATION_RET,
RL78_OPERATION_RETB,
RL78_OPERATION_RETI,
RL78_OPERATION_ROL,
RL78_OPERATION_ROLC,
RL78_OPERATION_ROLWC,
RL78_OPERATION_ROR,
RL78_OPERATION_RORC,
RL78_OPERATION_SAR,
RL78_OPERATION_SARW,
RL78_OPERATION_SEL,
RL78_OPERATION_SET1,
RL78_OPERATION_SHL,
RL78_OPERATION_SHLW,
RL78_OPERATION_SHR,
RL78_OPERATION_SHRW,
RL78_OPERATION_SKC,
RL78_OPERATION_SKH,
RL78_OPERATION_SKNC,
RL78_OPERATION_SKNH,
RL78_OPERATION_SKNZ,
RL78_OPERATION_SKZ,
RL78_OPERATION_STOP,
RL78_OPERATION_SUB,
RL78_OPERATION_SUBC,
RL78_OPERATION_SUBW,
RL78_OPERATION_XCH,
RL78_OPERATION_XCHW,
RL78_OPERATION_XOR,
RL78_OPERATION_XOR1,
_RL78_OPERATION_COUNT
} RL78Operation;
typedef struct RL78Instr {
RL78Operand op0;
RL78Operand op1;
RL78Operation operation;
} RL78Instr;
/**
* \brief Convert an RL78 instruction to a string
* \param dst Caller-supplied character buffer to print into
* \param n Size of dst
* \param operand RL78 instruction to be printed
* \return false On failure
*/
bool rl78_instr_to_string(RzStrBuf RZ_OUT *dst, const RL78Instr RZ_BORROW *instr);
#endif
File diff suppressed because it is too large Load Diff
+11
View File
@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RL78_MAPS_H
#define RL78_MAPS_H
#include "rl78_instr.h"
extern RL78Instr rl78_instr_maps[4 * 256];
#endif
+136
View File
@@ -0,0 +1,136 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rl78_operand.h"
#include <rz_types.h>
#include <rz_core.h>
#include <rz_util.h>
static const char *RL78_STRINGS_SYMBOLS[] = {
[RL78_GPR_X] = "x",
[RL78_GPR_A] = "a",
[RL78_GPR_C] = "c",
[RL78_GPR_B] = "b",
[RL78_GPR_E] = "e",
[RL78_GPR_D] = "d",
[RL78_GPR_L] = "l",
[RL78_GPR_H] = "h",
[RL78_GPR_AX] = "ax",
[RL78_GPR_BC] = "bc",
[RL78_GPR_DE] = "de",
[RL78_GPR_HL] = "hl",
[RL78_SFR_MEM] = "mem",
[RL78_SFR_PMC] = "pmc",
[RL78_SFR_ES] = "es",
[RL78_SFR_CS] = "cs",
[RL78_SFR_PSW] = "psw",
[RL78_SFR_SPH] = "sph",
[RL78_SFR_SPL] = "spl",
[RL78_CR_PC] = "pc",
[RL78_CR_PSW] = "psw",
[RL78_CR_SP] = "sp",
[RL78_RB_RB0] = "rb0",
[RL78_RB_RB1] = "rb1",
[RL78_RB_RB2] = "rb2",
[RL78_RB_RB3] = "rb3",
[RL78_PSW_CY] = "cy",
[RL78_PSW_AC] = "ac",
[RL78_PSW_Z] = "z",
};
bool rl78_operand_to_string(RzStrBuf RZ_OUT *dst, const RL78Operand RZ_BORROW *operand) {
if (operand->type <= RL78_OP_TYPE_NONE ||
operand->type >= _RL78_OP_TYPE_COUNT) {
return false;
}
RzStrBuf strbuf;
switch (operand->type) {
case RL78_OP_TYPE_IMMEDIATE_8:
case RL78_OP_TYPE_IMMEDIATE_16:
rz_strf(strbuf.buf, "#0x%" PFMT32x, operand->v0);
break;
case RL78_OP_TYPE_SYMBOL:
rz_return_val_if_fail(rl78_symbol_valid(operand->v0), false);
rz_strf(strbuf.buf, "%s", RL78_STRINGS_SYMBOLS[operand->v0]);
break;
case RL78_OP_TYPE_SFR:
case RL78_OP_TYPE_SADDR:
if (rl78_symbol_valid(operand->v0)) {
rz_strf(strbuf.buf, "%s", RL78_STRINGS_SYMBOLS[operand->v0]);
} else {
rz_strf(strbuf.buf, "0x%" PFMT32x, operand->v0);
}
break;
case RL78_OP_TYPE_ABSOLUTE_ADDR_16:
if (rl78_symbol_valid(operand->v0)) {
rz_strf(strbuf.buf, "%s", RL78_STRINGS_SYMBOLS[operand->v0]);
} else {
rz_strf(strbuf.buf, "!0x%" PFMT32x, operand->v0);
}
break;
case RL78_OP_TYPE_DECIMAL:
rz_strf(strbuf.buf, "%d", operand->v0);
break;
case RL78_OP_TYPE_ABSOLUTE_ADDR_20:
if (rl78_symbol_valid(operand->v0)) {
rz_strf(strbuf.buf, "%s", RL78_STRINGS_SYMBOLS[operand->v0]);
} else {
rz_strf(strbuf.buf, "!!0x%" PFMT32x, operand->v0);
}
break;
case RL78_OP_TYPE_RELATIVE_ADDR_8:
rz_strf(strbuf.buf, "$0x%" PFMT32x, operand->v0);
break;
case RL78_OP_TYPE_RELATIVE_ADDR_16:
rz_strf(strbuf.buf, "$!0x%" PFMT32x, operand->v0);
break;
case RL78_OP_TYPE_INDIRECT_ADDR:
if (rl78_symbol_valid(operand->v0)) {
rz_strf(strbuf.buf, "[%s]", RL78_STRINGS_SYMBOLS[operand->v0]);
} else {
rz_strf(strbuf.buf, "[0x%" PFMT32x "]", operand->v0);
}
break;
case RL78_OP_TYPE_BASED_ADDR_8:
rz_return_val_if_fail(rl78_symbol_valid(operand->v0), false);
rz_strf(strbuf.buf, "[%s+0x%" PFMT32x "]",
RL78_STRINGS_SYMBOLS[operand->v0], operand->v1);
break;
case RL78_OP_TYPE_BASED_ADDR_16:
rz_return_val_if_fail(rl78_symbol_valid(operand->v0), false);
rz_strf(strbuf.buf, "0x%" PFMT32x "[%s]",
operand->v1, RL78_STRINGS_SYMBOLS[operand->v0]);
break;
case RL78_OP_TYPE_BASED_INDEX_ADDR:
rz_return_val_if_fail(rl78_symbol_valid(operand->v0) &&
rl78_symbol_valid(operand->v1),
false);
rz_strf(strbuf.buf, "[%s+%s]",
RL78_STRINGS_SYMBOLS[operand->v0],
RL78_STRINGS_SYMBOLS[operand->v1]);
break;
default:
rz_warn_if_reached();
}
// prefix (extension addressing) and suffix (bit index)
const char *prefix = operand->flags & RL78_OP_FLAG_ES ? "es:" : "";
if (operand->flags & RL78_OP_FLAG_BA) {
rz_strf(dst->buf, "%s%s.%d", prefix, strbuf.buf, operand->v1);
} else {
rz_strf(dst->buf, "%s%s", prefix, strbuf.buf);
}
return true;
}
bool rl78_symbol_valid(int symbol) {
return symbol >= 0 && symbol < _RL78_SYMBOL_COUNT;
}
+107
View File
@@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RL78_OP_H
#define RL78_OP_H
#include <rz_util.h>
#include <rz_types.h>
typedef enum RL78Label {
// 8-bit general-purpose registers
RL78_GPR_X,
RL78_GPR_A,
RL78_GPR_C,
RL78_GPR_B,
RL78_GPR_E,
RL78_GPR_D,
RL78_GPR_L,
RL78_GPR_H,
// 16-bit general-purpose registers
RL78_GPR_AX,
RL78_GPR_BC,
RL78_GPR_DE,
RL78_GPR_HL,
// special function registers
RL78_SFR_MEM,
RL78_SFR_PMC, // processor mode control
RL78_SFR_ES, // higher part of address for data access
RL78_SFR_CS, // higher part of address for branching
RL78_SFR_PSW, // program status word
RL78_SFR_SPH,
RL78_SFR_SPL,
// control registers
RL78_CR_PC, // program counter
RL78_CR_PSW, // program status word
RL78_CR_SP, // stack pointer
// register banks
RL78_RB_RB0,
RL78_RB_RB1,
RL78_RB_RB2,
RL78_RB_RB3,
// program status word bits and flags
RL78_PSW_CY, // carry
RL78_PSW_AC, // auxiliary carry
RL78_PSW_Z, // zero
_RL78_SYMBOL_COUNT
} RL78Label;
typedef enum RL78OperandType {
RL78_OP_TYPE_NONE, // used for instructions with less than 2 operands
RL78_OP_TYPE_IMMEDIATE_8, // #byte
RL78_OP_TYPE_IMMEDIATE_16, // #word
// operands of type SFR and SADDR will be parsed into
// RL78_OP_TYPE_SYMBOL if they point to a labeled address
RL78_OP_TYPE_SFR, // special function register
RL78_OP_TYPE_SADDR, // short addressing
RL78_OP_TYPE_SYMBOL, // A, X, BC
RL78_OP_TYPE_DECIMAL, // only used for shifts
RL78_OP_TYPE_ABSOLUTE_ADDR_16, // !...
RL78_OP_TYPE_ABSOLUTE_ADDR_20, // !!...
RL78_OP_TYPE_RELATIVE_ADDR_8, // $...
RL78_OP_TYPE_RELATIVE_ADDR_16, // $!...
RL78_OP_TYPE_INDIRECT_ADDR, // [HL]
RL78_OP_TYPE_BASED_ADDR_8, // [HL+byte]
RL78_OP_TYPE_BASED_ADDR_16, // word[HL]
RL78_OP_TYPE_BASED_INDEX_ADDR, // [HL+C]
_RL78_OP_TYPE_COUNT
} RL78OperandType;
typedef enum RL78OperandFlags {
RL78_OP_FLAG_BA = 1 << 0, // bit addressing (bit index stored in v1)
RL78_OP_FLAG_ES = 1 << 1 // extension addressing
} RL78OperandFlags;
typedef struct RL78Operand {
int v0; // contains label enum if applicable or immediate data
int v1; // contains additional data like the offset for based addressing
int flags;
RL78OperandType type;
} RL78Operand;
/**
* \brief Convert an RL78 operand to a string
* \param dst A caller-supplied character buffer to print into
* \param n Size of dst
* \param operand RL78 operand to be printed
* \return false If operand->type is out of range or equal to RL78_OP_TYPE_NONE
*/
bool rl78_operand_to_string(RzStrBuf RZ_OUT *dst, const RL78Operand RZ_BORROW *operand);
/**
* \brief Check whether a symbol is valid, i.e. is in enum bounds
* \param symbol A symbol
* \return false If symbol is out of range (i.e. < 0 or >= _RL78_SYMBOL_COUNT)
*/
bool rl78_symbol_valid(int symbol);
#endif
+76
View File
@@ -0,0 +1,76 @@
add=byte data addition
addc=addition of byte data with carry
addw=word data addition
addw=addition of stack pointer
and=logical product of byte data
and1=1 bit data logical product
bc=conditional branch with carry flag (cy = 1)
bf=conditional branch by bit test (byte data bit = 0)
bh=conditional branch by numeric value comparison ((z | cy) = 0)
bnc=conditional branch with carry flag (cy = 0)
bnh=conditional branch by numeric value comparison ((z | cy) = 1)
bnz=conditional branch with zero flag (z = 0)
br=unconditional branch
brk=software vectored interrupt
bt=conditional branch by bit test (byte data bit = 1)
btclr=conditional branch and clear by bit test (byte data bit =1)
bz=conditional branch with zero flag (z = 1)
call=subroutine call
callt=subroutine call (refer to the call table)
clrb=byte data clear
clrw=word data clear
clr1=1 bit data clear
cmp=byte data comparison
cmps=byte data comparison
cmpw=word data comparison
cmp0=byte data zero comparison
dec=byte data decrement
decw=word data decrement
di=interrupt disabled
divhu=unsigned division of data
divwu=unsigned division of data
ei=interrupt enabled
halt=halt mode set
inc=byte data increment
incw=word data increment
mach=signed multiplication and accumulation of data
machu=unsigned multiplication and accumulation of data
mov=byte data transfer
movs=byte data transfer and psw change
movw=word data transfer
movw=rp, sp word data transfer with stack pointer
movw=sp, src word data transfer with stack pointer
mov1=1 bit data transfer
mulh=signed multiplication of data
mulhu=unsigned multiplication of data
mulu=unsigned multiplication of data
nop=no operation
not1=1 bit data logical negation
oneb=byte data 01h set
onew=word data 0001h set
or=logical sum of byte data
or1=1 bit data logical sum
pop=pop
push=push
ret=return from subroutine
retb=return from software vectored interrupt
reti=return from hardware vectored interrupt
rol=byte data rotation to the left
rolc=byte data rotation to the left with carry
rolwc=word data rotation to the left with carry
ror=byte data rotation to the right
rorc=byte data rotation to the right with carry
sar=arithmetic shift to the right
sarw=arithmetic shift to the right
sel=rbn register bank selection
set1=1 bit data set
shl=logical shift to the left
shlw=logical shift to the left
shr=logical shift to the right
shrw=logical shift to the right
skc=skip with carry flag (cy = 1)
skh=skip with numeric value comparison ((z | cy) = 0)
sknc=skip with carry flag (cy = 0)
sknh=skip with numeric value comparison ((z | cy) = 1)
sknz=skip with zero flag (z = 0)
skz=skip with zero flag (z = 1)
+6
View File
@@ -35,6 +35,7 @@ asm_plugins_list = [
'ppc_cs',
'propeller',
'pyc',
'rl78',
'rsp',
'sh',
'snes',
@@ -122,6 +123,7 @@ rz_asm_sources = [
'p/asm_ppc_cs.c',
'p/asm_propeller.c',
'p/asm_pyc.c',
'p/asm_rl78.c',
'p/asm_rsp.c',
'p/asm_sh.c',
'p/asm_snes.c',
@@ -214,6 +216,10 @@ rz_asm_sources = [
'arch/pyc/opcode_arg_fmt.c',
'arch/pyc/opcode.c',
'arch/pyc/pyc_dis.c',
'arch/rl78/rl78_instr.c',
'arch/rl78/rl78_maps.c',
'arch/rl78/rl78_operand.c',
'arch/rl78/rl78.c',
'arch/rsp/rsp_idec.c',
'arch/sh/disassembler.c',
'arch/sh/assembler.c',
+54
View File
@@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2023 Bastian Engel <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include "../arch/rl78/rl78.h"
static int assemble(RzAsm *a, RzAsmOp *op, const char *buf) {
return 0x69;
}
static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
RL78Instr instr = { 0 };
size_t bytes_read = 0;
if (!rl78_dis(&instr, &bytes_read, buf, len)) {
rz_strbuf_set(&op->buf_asm, "(invalid)");
return bytes_read;
}
RzStrBuf *instr_strbuf = rz_strbuf_new("");
if (rl78_instr_to_string(instr_strbuf, &instr)) {
rz_strbuf_copy(&op->buf_asm, instr_strbuf);
} else {
rz_strbuf_set(&op->buf_asm, "(invalid)");
}
rz_strbuf_free(instr_strbuf);
op->size = bytes_read;
return bytes_read;
}
RzAsmPlugin rz_asm_plugin_rl78 = {
.name = "rl78",
.arch = "rl78",
.desc = "Renesas RL78 disassembler",
.author = "Bastian Engel",
.license = "LGPL3",
.bits = 32,
.endian = RZ_SYS_ENDIAN_LITTLE | RZ_SYS_ENDIAN_BIG,
.assemble = &assemble,
.disassemble = &disassemble
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ASM,
.data = &rz_asm_plugin_rl78,
.version = RZ_VERSION
};
#endif
+1
View File
@@ -2406,6 +2406,7 @@ extern RzAnalysisPlugin rz_analysis_plugin_ppc_cs;
extern RzAnalysisPlugin rz_analysis_plugin_propeller;
extern RzAnalysisPlugin rz_analysis_plugin_riscv;
extern RzAnalysisPlugin rz_analysis_plugin_riscv_cs;
extern RzAnalysisPlugin rz_analysis_plugin_rl78;
extern RzAnalysisPlugin rz_analysis_plugin_rsp;
extern RzAnalysisPlugin rz_analysis_plugin_sh;
extern RzAnalysisPlugin rz_analysis_plugin_snes;
+1
View File
@@ -258,6 +258,7 @@ extern RzAsmPlugin rz_asm_plugin_ppc_cs;
extern RzAsmPlugin rz_asm_plugin_propeller;
extern RzAsmPlugin rz_asm_plugin_riscv;
extern RzAsmPlugin rz_asm_plugin_riscv_cs;
extern RzAsmPlugin rz_asm_plugin_rl78;
extern RzAsmPlugin rz_asm_plugin_rsp;
extern RzAsmPlugin rz_asm_plugin_sh;
extern RzAsmPlugin rz_asm_plugin_snes;
+205
View File
@@ -0,0 +1,205 @@
NAME=RL78 caesar_nostrip info
FILE=bins/rl78/caesar_nostrip
ARGS=-a rl78
CMDS=<<EOF
pd 4 @ entry0
iI
EOF
EXPECT=<<EOF
;-- entry0:
;-- _start:
0x0000077c movw spl, #0xfedc
0x00000780 mov es, #0x0
0x00000782 movw bc, #0x472
0x00000785 clrw ax
arch N/A
cpu N/A
baddr 0x00000000
binsz 0x00008360
bintype elf
bits 32
class ELF32
compiler Linker: LLD 10.0.0 clang version LLVM for Renesas RL78 10.0.0.202306
dbg_file N/A
endian LE
hdr.csum N/A
guid N/A
intrp N/A
laddr 0x00000000
lang c
machine Renesas RL78 family
minopsz 1
os linux
cc N/A
rpath NONE
subsys linux
stripped false
crypto false
havecode true
va true
sanitiz false
static true
linenum true
lsyms true
canary false
PIE false
RELROCS true
NX true
EOF
RUN
NAME=RL78 caesar_nostrip function bodies
FILE=bins/rl78/caesar_nostrip
ARGS=-a rl78
CMDS=<<EOF
aaa
pdf @ sym._decrypt
pdf @ sym._make_uppercase
pdf @ sym._hash
pdf @ sym._main
EOF
EXPECT=<<EOF
;-- section..text:
;-- segment.LOAD4:
;-- _decrypt:
/ int decrypt(char *decrypted, const char *encrypted, size_t n)
| ; arg char *decrypted @ ...
| ; arg const char *encrypted @ ...
| ; arg size_t n @ ...
| 0x00000552 subw sp, #0x12 ; caesar.c:15 ; int decrypt(char *decrypted, const char *encrypted, size_t n)
| 0x00000554 movw [sp+0x0], ax
| 0x00000556 movw ax, bc
| 0x00000557 movw [sp+0x2], ax
| 0x00000559 movw ax, de
| 0x0000055a movw [sp+0x4], ax
| 0x0000055c clrw ax
| 0x0000055d movw [sp+0x6], ax ; caesar.c:16
\ @-> 0x0000055f br $0x0
;-- _make_uppercase:
/ void make_uppercase(char *buf, size_t n)
| ; arg char *buf @ ...
| ; arg size_t n @ ...
| 0x000005a3 subw sp, #0x18 ; caesar.c:24 ; void make_uppercase(char *buf, size_t n)
| 0x000005a5 movw [sp+0x0], ax
| 0x000005a7 movw ax, bc
| 0x000005a8 movw [sp+0x2], ax
| 0x000005aa clrw ax
| 0x000005ab movw [sp+0x4], ax ; caesar.c:25
\ @-> 0x000005ad br $0x0
; CALL XREFS from sym._main @ +0x8f, +0x9d
;-- _hash:
/ int hash(const char *buf, size_t n)
| ; arg const char *buf @ ...
| ; arg size_t n @ ...
| ; var int sum @ ...
| 0x00000634 subw sp, #0x1e ; caesar.c:33 ; int hash(const char *buf, size_t n)
| 0x00000636 movw [sp+0x4], ax
| 0x00000638 movw ax, bc
| 0x00000639 movw [sp+0x6], ax
| 0x0000063b clrw ax
| 0x0000063c movw [sp+0xc], ax ; caesar.c:34
| 0x0000063e movw [sp+0x8], ax
| 0x00000640 movw ax, [sp+0xc] ; caesar.c:35
| 0x00000642 movw [sp+0xa], ax
\ @-> 0x00000644 br $0x0
; CALL XREF from entry0 @ 0x7f8
;-- _main:
/ int main(int argc, char **argv)
| ; arg int argc @ ...
| ; arg char **argv @ ...
| ; var const struct operations ops @ ...
| ; var size_t len @ ...
| ; var char *decrypted @ ...
| ; var char *uppercase @ ...
| ; var const char *pw @ ...
| ; var size_t pwlen @ ...
| 0x000006b3 subw sp, #0x26 ; caesar.c:43 ; int main(int argc, char **argv)
| 0x000006b5 movw de, #0x0
| 0x000006b8 movw [sp+0x14], ax
| 0x000006ba movw ax, de
| 0x000006bb movw [sp+0x0], ax
| 0x000006bd movw ax, [sp+0x14]
| 0x000006bf movw [sp+0x2], ax
| 0x000006c1 movw ax, bc
| 0x000006c2 movw [sp+0x4], ax
| 0x000006c4 movw ax, !0x3004 ; caesar.c:44
| 0x000006c7 movw [sp+0x8], ax
| 0x000006c9 movw ax, !0x3002
| 0x000006cc movw [sp+0x6], ax
| 0x000006ce movw ax, !0x5700 ; caesar.c:49
| 0x000006d1 call !0x84e ; sym._strlen ; size_t strlen(const char *s)
| 0x000006d4 movw [sp+0xa], ax
| 0x000006d6 movw ax, [sp+0xa] ; caesar.c:50
| 0x000006d8 cmpw ax, #0x41
| ,=< 0x000006db bc $0x8
| @=-> 0x000006dd br $0x0
..
| |`-> 0x000006e3 dec c
| | 0x000006e4 nop
| | 0x000006e5 movw ax, [sp+0xa] ; caesar.c:54
| | 0x000006e7 call !0xb18 ; sym._malloc ; void *malloc(size_t size)
| | 0x000006ea movw [sp+0xc], ax
| | 0x000006ec movw ax, [sp+0x6] ; caesar.c:55
| | 0x000006ee movw [sp+0x16], ax
| | 0x000006f0 movw ax, [sp+0xc]
| | 0x000006f2 movw bc, !0x5700
| | 0x000006f5 movw [sp+0x18], ax
| | 0x000006f7 movw ax, [sp+0xa]
| | 0x000006f9 movw de, ax
| | 0x000006fa movw ax, [sp+0x18]
| | 0x000006fc xchw ax, hl
| | 0x000006fd movw ax, [sp+0x16]
| | 0x000006ff xchw ax, hl
| | 0x00000700 call hl
| | 0x00000702 cmpw ax, #0x0
| |,=< 0x00000705 bnz $0xc
| @==-> 0x00000707 br $0x0
..
| ,=`-> 0x00000711 br $0x64
..
| || @ ; CODE XREF from dbg.main @ 0x711
| || @ ; CODE XREF from sym._main @ +0xb3
\ ``-@-> 0x00000775 br $0x0
EOF
RUN
NAME=RL78 caesar_nostrip function list
FILE=bins/rl78/caesar_nostrip
ARGS=-a rl78
CMDS=<<EOF
aaa
afl
EOF
EXPECT=<<EOF
0x0000077c 60 1024 -> 464 entry0
0x0000093a 8 81 -> 83 sym.___do_fini
0x000008de 2 11 sym.___do_init
0x000013d7 7 90 -> 91 sym._malloc_extend_top
0x00000552 2 15 dbg.decrypt
0x00000b1f 1 7 sym._free
0x00000634 2 18 dbg.hash
0x000006b3 6 196 -> 86 dbg.main
0x000005a3 2 12 dbg.make_uppercase
0x00000b18 1 7 sym._malloc
0x000015fb 1 7 sym._strdup
0x0000084e 2 11 sym._strlen
0x00000e5e 1 20 sym.__malloc_r
0x0000083e 1 8 sym._memcpy
0x000009ab 3 26 sym._exit
0x000009c5 1 24 sym.___call_exitprocs
0x00000b16 8 345 -> 80 sym.__exit
0x00000816 7 39 sym._rl78_run_fini_array
0x0000080b 1 11 sym._rl78_run_init_array
0x00000800 1 11 sym._rl78_run_preinit_array
0x000015e1 3 26 -> 28 sym._sbrk
0x00000b26 1 11 sym.__free_r
0x00000d9e 3 49 sym.__malloc_trim_r
0x000015bd 1 1 sym.___malloc_lock
0x000015be 1 1 sym.___malloc_unlock
0x000015bf 4 34 sym.__sbrk_r
0x00001602 3 44 sym.__strdup_r
0x00000896 1 8 loc.__COM_slrem
0x0000162e 1 13 loc.__rl78_init
0x0000086e 5 25 loc.__COM_lshl
EOF
RUN
+1331
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
File diff suppressed because one or more lines are too long