yath / ghidra-xtensa

Tensilica Xtensa processor module for Ghidra
MIT License
102 stars 34 forks source link

entry instruction not supported #3

Open pixel-stuck opened 4 years ago

pixel-stuck commented 4 years ago

per title. It seems the entry instruction isn't supported (which seems like a really common instruction, at least in the esp32 binary I'm working on right now), which is making any decompilation impossible.

If you need a binary let me know, I can provide one.

Ebiroll commented 4 years ago

I have been experimenting with a simple entry implementation to allow the decompiler to run on esp32 binaries. Some help would be useful. Where can I learn more? Can you fix this naive implementation? I guess all register should be shifted. and maybe one could add more ar registers to allow entry a1,12

I guess as is normally a1 (sp)

:entry as, u15_12.23_sb3 is u15_12.23_sb3 & as & u2_6.7 = 0b00 & u2_4.5 = 0b11 & op0 = 0b0110 { if (u15_12.23_sb3 ==4) goto <shift4>; if (u15_12.23_sb3 ==8) goto <shift8>; if (u15_12.23_sb3 ==12) goto <shift12>; <shift4> a2=a6; a3=a7; a4=a8; a5=a9; a6=a10; a7=a11; a8=a12; a9=a13; a10=a14; a11=a15; goto ; <shift8> a2=a10; a3=a11; a4=a12; a5=a13; a6=a14; a7=a15; goto ; <shift12> a2=a14; a3=a15; <end> } Thanks in advance.

In case that the register window overflows, this interrupt is called. but that is probably not important for decompiling the code. a5 contains call[j+1]’s stack pointer and registers are saved to call[j+1]’s stack frame

_WindowOverflow4:

  | s32e a0, a5, -16   | s32e a1, a5, -12   | s32e a2, a5, -8   | s32e a3, a5, -4   | rfwo

Ebiroll commented 4 years ago

A simple naive implementation would be more useful than the currrent unimplemented one. Here is some info for those who have not read the specifcations.

The Xtensa windowed register calling convention

Is designed to efficiently pass arguments and return values in AR registers

The register windows for the caller and the callee are not the same, but they partially overlap. As many as six words of arguments can be passed from the caller to the callee in these overlapping registers, and as many as four words of a return value can be returned in the same registers. If all the arguments do not fit in registers, the rest are passed on the stack. Similarly, if the return value needs more than four words, the value is returned on the stack instead of the AR registers.

The Windowed Register Option replaces the simple 16-entry AR register file with a larger register file from which a window of 16 entries is visible at any given time. The window is rotated on subroutine entry and exit, automatically saving and restoring some registers. When the window is rotated far enough to require registers to be saved to or re- stored from the program stack, an exception is raised to move some of the register values between the register file and the program stack. The option reduces code size and increases performance of programs by eliminating register saves and restores at procedure entry and exit, and by reducing argument-shuffling at calls. It allows more local variables to live permanently in registers, reducing the need for stack-frame maintenance in non-leaf routines. Xtensa ISA register windows are different from register windows in other instruction sets. Xtensa register increments are 4, 8, and 12 on a per-call basis, not a fixed incre- ment as in other instruction sets. Also, Xtensa processors have no global address registers. The caller specifies the increment amount, while the callee performs the actual in- crement by the ENTRY instruction.

Example

The registers that the caller uses for arguments and return values are determined by the size of the register window. The window size must be added to the register numbers seen by the callee. For example, if the caller uses a CALL8 instruction, the window size is 8.

x = proc1 (1, 2, 3) translates to: movi.n a10, 1 movi.n a11, 2 movi.n a12, 3 call8 proc1 s32i a10, sp, x_offset

http://wiki.linux-xtensa.org/index.php/ABI_Interface

Ebiroll commented 4 years ago

My idea worked. https://github.com/Ebiroll/ghidra-xtensa However it is not 100% correct, but good enough to get decompilation.

mcguidarelli commented 4 years ago

Is this being looked into? Are register windows supported for the Sparc descriptor in Ghidra, and useful for reference?

Ebiroll commented 4 years ago

The main problem, as they have noted is: When the window is overflowed the data must be stored on the stack When the window is underflowed the data must be read from the stack. It seems they have solved this with the macro save() and restore() that saves the registers in "fake" registers. The main problem with my implementation, regarding decompilation, is that a2-a7 is "destroyed" after return of the call. Implementing a save() and restore() macro as well as adding more registers to the tag in the call spec, (cspec) would probably be enough.

Ebiroll commented 4 years ago

Some input by the experts would be useful. I wrote an article on how well my changes actually performs, in case someone is interested. https://medium.com/@olof.astrand/enter-home-dragon-with-ghidra-3ed7ddf75935