Skip to content

Commit

Permalink
Relocation and analysis improvement for Renesas RX (#4461)
Browse files Browse the repository at this point in the history
* Improve RX analysis of stack pointer
* Add Renesas RX ELF e_flag and reloc type macros
* Add Renesas RX relocation patch and elf_reloc to rz_reloc converter
* Update Renesas RX 'ir-info relocs' cmd test
* Add Renesas RX instruction description sdb
  • Loading branch information
Heersin committed May 1, 2024
1 parent bbbe3c6 commit ba780a7
Show file tree
Hide file tree
Showing 6 changed files with 502 additions and 27 deletions.
2 changes: 2 additions & 0 deletions librz/arch/opcodes/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ sdb_opcodes_files = [
'ppc',
'propeller',
'riscv',
'rx',
'rl78',
'sh',
'sparc',
'sysz',
Expand Down
129 changes: 129 additions & 0 deletions librz/arch/opcodes/rx.sdb.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
abs=absolute value
add=byte data addition without carry
sub=subtract data
adc=addition of byte data with carry
and=logical and
bclr=clear a bit
bnot=inverts a bit
bset=set a bit
btst=test a bit to set C/Z flag
clrpsw=clear a flag in the PSW reg
cmp=compare two operands
div=divide signed
divu=divide unsigned
emul=extended multiply signed
emulu=extended multiply unsigned
fadd=float-point addition
fcmp=compare float-point
fdiv=divide float-point
fmul=multiply float-point
fsub=subtract float-point
ftoi=convert float-point to signed integer
itof=convert signed integer to float-point
machi=multiply-accumulate the upper words
maclo=multiply-accumulate the lower words
max=maximum of two signed integers
min=minimum of two signed integers
mov=move data
mov=move data unsigned
xchg=exchange data
mul=multiply data
mulhi=multiply the upper words
mullo=multiply the lower words
mvfachi=move data from upper longword([b32,b63]) of the accumulator(acc)
mvfacmi=move data from middle longword([b16, b47]) of the accumulator(acc)
mvtachi=move data to upper longword([b32,b63]) of the accumulator(acc)
mvtaclo=move data to lower longword([b0, b31]) of the accumulator(acc)
mvfc=move data from a control register
mvtc=move data to a control register
mvtipl=move data to IPL
neg=negate operand (2's complement)
not=logical not (1's complement)
or=logical or
xor=logical xor
nop=do nothing
pop=pop register from stack
popc=pop a control register from stack
popm=pop multiple registers from stack
push= push a register to stack
pushc=push a control register to stack
pushm=push multiple registers to stack
racw=round the accumulator into a word and stores result
revl=reverse endian within longword
revw=reverse endian within word
rmpa=repeat multiply-accumulate
rolc=rotate left with carry
rorc=rotate right with carry
rotl=rotate left
rotr=rotate right
round=round float-point to signed integer
rte=return from exception
rtfi=return from fast interrupt
rts=return from subroutine
rtsd=return from subroutine after deallocating stack frames
sat=saturate (generate 7FFFFFFFh if flag O and S are set to 1 else generate 80000000)
satr=saturate from rmpa
sbb=subtract with borrow
setpsw=set a flag or bit in PSW
shar=arithmetic shift right
shlr=logical shift right
shll=logical shift left
scmpu=string compare until not equal
smovb=string move backward
smovf=string move forward
smovu=string move until zero detected
sstr=string store
suntil=string search until equal
swhile=string search while equal
stnz=store(move) data on not zero
stz=store(move) on zero
tst=test logical (S = MSB(op1&op2) Z = !(op1&op2))
wait=pause and wait interrupt
int=software interrupt
jmp=unconditional
jsr=jump to a subroutine
bra=unconditional relative branch
brk=unconditional trap
bsr=relative branch to a subroutine
scgeu=store truth value of condition if C == 1 (unsigned <=)
sceq=store truth value of condition if Z == 1 (==)
scgtu=store truth value of condition if (C & ~Z) == 1 (unsigned <)
scpz=store truth value of condition if S == 0 ( >= 0)
scge=store truth value of condition if (S ^ O) == 0 (signed <=)
scgt=store truth value of condition if ((S ^ O) | Z) == 0 (signed <)
sco=store truth value of condition if O == 1 (overflow)
scltu=store truth value of condition if C == 0 (unsigned >)
scne=store truth value of condition if Z == 0 (!=)
scleu=store truth value of condition if (C & ~Z) == 0 (unsigned >=)
scn=store truth value of condition if S == 1 ( < 0 )
scle=store truth value of condition if ((S ^ O) | Z) == 1 (<)
sclt=store truth value of condition if (S ^ O) == 1 (>)
scno=store truth value of condition if O == 0
bgeu=conditional relative branch if C == 1 (unsigned <=)
beq=conditional relative branch if Z == 1 (==)
bgtu=conditional relative branch if (C & ~Z) == 1 (unsigned <)
bpz=conditional relative branch if S == 0 ( >= 0)
bge=conditional relative branch if (S ^ O) == 0 (signed <=)
bgt=conditional relative branch if ((S ^ O) | Z) == 0 (signed <)
bo=conditional relative branch if O == 1 (overflow)
bltu=conditional relative branch if C == 0 (unsigned >)
bne=conditional relative branch if Z == 0 (!=)
bleu=conditional relative branch if (C & ~Z) == 0 (unsigned >=)
bn=conditional relative branch if S == 1 ( < 0 )
ble=conditional relative branch if ((S ^ O) | Z) == 1 (<)
blt=conditional relative branch if (S ^ O) == 1 (>)
bno=conditional relative branch if O == 0
bmgeu=store truth value of condition to a bit if C == 1 (unsigned <=)
bmeq=store truth value of condition to a bit if Z == 1 (==)
bmgtu=store truth value of condition to a bit if (C & ~Z) == 1 (unsigned <)
bmpz=store truth value of condition to a bit if S == 0 ( >= 0)
bmge=store truth value of condition to a bit if (S ^ O) == 0 (signed <=)
bmgt=store truth value of condition to a bit if ((S ^ O) | Z) == 0 (signed <)
bmo=store truth value of condition to a bit if O == 1 (overflow)
bmltu=store truth value of condition to a bit if C == 0 (unsigned >)
bmne=store truth value of condition to a bit if Z == 0 (!=)
bmleu=store truth value of condition to a bit if (C & ~Z) == 0 (unsigned >=)
bmn=store truth value of condition to a bit if S == 1 ( < 0 )
bmle=store truth value of condition to a bit if ((S ^ O) | Z) == 1 (<)
bmlt=store truth value of condition to a bit if (S ^ O) == 1 (>)
bmno=store truth value of condition to a bit if O == 0
173 changes: 152 additions & 21 deletions librz/arch/p/analysis/analysis_rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ static void calculate_jmp_addr(RxInst *inst, RzAnalysisOp *op) {
op->fail = op->addr + op->size;
}

static int rx_operand_cnt(RxInst *inst) {
int cnt = 0;
if (inst->v0.kind != RX_OPERAND_NULL) {
cnt++;
}
if (inst->v1.kind != RX_OPERAND_NULL) {
cnt++;
}
if (inst->v2.kind != RX_OPERAND_NULL) {
cnt++;
}
return cnt;
}

static inline RxOperand *rx_operand_get(RxInst *inst, int idx) {
if (idx >= rx_operand_cnt(inst)) {
RZ_LOG_WARN("Failed to get operand%d of ISA Renesas Rx\n", idx);
rz_warn_if_reached();
return NULL;
}
switch (idx) {
case 0:
return &inst->v0;
case 1:
return &inst->v1;
case 2:
return &inst->v2;
default:
return NULL;
}
}

static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
const ut8 *buf, int len, RzAnalysisOpMask mask) {
op->addr = addr;
Expand All @@ -46,12 +78,16 @@ static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
switch (inst.op) {
// jump related instructions
case RX_OP_RTS:
op->type = RZ_ANALYSIS_OP_TYPE_RET;
op->stackop = RZ_ANALYSIS_STACK_INC;
op->stackptr = 4;
break;
case RX_OP_RTSD:
// use register to deallocate stack frames
op->type = RZ_ANALYSIS_OP_TYPE_RET;
break;
case RX_OP_BSR_A:
case RX_OP_BSR_L:
case RX_OP_BSR_W:
case RX_OP_JSR:
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
calculate_jmp_addr(&inst, op);
break;
Expand All @@ -61,25 +97,84 @@ static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
calculate_jmp_addr(&inst, op);
break;
case RX_OP_BRA_L:
case RX_OP_BRA_A:
case RX_OP_BRA_B:
case RX_OP_BRA_S:
case RX_OP_BRA_W:
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
calculate_jmp_addr(&inst, op);
break;
case RX_OP_BRA_L:
case RX_OP_JMP:
// use register
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
// use register to jump unconditionally
op->type = RZ_ANALYSIS_OP_TYPE_IRJMP;
break;
case RX_OP_BSR_L:
case RX_OP_JSR:
// use register to call unconditionally
op->type = RZ_ANALYSIS_OP_TYPE_IRCALL;
break;

// stack related operations
case RX_OP_PUSH:
case RX_OP_PUSHC:
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
op->stackop = RZ_ANALYSIS_STACK_DEC;
op->stackptr = 4;
break;
case RX_OP_PUSHM:
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
op->stackop = RZ_ANALYSIS_STACK_DEC;
op->stackptr = 4 * (inst.v1.v.reg.reg - inst.v0.v.reg.reg + 1);
break;
case RX_OP_POP:
case RX_OP_POPM:
op->type = RZ_ANALYSIS_OP_TYPE_POP;
op->stackop = RZ_ANALYSIS_STACK_INC;
op->stackptr = 4;
break;
case RX_OP_POPC:
op->type = RZ_ANALYSIS_OP_TYPE_POP;
op->stackop = RZ_ANALYSIS_STACK_INC;
op->stackptr = 4 * (inst.v1.v.reg.reg - inst.v0.v.reg.reg + 1);
break;

// normal instruction
case RX_OP_ADD:
case RX_OP_ADD_UB:
case RX_OP_ADC:
// add imm, rn, rm
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
break;
case RX_OP_ADD:
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
if (rx_operand_cnt(&inst) == 2) {
// add imm, sp
const RxOperand *op0 = rx_operand_get(&inst, 0);
if (op0->kind == RX_OPERAND_IMM) {
const RxOperand *op1 = rx_operand_get(&inst, 1);
if (op1->kind == RX_OPERAND_REG && op1->v.reg.reg == RX_REG_R0) {
// modify SP
op->stackop = RZ_ANALYSIS_STACK_INC;
op->stackptr = op0->v.imm.imm;
}
}
}
break;
case RX_OP_SUB:
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
if (rx_operand_cnt(&inst) == 2) {
// sub imm, sp
const RxOperand *op0 = rx_operand_get(&inst, 0);
if (op0->kind == RX_OPERAND_IMM) {
const RxOperand *op1 = rx_operand_get(&inst, 1);
if (op1->kind == RX_OPERAND_REG && op1->v.reg.reg == RX_REG_R0) {
// modify SP
op->stackop = RZ_ANALYSIS_STACK_DEC;
op->stackptr = op0->v.imm.imm;
}
}
}
break;
case RX_OP_SUB_UB:
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
break;
Expand Down Expand Up @@ -115,20 +210,13 @@ static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
case RX_OP_NOP:
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
break;
case RX_OP_NEG:
op->type = RZ_ANALYSIS_OP_TYPE_CPL;
break;
case RX_OP_CMP:
case RX_OP_CMP_UB:
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
break;
case RX_OP_PUSH:
case RX_OP_PUSHM:
case RX_OP_PUSHC:
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
break;
case RX_OP_POP:
case RX_OP_POPM:
case RX_OP_POPC:
op->type = RZ_ANALYSIS_OP_TYPE_POP;
break;
case RX_OP_ROTL:
case RX_OP_ROLC:
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
Expand All @@ -154,15 +242,26 @@ static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
case RX_OP_XOR_UB:
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
break;
case RX_OP_ITOF:
case RX_OP_FTOI:
case RX_OP_ITOF_UB:
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
break;
case RX_OP_INT:
case RX_OP_RTE:
case RX_OP_RTFI:
op->type = RZ_ANALYSIS_OP_TYPE_SWI;
break;
case RX_OP_MOV:
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
if (rx_operand_cnt(&inst) == 2) {
// mov sp, rn
const RxOperand *op0 = rx_operand_get(&inst, 0);
const RxOperand *op1 = rx_operand_get(&inst, 1);
if (op0->kind == RX_OPERAND_IMM) {
if (op1->kind == RX_OPERAND_REG && op1->v.reg.reg == RX_REG_R0) {
// modify SP
op->stackop = RZ_ANALYSIS_STACK_SET;
op->stackptr = op0->v.imm.imm;
}
}
}
break;
case RX_OP_MOVU:
case RX_OP_MVTIPL:
case RX_OP_MVTC:
Expand All @@ -173,7 +272,39 @@ static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
case RX_OP_MVFC:
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
break;
case RX_OP_ABS:
op->type = RZ_ANALYSIS_OP_TYPE_ABS;
break;

// FPU
case RX_OP_FADD:
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
case RX_OP_FSUB:
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
case RX_OP_FMUL:
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
case RX_OP_FDIV:
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
case RX_OP_FCMP:
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
case RX_OP_ITOF:
case RX_OP_FTOI:
case RX_OP_ITOF_UB:
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
op->family = RZ_ANALYSIS_OP_FAMILY_FPU;
break;
default:
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
break;
}

Expand Down
Loading

0 comments on commit ba780a7

Please sign in to comment.