[Windows Mobile Development and Hacking General] sztupy:
This is normal. -l2 crashes less, but for large scripts I recommend fixing the places where -l crashes (if possible), because so the output will be more useful

In case you're interested -l crashes more often because it links the numbers to actual registers (so you can specify which register to declare as local), but if you specify it wrong the decompiler won't like it, and read a lot of useless information from the memory it shouldn't access.

LDS2 instead doesn't rely on register numbers, it will simply use the next avaialable register slot to declare the local. The good part is that this way it will cash less. The bad part of this that you won't know from the sources which register the local is referring to. In LDS1 you always knew that l_5_0 was R0, l_5_1 was R1, etc., but using LDS2 you only know, that l_5_0 is the first local, l_5_1 is the second, but in a case like "-l2 10-20,30-40" both the first and the second local will be assigned to R0 (because between 10-20 R0 is the first register that is free, between 20-30 there are no locals declared and between 30-40 the first free register is R0 again).

If you don't mind the latter problem (which is not really a problem, but it will make decompiling a bit harder (but if you were used to that the function numbers are not the same, that the disasembler can't' print out numbers correctly you won't find this a problem after all :) ). If you removed the "empty 0"-s from the LDS strings, then they both should output the same code.

Check the top if this code. It shows a CLOSURE at opcode line 98, so somewhere at opcode line 98 in some of the functions (usually this will be the main body, which can consiedered to be also a "function") there is a function defined. You have to search through the disassembly to get which function this is. So if you find something in the disassembly that reads

[98] R0:=function(#10)

Then you know this will be the 11th function (10+1).

Now, it crashed at opcode line 6. But when looking at the output (either of the debug screen, or the disassembly of the 11th function) you'll see that on opcode line 5 there is an assignemnt to R0. In your LDS:

-l ;;0,11,32;;0,17,38;;;;;;;5

And looking at the disassembly again you'll see that R0 was assigned to a value at line [1], so change to:

-l ;;0,11,32;;0,17,38;;;;;;;1

or

-l2 ;;11,32;;17,38;;;;;;;1

luadecguess -fg tryes to determine from the last line of the disasembly how many locals there are. Usually (in most of the cases) the last register used in a program refers to a register that is the first non-local register. So if the last line (actually the 2nd from the end, because the last line is always an empty RETURN) of your code reads for example

return R5

And you have two parameters (R0, R1), then luadecguess -fg will think R2,R3 and R4 are locals, and R5 is not. This alos means that luadecguess -fg doesn't like functions with the following structure:

local l0 = "" -- or local l0 = nil or similar
if something then
l0 = "something else"
end
(...)
return l0

because here the last line will read "RETURN R0", so it will think R0 is not a local, and it won't declare it as so. Usually luadec won't crash this way, but it will output a lot of garbage, and the code as a whole won't be really usable.

Now let's look at another code:

local l0 = "" -- or local l0 = nil or similar
if something then
l0 = "something else"
end
(...)
return false

in this case the last line will read:

R1 := false
RETURN R1

So it will think R1 is not a local, but R0 is. And we've got the crash, because the last assignment is

l0 = "something else"

but we have to declare the local at the beginning of the script.

This is the same error as the one in my previous example. In large scripts (with 40+ functions) there are usually 3-4 functions with this kind of structure. In both of this two kind you usually have to check the place of the locals and fix them accordingly. Lot of these things are very easy to spot. If any line of the disassemlby reads LOADK R0:= "" then it usually means it will create an empty string. Empty strings doesn't just hang around the code, so they are usually locals. The other one is LOADNIL (R0:=nil). If you find a LOADNIL statement somewhere then it usually means there is a local defined there (*). If you find a mass nil assignmnet (R0 := R1 := R2 := nil), then you can be sure that on that line R0, R1 and R2 are declared as locals (all three of them at the same line). Lines like:

R0 := nil
R1 := 0
R2 := 0

Usually mean local assignemnts too:

local l0 = nil
local l1 = 0
local l2 = 0

(*): of course if the first line is LOADNIL, then it will be optimized away. But you can easily guess that there is a local assignment. In a case like

function(l_1_0,l_1_1)
local l_1_2 = nil
if something then
end
end

will translate to:

[1] R3 := something
[2] if not R3 then ...

As you see R3 is the first assignemnt, but there are only two parameters (R0,R1)... so it means R2 must be a local, that has been nil-ed at the beginning.