Open brightprogrammer opened 1 year ago
@XVilka @wargio @thestr4ng3r please give your suggestions.
For me the issue is that we cannot know the machine status when we create the IL code, thus we cannot use SET functions. Since tho we can write on memory, we could skip the SET and instead just add a type on the profile side and have the profile be synchronized each time a certain memory location is written or at each cycle
Could you explain what is the problem in having these instructions converted in a series of if
at the IL level? Is it always possible to determine the selected bank or is it an intractable problem in general?
Consider this layout. There are 4 banks. Let's consider the time of uplifting phase. Each instruction uses a value between 0x00-0x7F to index a register into a selected bank. Banks are selected using two bits in the STATUS
register. When a function wants to deduce the exact address of register provided in current instruction it'll need both bank and this index. We already get the register index into selected bank in direct addressing mode because it's hardcoded into the instruction but we still don't have the selected bank.
The problem here is that we are not able to get the selected bank during the uplifting phase because it may change any time using any instruction at runtime and only the VM has knowledge of current selected bank. Similarly we cannot get both the selected register and selected bank in indirect addressing mode.
If we convert this problem into a series of IF statements to deduce the register, it still won't be possible (in my opinion) because there are some registers that aren't implemented in some devices and always read to a constant value "0". Also note that at the moment, RzIL uses strings to refer to registers and not numbers.
We can use LOAD/STORE
operations to directly read/write to these register addresses treating them as memory but then again there are registers with special meanings. For example, some bits in STATUS
register cannot be altered directly using any instruction. INDF
(at the top) is not ha physical register. Reserved & Unimplemented registers are always 0, like the zero register in MIPS/RISCV. Due to these things we need a way to exactly determine the registers during the uplifting phase itself which is not "completely" possible at the moment.
@ret2libc essentially the instruction choose which register to access based on the bits set in the status register (bank_n*offset = register). Essentially we would need to access to the current status register at runtime to choose which register to emit in the IL translation.
yes, exactly that is the issue
@ret2libc essentially the instruction choose which register to access based on the bits set in the status register (bank_n*offset = register).
Essentially we would need to access to the current status register at runtime to choose which register to emit in the IL translation.
Yes that's what I understood and I think it is not a problem. We could emit all possible instructions with a series of if. In theory subsequent rzil passes could optimize the flow later IF the status register can be determined statically. And I think that's the main problem.. is there any reason why an instruction should always behave the same across the whole program execution? For example, you could have a function that sometimes access register x and other times register y, but if you convert that to always accessing register x in rzil you change the meaning of the program.
Hope it's clear what I mean.
Yes the problem here is that we cannot determine value in registers like STATUS, FSR, etc... statically.
We can use IF statements and use LOAD/STORE operations (like used for memory) instead of SETG/SETL by peforming the register address calculation in the IL itself.
The problem I find in this solution is that we won't be able to decide (easily) if it's STATUS register or some other register that shouldn't be modified arbitrarily. This would mean checking for these register indices in all instructions and when bank changes, addresses of some of these registers also change meaning we will need to generate IL checks for all available banks in all instructions.
Btw, I didn't get your last part on function using x and y.
Note that STATUS register itself is present in this register array, meaning it is also indexed like other registers. Only difference is that it's mirrored across all data memory banks and it's index remains same in all devices.
The problem I find in this solution is that we won't be able to decide (easily) if it's STATUS register or some other register that shouldn't be modified arbitrarily.
What would happen in the native code? I think the il should mirror that. But since we cannot determine things statically, I think the only solution is to implement everything "at runtime" in the il , even if that means making the translation quite complicated.
it kinda feels silly, tbh.
it kinda feels silly, tbh.
What is the alternative? AFAIK keeping track statically of the registers is not possible in the general case.
not really, just add a new type to the profile mmio TMR0 .8 38 0 0x1234
Background
When uplifting architectures with banked memory we must know which memory bank is being accessed in order to properly uplfit the code. This is not possible while uplifting because only the RzIL VM knows which bank is being used at the moment.
Points to consider
Problem Statement How to deduce active bank during the uplifting phase and use that in combination with register index provided in the instructions to get the actual effective address of target register. Example : For PIC16FXXX devices, let's consider the following assembly
If we get this assembly then we can get the selected bank during uplifting phase only when we check whether the arguments of instructions are status registers or not. Although this is a hacky solution, even if we consider this to be true, it'll bloat the uplifted code with lots of useless checks and still won't be complete solution because of indirect addressing modes.
Proposed Solution: According to @wargio :
SETG
/SETL
here.Some other points that I haven't understood/mentioned properly can be explained by him instead :smile:
Alternative Experimental Solution Since the problem is related to memory banking only, we should develop banking support into the VM itself. This would mean creating register profiles for different devices, use to to create intial VM config and in the register profile we specify which register belongs to which bank, whether they are volatile or are const (fixed value). Then during uplifting, we uplift the instructions as usual and all bank selection operations can be automatically done by the VM. To generalize this for other similar architectures, we add a feature the allows to register a function with VM that can handle this bank selection process and compute the effective register addresses. This would mean allow use of numbers to refer to registers along with strings.
Additional context Problem encountered in task : RzIL PIC Uplifting