librz/analysis/mips: resolve PIC calls through $t9 (jalr/jr) to the callee (#6482)
MIPS PIC code calls a function by loading its address from the GOT into
$t9 and then doing `jalr t9` (or `jr t9` for a tail call), e.g.:
lw v0, -sym._MIPS_STUBS(gp) ; v0 = *(gp + %call16(puts))
move t9, v0
jalr t9 ; -> puts
rizin did not turn this into a call to the imported function, so the
target was lost: rz-ghidra rendered it as an indirect `(*_data.XXXX)()`
instead of `puts(...)`, whereas a direct `jal sym.dummy` decompiled fine.
Root cause (two independent gaps):
1. For (R|U)CALL and RJMP ops the core creates the CALL/CODE xref from
op->ptr, not op->jump (see core_analysis_followptr() and the op-type
switch in librz/core/canalysis.c, RZ_ANALYSIS_OP_TYPE_RCALL/RJMP). The
MIPS plugin only ever set op->jump for `jalr`/`jr`, so no call xref was
produced even when $t9 was tracked, and the decompiler never saw a call
target.
2. $t9 was only tracked when it was the *direct* destination of a
gp-relative load (`lw t9, ...(gp)`). The very common sequence that loads
into another register first and then `move t9, vX` was not tracked, so
even op->jump was left unset there (this is the issue's binary). Note
that capstone emits `move t9, vX` as the 2-operand alias of `or` (and on
some toolchains `addu`/`daddu`), i.e. `or t9, vX, $zero`, so the move
must be recognised across MIPS_INS_MOVE *and* the 2-operand OR/ADDU
forms.
Additionally, the tracked value was the GOT *slot* address, while the call
target is the function the slot points to, so the slot has to be
dereferenced.
This commit:
- tracks the destination register and slot of every gp-relative load
(gp_load_reg/gp_load_ptr in MIPSContext), and propagates it to $t9 on a
register move (MIPS_INS_MOVE, or the 2-operand OR/ADDU alias), so the
PIC sequence above is recognised;
- adds mips_pic_call_target(), which dereferences the GOT slot via the
analysis IO bind (honouring word size and endianness) to obtain the
actual callee;
- sets op->ptr (and op->jump) to that resolved address for `jalr t9`
(RCALL) and `jr t9` (RJMP tail call), so the core emits the proper
CALL/CODE xref and the decompiler resolves the callee like it does for
`jal`.
The resolution is best-effort and fully guarded: if gp is unknown, the
slot cannot be read, or it holds 0, op->ptr is left unset and behaviour is
exactly as before. The core additionally validates the target
(is_valid_xref) before creating the xref, so a stale/garbage slot cannot
introduce a bogus call, and the propagation only fires when $t9 is the
destination, so ordinary moves (`move fp, sp`, ...) are unaffected.
Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
This commit is contained in:
parent
c58aa48c3e
commit
1db722606b
3 changed files with 147 additions and 37 deletions
|
|
@ -143,17 +143,47 @@ static int parse_reg_name(RzRegItem *reg, csh handle, cs_insn *insn, int reg_num
|
|||
|
||||
typedef struct {
|
||||
RzRegItem reg;
|
||||
ut64 t9_pre;
|
||||
ut64 t9_pre; ///< address of the GOT slot $t9 points through (UT64_MAX if unknown)
|
||||
int gp_load_reg; ///< register last loaded from a gp-relative address (MIPS_REG_INVALID if none)
|
||||
ut64 gp_load_ptr; ///< the gp-relative slot address loaded into gp_load_reg
|
||||
} MIPSContext;
|
||||
|
||||
static bool mips_init(void **user) {
|
||||
MIPSContext *ctx = RZ_NEW0(MIPSContext);
|
||||
rz_return_val_if_fail(ctx, false);
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
ctx->gp_load_reg = MIPS_REG_INVALID;
|
||||
*user = ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resolve the target of a PIC call/tail-call made through $t9.
|
||||
*
|
||||
* In MIPS PIC code the callee address is loaded from the GOT into $t9 (either
|
||||
* directly via `lw t9, %call16(sym)(gp)` or via `lw vX, ...(gp)` followed by
|
||||
* `move t9, vX`) and then reached with `jalr t9` / `jr t9`. \p got_slot is the
|
||||
* address of that GOT slot (tracked in MIPSContext); dereferencing it yields
|
||||
* the actual function address (the imported symbol / lazy-binding stub).
|
||||
*
|
||||
* \return the resolved target address, or UT64_MAX when it cannot be
|
||||
* determined, in which case the caller leaves the op unresolved as before.
|
||||
*/
|
||||
static ut64 mips_pic_call_target(RzAnalysis *analysis, ut64 got_slot) {
|
||||
if (got_slot == 0 || got_slot == UT64_MAX || !analysis->iob.read_at) {
|
||||
return UT64_MAX;
|
||||
}
|
||||
ut8 buf[8] = { 0 };
|
||||
int wordsize = analysis->bits == 64 ? 8 : 4;
|
||||
if (!analysis->iob.read_at(analysis->iob.io, got_slot, buf, wordsize)) {
|
||||
return UT64_MAX;
|
||||
}
|
||||
ut64 target = wordsize == 8
|
||||
? rz_read_ble64(buf, analysis->big_endian)
|
||||
: (ut64)rz_read_ble32(buf, analysis->big_endian);
|
||||
return target ? target : UT64_MAX;
|
||||
}
|
||||
|
||||
static void op_fillval(RzAnalysis *analysis, RzAnalysisOp *op, csh *handle, cs_insn *insn) {
|
||||
MIPSContext *ctx = (MIPSContext *)analysis->plugin_data;
|
||||
switch (op->type & RZ_ANALYSIS_OP_TYPE_MASK) {
|
||||
|
|
@ -347,11 +377,21 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
case MIPS_OP_MEM:
|
||||
if (IS_REG_GP(OPERAND(1).mem.base)) {
|
||||
op->ptr = analysis->gp + OPERAND(1).mem.disp;
|
||||
// Remember this gp-relative load so a following `move t9, <reg>`
|
||||
// (the standard PIC call setup) can recover the GOT slot.
|
||||
ctx->gp_load_reg = REGID(0);
|
||||
ctx->gp_load_ptr = op->ptr;
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
ctx->t9_pre = op->ptr;
|
||||
}
|
||||
} else if (IS_REG_T9(REGID(0))) {
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
} else {
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
}
|
||||
// A non-gp load into the tracked register invalidates it.
|
||||
if (REGID(0) == ctx->gp_load_reg) {
|
||||
ctx->gp_load_reg = MIPS_REG_INVALID;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIPS_OP_IMM:
|
||||
|
|
@ -395,9 +435,18 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
op->delay = 1;
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_UCALL;
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
op->jump = ctx->t9_pre;
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_RCALL;
|
||||
// Resolve the PIC callee: $t9 holds (a copy of) the GOT slot
|
||||
// address; dereference it so the call points at the imported
|
||||
// function. For (R|U)CALL ops the core builds the CALL xref from
|
||||
// op->ptr, so set that (and op->jump) to the resolved target.
|
||||
ut64 target = mips_pic_call_target(analysis, ctx->t9_pre);
|
||||
if (target != UT64_MAX) {
|
||||
op->ptr = target;
|
||||
op->jump = target;
|
||||
}
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
ctx->gp_load_reg = MIPS_REG_INVALID;
|
||||
}
|
||||
break;
|
||||
#if CS_NEXT_VERSION >= 6
|
||||
|
|
@ -459,6 +508,16 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
break;
|
||||
case MIPS_INS_MOVE:
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
// `move t9, vX` right after `lw vX, %call16(sym)(gp)` is the
|
||||
// canonical PIC call sequence; carry the GOT slot over to $t9 so
|
||||
// the upcoming jalr can be resolved to the imported function.
|
||||
if (ctx->gp_load_reg != MIPS_REG_INVALID && REGID(1) == ctx->gp_load_reg) {
|
||||
ctx->t9_pre = ctx->gp_load_ptr;
|
||||
} else {
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIPS_INS_ADD:
|
||||
case MIPS_INS_ADDI:
|
||||
|
|
@ -471,7 +530,14 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
op->sign = (insn->id == MIPS_INS_ADDI || insn->id == MIPS_INS_ADD || insn->id == MIPS_INS_DADD);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
ctx->t9_pre += IMM(2);
|
||||
if (insn->id == MIPS_INS_ADDU && OPCOUNT() == 2 &&
|
||||
ctx->gp_load_reg != MIPS_REG_INVALID && REGID(1) == ctx->gp_load_reg) {
|
||||
// `move t9, vX` may be emitted as the 2-operand `addu t9, vX`
|
||||
// alias; carry the GOT slot over like MIPS_INS_MOVE does.
|
||||
ctx->t9_pre = ctx->gp_load_ptr;
|
||||
} else {
|
||||
ctx->t9_pre += IMM(2);
|
||||
}
|
||||
}
|
||||
if (IS_REG_SP(REGID(0))) {
|
||||
op->stackop = RZ_ANALYSIS_STACK_INC;
|
||||
|
|
@ -559,6 +625,18 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
case MIPS_INS_ORI:
|
||||
SET_VAL(op, 2);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_OR;
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
if (insn->id == MIPS_INS_OR && OPCOUNT() == 2 &&
|
||||
ctx->gp_load_reg != MIPS_REG_INVALID && REGID(1) == ctx->gp_load_reg) {
|
||||
// capstone emits `move t9, vX` as the 2-operand `or t9, vX`
|
||||
// alias (`or t9, vX, $zero`); carry the GOT slot over so the
|
||||
// following jalr/jr resolves to the imported function.
|
||||
ctx->t9_pre = ctx->gp_load_ptr;
|
||||
} else {
|
||||
// any other write to $t9 invalidates the tracked slot
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MIPS_INS_DIV:
|
||||
case MIPS_INS_DIVU:
|
||||
|
|
@ -816,8 +894,15 @@ static int mips_analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, co
|
|||
ctx->t9_pre = UT64_MAX;
|
||||
}
|
||||
if (IS_REG_T9(REGID(0))) {
|
||||
op->jump = ctx->t9_pre;
|
||||
// PIC tail-call through $t9: resolve it like the jalr case above.
|
||||
// For RJMP the core builds the xref from op->ptr.
|
||||
ut64 target = mips_pic_call_target(analysis, ctx->t9_pre);
|
||||
if (target != UT64_MAX) {
|
||||
op->ptr = target;
|
||||
op->jump = target;
|
||||
}
|
||||
ctx->t9_pre = UT64_MAX;
|
||||
ctx->gp_load_reg = MIPS_REG_INVALID;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ features noreorder pic cpic o32 n32
|
|||
| 0x000804e8 addiu sp, sp, -0x20
|
||||
| 0x000804ec sw zero, (var_4h)
|
||||
| 0x000804f0 lw t9, -sym.do_mips_start(gp) ; [data.00091018:4]=0x8051c sym.do_mips_start
|
||||
| 0x000804f4 jalr t9
|
||||
| 0x000804f4 jalr t9 ; sym.do_mips_start
|
||||
| ; 0x8051c
|
||||
| 0x000804f8 nop
|
||||
| @-> 0x000804fc b 0x804fc
|
||||
\ 0x00080500 nop
|
||||
|
|
@ -50,10 +51,11 @@ features noreorder pic cpic o32 n32
|
|||
| 0x000805b8 move fp, sp
|
||||
| 0x000805bc sw gp, (var_10h)
|
||||
| 0x000805c0 lw v0, -segment.LOAD0(gp) ; [data.0009103c:4]=0x80000 segment.ehdr
|
||||
| 0x000805c4 addiu a0, v0, 0x640 ; 0x80640 ; "Hello World" ; str.Hello_World
|
||||
| 0x000805c4 addiu a0, v0, 0x640 ; 0x80640 ; "Hello World" ; const char *s ; str.Hello_World
|
||||
| 0x000805c8 lw v0, -sym._MIPS_STUBS(gp) ; [data.00091048:4]=0x80600 sym.imp.puts
|
||||
| 0x000805cc move t9, v0
|
||||
| 0x000805d0 jalr t9
|
||||
| 0x000805d0 jalr t9 ; sym.imp.puts
|
||||
| ; 0x80600 ; int puts(const char *s)
|
||||
| 0x000805d4 nop
|
||||
| 0x000805d8 lw gp, (arg_10h)
|
||||
| 0x000805dc move sp, fp
|
||||
|
|
@ -98,7 +100,7 @@ features noreorder cpic o32 n32
|
|||
| 0x004000e2 sw gp, (arg_10h)
|
||||
| 0x004000e6 sw ra, (arg_24h)
|
||||
| 0x004000e8 addiur1sp a1, 0x18
|
||||
| 0x004000ea jalr t9
|
||||
| 0x004000ea jalr t9 ; 0x400221
|
||||
| 0x004000ec addiu a0, zero, 5
|
||||
| 0x004000f0 lw ra, (arg_24h)
|
||||
| 0x004000f2 jraddiusp 0x28
|
||||
|
|
@ -977,7 +979,8 @@ EXPECT=<<EOF
|
|||
| 0x00402598 addiu a1, zero, 0x2f
|
||||
| 0x0040259c lw s6, 0(s0)
|
||||
| 0x004025a0 move s1, a0 ; argc
|
||||
| 0x004025a4 jalr t9
|
||||
| 0x004025a4 jalr t9 ; sym.imp.strrchr
|
||||
| ; 0x41e910 ; char *strrchr(const char *s, int c)
|
||||
| 0x004025a8 move a0, s6
|
||||
| 0x004025ac slti v1, s1, 2
|
||||
| 0x004025b0 addiu a0, v0, 1
|
||||
|
|
@ -990,7 +993,8 @@ EXPECT=<<EOF
|
|||
| :| 0x004025f8 addiu a1, s2, -0x10c0
|
||||
| :| 0x004025fc lw t9, -sym.imp.strcmp(gp) ; [0x435200:4]=0x41eb40 sym.imp.strcmp
|
||||
| :| 0x00402600 move a0, v1
|
||||
| :| 0x00402604 jalr t9
|
||||
| :| 0x00402604 jalr t9 ; sym.imp.strcmp
|
||||
| :| ; 0x41eb40 ; int strcmp(const char *s1, const char *s2)
|
||||
| :| 0x00402608 sw v1, (var_2ch)
|
||||
| :| 0x0040260c lw gp, (var_40h)
|
||||
| :| 0x00402610 lw v1, (var_2ch)
|
||||
|
|
@ -1048,13 +1052,15 @@ EXPECT=<<EOF
|
|||
| --------> 0x00402868 lw t9, -sym.rtnl_open(gp) ; [0x435300:4]=0x41a99c sym.rtnl_open
|
||||
| :||||: 0x0040286c lui s2, 0x43
|
||||
| :||||: 0x00402870 addiu a0, s2, 0x3c60
|
||||
| :||||: 0x00402874 jalr t9
|
||||
| :||||: 0x00402874 jalr t9 ; sym.rtnl_open
|
||||
| :||||: ; 0x41a99c ; "<\U0000001c"
|
||||
| :||||: 0x00402878 move a1, zero
|
||||
| :||||: 0x0040287c lw gp, (var_40h)
|
||||
| :||||:,=< 0x00402880 bltz v0, 0x402aa4
|
||||
| :||||:| 0x00402884 nop
|
||||
| :||||:| 0x00402888 lw t9, -sym.imp.strlen(gp) ; [0x435174:4]=0x41ec10 sym.imp.strlen
|
||||
| :||||:| 0x0040288c jalr t9
|
||||
| :||||:| 0x0040288c jalr t9 ; sym.imp.strlen
|
||||
| :||||:| ; 0x41ec10 ; size_t strlen(const char *s)
|
||||
| :||||:| 0x00402890 move a0, s6
|
||||
| :||||:| 0x00402894 sltiu v0, v0, 3
|
||||
| :||||:| 0x00402898 lw gp, (var_40h)
|
||||
|
|
@ -1101,7 +1107,8 @@ EXPECT=<<EOF
|
|||
| | :|| 0x004029c4 nop
|
||||
..
|
||||
| --------> 0x00402a20 lw t9, -sym.rtnl_close(gp) ; [0x4352c8:4]=0x41a9b8 sym.rtnl_close
|
||||
| | || 0x00402a24 jalr t9
|
||||
| | || 0x00402a24 jalr t9 ; sym.rtnl_close
|
||||
| | || ; 0x41a9b8 ; "<\U0000001c"
|
||||
| | || 0x00402a28 addiu a0, s2, 0x3c60
|
||||
| -`...---> 0x00402a2c jal fcn.004022e4
|
||||
| :::|| 0x00402a30 nop
|
||||
|
|
@ -1109,7 +1116,8 @@ EXPECT=<<EOF
|
|||
| ::: | 0x00402a38 lui a1, 0x42
|
||||
| ::: | 0x00402a3c move a0, a2
|
||||
| ::: | 0x00402a40 sw a2, (var_2ch)
|
||||
| ::: | 0x00402a44 jalr t9
|
||||
| ::: | 0x00402a44 jalr t9 ; sym.matches
|
||||
| ::: | ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: | 0x00402a48 addiu a1, a1, -0x1044
|
||||
| ::: | 0x00402a4c lw gp, (var_40h)
|
||||
| ::: | 0x00402a50 lw a2, (var_2ch)
|
||||
|
|
@ -1123,7 +1131,8 @@ EXPECT=<<EOF
|
|||
| ::: | 0x00402a70 lui a1, 0x42
|
||||
| ::: | 0x00402a74 move a0, a2
|
||||
| ::: | 0x00402a78 sw a2, (var_2ch)
|
||||
| ::: | 0x00402a7c jalr t9
|
||||
| ::: | 0x00402a7c jalr t9 ; sym.matches
|
||||
| ::: | ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: | 0x00402a80 addiu a1, a1, -0x1038
|
||||
| ::: | 0x00402a84 lw gp, (var_40h)
|
||||
| ::: | 0x00402a88 lw a2, (var_2ch)
|
||||
|
|
@ -1134,13 +1143,15 @@ EXPECT=<<EOF
|
|||
| ========< 0x00402a9c b 0x4026f8
|
||||
| :::|| 0x00402aa0 sw v1, 0x5470(v0)
|
||||
| :::|`-> 0x00402aa4 lw t9, -sym.imp.exit(gp) ; [0x4351a4:4]=0x41ebb0 sym.imp.exit
|
||||
| :::| 0x00402aa8 jalr t9
|
||||
| :::| 0x00402aac addiu a0, zero, 1
|
||||
| :::| 0x00402aa8 jalr t9 ; sym.imp.exit
|
||||
| :::| ; 0x41ebb0 ; void exit(int status)
|
||||
..
|
||||
| :::`--> 0x00402ab0 lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| ::: 0x00402ab4 lui a1, 0x42
|
||||
| ::: 0x00402ab8 move a0, a2 ; envp
|
||||
| ::: 0x00402ab8 move a0, a2
|
||||
| ::: 0x00402abc sw a2, (var_2ch)
|
||||
| ::: 0x00402ac0 jalr t9
|
||||
| ::: 0x00402ac0 jalr t9 ; sym.matches
|
||||
| ::: ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: 0x00402ac4 addiu a1, a1, -0x102c
|
||||
| ::: 0x00402ac8 lw gp, (var_40h)
|
||||
| ::: 0x00402acc lw a2, (var_2ch)
|
||||
|
|
@ -1152,9 +1163,10 @@ EXPECT=<<EOF
|
|||
| ::: | 0x00402ae4 sw v1, 0x5474(v0)
|
||||
| ::: `-> 0x00402ae8 lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| ::: 0x00402aec lui a1, 0x42
|
||||
| ::: 0x00402af0 move a0, a2 ; envp
|
||||
| ::: 0x00402af0 move a0, a2
|
||||
| ::: 0x00402af4 sw a2, (var_2ch)
|
||||
| ::: 0x00402af8 jalr t9
|
||||
| ::: 0x00402af8 jalr t9 ; sym.matches
|
||||
| ::: ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: 0x00402afc addiu a1, a1, -0x1020
|
||||
| ::: 0x00402b00 lw gp, (var_40h)
|
||||
| ::: 0x00402b04 lw a2, (var_2ch)
|
||||
|
|
@ -1162,9 +1174,10 @@ EXPECT=<<EOF
|
|||
| ::: | 0x00402b0c lui a0, 0x42
|
||||
| ::: | 0x00402b10 lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| ::: | 0x00402b14 lui a1, 0x42
|
||||
| ::: | 0x00402b18 move a0, a2 ; envp
|
||||
| ::: | 0x00402b18 move a0, a2
|
||||
| ::: | 0x00402b1c sw a2, (var_2ch)
|
||||
| ::: | 0x00402b20 jalr t9
|
||||
| ::: | 0x00402b20 jalr t9 ; sym.matches
|
||||
| ::: | ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: | 0x00402b24 addiu a1, a1, -0xff8
|
||||
| ::: | 0x00402b28 lw gp, (var_40h)
|
||||
| ::: | 0x00402b2c lw a2, (var_2ch)
|
||||
|
|
@ -1177,17 +1190,20 @@ EXPECT=<<EOF
|
|||
| :::|`-> 0x00402b48 lw t9, -sym.imp.printf(gp) ; [0x4353ec:4]=0x41e7b0 sym.imp.printf
|
||||
| :::| 0x00402b4c lui a1, 0x42
|
||||
| :::| 0x00402b50 addiu a0, a0, -0x1014
|
||||
| :::| 0x00402b54 jalr t9
|
||||
| :::| 0x00402b54 jalr t9 ; sym.imp.printf
|
||||
| :::| ; 0x41e7b0 ; int printf(const char *format)
|
||||
| :::| 0x00402b58 addiu a1, a1, -0xf20
|
||||
| :::| 0x00402b5c lw gp, (var_40h)
|
||||
| :::| 0x00402b60 lw t9, -sym.imp.exit(gp) ; [0x4351a4:4]=0x41ebb0 sym.imp.exit
|
||||
| :::| 0x00402b64 jalr t9
|
||||
| :::| 0x00402b64 jalr t9 ; sym.imp.exit
|
||||
| :::| ; 0x41ebb0 ; void exit(int status)
|
||||
| :::| 0x00402b68 move a0, zero
|
||||
| :::`--> 0x00402b6c lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| ::: 0x00402b70 lui a1, 0x42
|
||||
| ::: 0x00402b74 move a0, a2 ; envp
|
||||
| ::: 0x00402b74 move a0, a2
|
||||
| ::: 0x00402b78 sw a2, (var_2ch)
|
||||
| ::: 0x00402b7c jalr t9
|
||||
| ::: 0x00402b7c jalr t9 ; sym.matches
|
||||
| ::: ; 0x41b2b4 ; "<\U0000001c"
|
||||
| ::: 0x00402b80 addiu a1, a1, -0xff0
|
||||
| ::: 0x00402b84 lw gp, (var_40h)
|
||||
| ::: 0x00402b88 lw a2, (var_2ch)
|
||||
|
|
@ -1202,9 +1218,10 @@ EXPECT=<<EOF
|
|||
..
|
||||
| :: `-> 0x00402bb0 lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| :: 0x00402bb4 lui a1, 0x42
|
||||
| :: 0x00402bb8 move a0, a2 ; envp
|
||||
| :: 0x00402bb8 move a0, a2
|
||||
| :: 0x00402bbc sw a2, (var_2ch)
|
||||
| :: 0x00402bc0 jalr t9
|
||||
| :: 0x00402bc0 jalr t9 ; sym.matches
|
||||
| :: ; 0x41b2b4 ; "<\U0000001c"
|
||||
| :: 0x00402bc4 addiu a1, a1, -0xfe8
|
||||
| :: 0x00402bc8 lw gp, (var_40h)
|
||||
| :: 0x00402bcc lw a2, (var_2ch)
|
||||
|
|
@ -1216,7 +1233,8 @@ EXPECT=<<EOF
|
|||
| : | 0x00402be4 addiu a0, sp, 0x18
|
||||
| : | 0x00402be8 lw t9, -sym.get_unsigned(gp) ; [0x435178:4]=0x41bec4 sym.get_unsigned
|
||||
| : | 0x00402bec lw a1, 0(s0)
|
||||
| : | 0x00402bf0 jalr t9
|
||||
| : | 0x00402bf0 jalr t9 ; sym.get_unsigned
|
||||
| : | ; 0x41bec4 ; "<\U0000001c"
|
||||
| : | 0x00402bf4 move a2, zero
|
||||
| : | 0x00402bf8 lw gp, (var_40h)
|
||||
| :,==< 0x00402bfc bnez v0, 0x402c68
|
||||
|
|
@ -1227,9 +1245,10 @@ EXPECT=<<EOF
|
|||
| :|| 0x00402c10 sw v1, 0(v0)
|
||||
| :|`-> 0x00402c14 lw t9, -sym.matches(gp) ; [0x4351ac:4]=0x41b2b4 sym.matches
|
||||
| :| 0x00402c18 lui a1, 0x42
|
||||
| :| 0x00402c1c move a0, a2 ; envp
|
||||
| :| 0x00402c1c move a0, a2
|
||||
| :| 0x00402c20 sw a2, (var_2ch)
|
||||
| :| 0x00402c24 jalr t9
|
||||
| :| 0x00402c24 jalr t9 ; sym.matches
|
||||
| :| ; 0x41b2b4 ; "<\U0000001c"
|
||||
| :| 0x00402c28 addiu a1, a1, -0xfc4
|
||||
| :| 0x00402c2c lw gp, (var_40h)
|
||||
| :| 0x00402c30 lw a2, (var_2ch)
|
||||
|
|
@ -1241,11 +1260,13 @@ EXPECT=<<EOF
|
|||
| | 0x00402c48 addiu a1, a1, -0xfbc
|
||||
| | 0x00402c4c lw a0, 0(v0)
|
||||
| | ; CODE XREF from main @ 0x402c7c
|
||||
| |.-> 0x00402c50 jalr t9
|
||||
| |.-> 0x00402c50 jalr t9 ; sym.imp.fprintf
|
||||
| |: ; 0x41e940 ; int fprintf(FILE *stream, const char *format, void *va_args)
|
||||
| |: 0x00402c54 nop
|
||||
| |: 0x00402c58 lw gp, (var_40h)
|
||||
| |: 0x00402c5c lw t9, -sym.imp.exit(gp) ; [0x4351a4:4]=0x41ebb0 sym.imp.exit
|
||||
| |: 0x00402c60 jalr t9
|
||||
| |: 0x00402c60 jalr t9 ; sym.imp.exit
|
||||
| |: ; 0x41ebb0 ; void exit(int status)
|
||||
| |: 0x00402c64 addiu a0, zero, -1
|
||||
| `--> 0x00402c68 lw v0, -0x7efc(gp) ; [0x4351e4:4]=0
|
||||
| : 0x00402c6c lui a1, 0x42
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ nth vaddr bind type lib name
|
|||
0x0000083c sym.varfunc
|
||||
0x00000850 str.res:__d str.res:__d
|
||||
0x00000854 sym._MIPS_STUBS(gp)
|
||||
0x0000085c sym.imp.printf
|
||||
0x00000940 [14] -r-x section size 48 named .MIPS.stubs
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
@ -61,6 +63,8 @@ nth vaddr bind type lib name
|
|||
0x0000080c sym.varfunc
|
||||
0x00000820 str.res:__d str.res:__d
|
||||
0x00000824 sym._MIPS_STUBS(gp)
|
||||
0x0000082c sym.imp.printf
|
||||
0x00000900 [14] -r-x section size 48 named .MIPS.stubs
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue