Replies: 8 comments
-
I guess this can be fixed in an Analyzer extension, somehow.
One thing I did realize is that I should set IFC_ON=0 in a <context_data>
<tracked_set space="ram">
<set name="IFC_ON" val="0" description="Assume IFC_ON=0 on function entry"/>
</tracked_set>
</context_data> |
Beta Was this translation helpful? Give feedback.
-
The problem with IFCALL -> JAL -> POP25 sequence seems to be that ghidra assumes a CALL pcode op will return to the following (fallthrough) instruction, and doesn't actually track the given language's link pointer register. Furthermore, a given instruction with "CALL" semantics can have only 1 fallthrough address. So, a CALL instruction (JAL in this case) which may return to multiple locations cannot be represented. Or am I missing something? |
Beta Was this translation helpful? Give feedback.
-
Here is another problematic code example, this time, the simple use case of using IFCALL/IFRET within what is clearly the same function body. I've modified my sleigh to emit
void FUN_00000b1c(void)
{
bool bVar1;
int iVar2;
undefined4 *puVar3;
undefined4 *puVar4;
code *UNRECOVERED_JUMPTABLE;
DAT_02093534 = DAT_80000060;
iVar2 = 0x0;
if (PTR_DAT_02090098 == (undefined *)0x0) {
iVar2 = 0x0;
goto LAB_00000b46;
}
puVar4 = &DAT_02090e44;
if (true) {
UNRECOVERED_JUMPTABLE = (code *)0xb40;
}
bVar1 = true;
puVar3 = (undefined4 *)PTR_DAT_02090098;
while( true ) {
puVar4 = (undefined4 *)(iVar2 + (int)puVar4);
iVar2 = iVar2 + 0x4;
*puVar4 = *puVar3;
/* WARNING: Could not recover jumptable at 0x00000b5c. Too many branches */
/* WARNING: Treating indirect jump as call */
if (bVar1) {
(*UNRECOVERED_JUMPTABLE)();
return;
}
if (iVar2 == 0x40) break;
LAB_00000b46:
bVar1 = false;
if (*(undefined4 **)((int)&PTR_DAT_02090018 + iVar2) == (undefined4 *)0x0) {
return;
}
puVar4 = &DAT_02090ca0;
puVar3 = *(undefined4 **)((int)&PTR_DAT_02090018 + iVar2);
}
return;
} This seems to almost "just work", with exception of flow to Manually overriding the fallthrough on the IFCALL to fallthrough to here is the listing with pcode visible
|
Beta Was this translation helpful? Give feedback.
-
I should also mention that I've tried to use a bit in a contextreg for IFC_ON flag, and it does not seem to help/work at all. |
Beta Was this translation helpful? Give feedback.
-
The stack depth tracking issue seems to be "fixed" if I change
which was generating this
to
In any case, the above only improves the stack tracking in the listing. it does not improve the decompilation or function graph. |
Beta Was this translation helpful? Give feedback.
-
Similarly, I've noticed that changing the implementation of IFCALL from:
to
(adding the trailing |
Beta Was this translation helpful? Give feedback.
-
Another oddity:
here, |
Beta Was this translation helpful? Give feedback.
-
I'm going to try and fix this in the decompiler (although I'm unfamiliar with it). When I first started out, using Restoring |
Beta Was this translation helpful? Give feedback.
-
The Andes V3 ISA has "inline function call" extension, which introduces a set of instructions (
IFCALL
,IFCALL9
,IFRET
,IFRET16
) which could be used to execute chunks of code at an arbitrary location (within current function body, or another function). The basic idea is thatIFCALL*
writes return address to a new link register USR (User Special Register)IFC_LP
instead of theLP
GPR, setsIFC_ON
=1 and branches to the target. Then,IFRET*
will return toIFC_LP
ifIFC_ON
==1. IfIFC_ON
==0, theIFRET*
is a nop (fall-through).However, there are some more complications. All branch instructions of the ISA have been updated to be IFC-aware, either clearing
IFC_ON
, or manipulatingIFC_LP
. The details can be seen in gdb: https://github.com/nds32/gdb/blob/master/sim/nds32/interp.cThis leads to code patterns like:
where
24e14
and00024ecc
are reachable via other functions both by otherIFCALL
as well as implicit fall-through flow. This construct allows both code reuse as well as reducing code size (by outlining the 32bitJ
from multiple 16bitIFCALL9
).In the above example, the original return address (in
IFC_LP
) gets moved intoLP
GPR byJ
(noted asji
in gdb sources), so the followingPOP25
will return to24d7e+2
. The same behavior applies toJAL
and other branches executed whileIFC_ON==1
.The above is shown as the following in the decompiler:
whereas it should just be
return 0;
instead of calling a thunk.Please note that this construct is used for all types of code that should be inlined - not just prologue/epilogue sequences.
This kind of flow seems to make the ghidra disassembler/decompiler rather confused. Ideally, I would like any code referenced by
IFCALL*
to be inlined into the function being decompiled. This is somewhat tricky for places where theIFCALL
target is within the function being decompiled - it would seem the decompiler would need to know to duplicate the code in the decompiled representation.Currently, I model
IFCALL
/IFRET
withcall
/return
sleigh semantics, which seemed to work better than just usinggoto
. However, the side effect is that ghidra is now creating functions/subroutines/thunks at allIFCALL
targets. The decompiler can't properly show the code at a anIFCALL
target, as it doesn't know it should show control flow with assumption thatIFC_ON
/IFC_LP
are set upon entry (which would be solved if the target was inlined into theIFCALL
-er).How can I modify my processor extension/ghidra to perform the type of flow control as outlined above, and show sensible decompiler output?
Beta Was this translation helpful? Give feedback.
All reactions