Re: Error In Compilation : Invalid register: v16. Must be between v0 and v15, inclusive.

Skip to first unread message

Ryszard Wiśniewski

Oct 11, 2016, 4:22:39 AM10/11/16


Two things are happening there.

First, most dalvik opcodes can only use first 16 registers. You need to move the data to lower registers before using it.

Second, distinction between local registers and parameter registers (vX and pX) is virtual. In reality there is only one set of registers and locals are first, then parameters. If using ".locals 16" p0 register is the same as v16 and this is why it doesn't work in your example. This is also why exactly the same code works in one method and it doesn't in another - it depends on the number of locals.

Ryszard Wiśniewski

On Oct 11, 2016 6:21 AM, "AS L" <> wrote:
HI All , 

I encountered the following errors when i add in some codes to invoke a method. I have also inserted the same codes into other files which did not  have errors. 

I have search the codes , there are no register bigger than v15 being used. 


decompile\smali\org\w.smali[5583,0] Invalid register: v16. Must be between v0 and v15, inclusive.
decompile\smali\org\w.smali[5607,0] Invalid register: v16. Must be between v0 and v15, inclusive.
decompile\smali\org\w.smali[5619,0] Invalid register: v16. Must be between v0 and v15, inclusive.

.locals 16

    const-string v1, "SqEsqxMcaxL"

invoke-virtual {p0, v1}, Lorg/blhelper/vrtwidget/i;->decrypt(Ljava/lang/String;)Ljava/lang/String;

move-result-object v1

    const/4 v2, 0x1

    invoke-static {v2}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;

    move-result-object v2

You received this message because you are subscribed to the Google Groups "apktool" group.
To unsubscribe from this group and stop receiving emails from it, send an email to
For more options, visit


Oct 11, 2016, 7:10:02 AM10/11/16
to apktool
Hi Ryszard,

Thank you for your reply.

Meaning I should expand. local to 17 if that happens?

Ryszard Wiśniewski

Oct 11, 2016, 1:37:42 PM10/11/16

Well, no ;-)

Lets say there is a static method with ".locals 6" and 4 parameters. In total it has 10 registers named v0-v9. v0-v5 are "local" registers and v6-v9 are "parameter" registers, but there is really no difference between them. In addition in smali parameter registers have aliases for user convenience, so p0=v6, p1=v7 and so on. 

As said earlier most dalvik instructions can only use registers v0-v15. Usually it is not a problem, in my above example there are only 10 registers, so everything is fine. In your example there are 16 local registers (v0-v15), p0 is v16, so it is out of the range and can't be accessed directly. If we change locals number to ".locals 17" then the only difference would be that p0 would become v17 and it would be still out of the range.

To access values of registers above v15 we need to move them to lower registers. Move, as you can see here: , is almost only instruction that can access more than 16 registers. Instead of your:

invoke-virtual {p0, v1}, Lorg/blhelper/vrtwidget/i;->decrypt(Ljava/lang/String;)Ljava/lang/String;

We need to do something like:

move v0, p0
invoke-virtual {v0, v1}, Lorg/blhelper/vrtwidget/i;->decrypt(Ljava/lang/String;)Ljava/lang/String;

Unfortunately this way we overwrite v0, so we lose its value if it is needed later. There is no easy and straightforward solution to this problem. You can try to find some register that isn't read after your instruction, so you can overwrite it safely. You can also backup&restore lower registers to upper registers. In your example we have ".locals 16", so we can be sure existing smali code uses registers v0-v15 only (and some parameters). If we increase locals to ".locals 16" then code will still use v0-v15 and parameters will become v17+. v16 is free and we can do whatever we want with it. Now we can write above example properly:

move v16, v0
move v0, p0
invoke-virtual {v0, v1}, Lorg/blhelper/vrtwidget/i;->decrypt(Ljava/lang/String;)Ljava/lang/String;
move v0, v16

First we backup existing value of v0 to our free v16, we load p0 to v0, use it and then restore original value of v0. If you look into disassembled smali code of some bigger methods with a lot of registers then you will find a lot of such backup&restore instructions generated by the compiler itself.

Unfortunately above solution also has its drawbacks. Lets say we have a method with ".locals 12" and with 6 params. In this example p3 is v15, so compiler generates code that accesses it directly. If you increase locals to ".locals 13" p3 will become v16 and now it can't be accessed directly anymore. Still existing code tries to use it directly, so it won't assemble. As I said, it is not straightforward, you need to understand what are you doing.

Ryszard Wiśniewski

Reply all
Reply to author
0 new messages