rizin/test/db/analysis/luac
2026-04-05 08:12:55 +08:00

1203 lines
78 KiB
Text

NAME=LUAC: function boundary
FILE=bins/luac/big.luac
CMDS=<<EOF
e scr.utf8=false
aa
pdf~?
s 0x1c
pd 7
EOF
EXPECT=<<EOF
364
| ,==< 0x0000001c lti r0 50 0 ; @learnlua.lua:25
| ,===< 0x00000020 jmp 5 ; jump to 0x38
| |`--> 0x00000024 gettabup r0 0 0 ; @learnlua.lua:26 ; 0x820 ; r0 = _ENV['num']
| | : 0x00000028 addi r0 r0 1 ; r0 := r0 + (sC=1)
| | : 0x0000002c mmbini r0 1 6 ; add
| | : ; 0x15018 ; call metamethod __add(r0, 1)
| | : 0x00000030 settabup 0 0 r0 ; 0x820 ; _ENV['num'] = r0
| | `=< 0x00000034 jmp -8 ; jump to 0x18
EOF
RUN
NAME=LUAC_5.4: functions check
FILE=bins/luac/class54.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
is
pd 23 @ 0x0
pd 9 @ 0x1000
pd 5 @ 0x2000
EOF
EXPECT=<<EOF
nth paddr vaddr bind type size lib name
------------------------------------------------------
0 0x00000031 0x00000000 GLOBAL FUNC 92 entry0
0 0x000000cc 0x00001000 GLOBAL FUNC 36 proto1
0 0x00000147 0x00002000 GLOBAL FUNC 20 proto2
0 0x00000031 0x00000000 GLOBAL FUNC 92 entry0
;-- section.fcn.00000000.code:
/ entry0();
| 0x00000000 51000000 varargprep 0 ; @class.lua:1 ; prepare varargs, 0 fixed args
| 0x00000004 13000000 newtable r0 0 0 ; r0 = {}; array: 0, hash: 0
| 0x00000008 52000000 extraarg 0 ; extension for previous opcode
| 0x0000000c 0f000000 settabup 0 0 r0 ; 0x820 ; 0 ; _ENV['Account'] = r0
| 0x00000010 0b000000 gettabup r0 0 0 ; @class.lua:2 ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000014 8b000000 gettabup r1 0 0 ; 0x820 ; 0 ; r1 = _ENV['Account']
| 0x00000018 12000101 setfield r0 1 r1 ; table r0['__index'] = r1
| 0x0000001c 0b000000 gettabup r0 0 0 ; @class.lua:4 ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000020 cf000000 closure r1 0 ; @class.lua:9 ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000024 12000201 setfield r0 2 r1 ; @class.lua:4 ; table r0['create'] = r1
| 0x00000028 0b000003 gettabup r0 0 3 ; @class.lua:11 ; 0x880 ; 0 ; r0 = _ENV['Account']
| 0x0000002c cf800000 closure r1 1 ; @class.lua:13 ; sym.proto2
| ; 0x2000 ; instantiate proto 2 `proto2` at 0x2000
| 0x00000030 12000401 setfield r0 4 r1 ; @class.lua:11 ; table r0['withdraw'] = r1
| 0x00000034 0b000003 gettabup r0 0 3 ; @class.lua:16 ; 0x880 ; 0 ; r0 = _ENV['Account']
| 0x00000038 14800002 self r0 r0 section.fcn.00000000.const ; r1=r0 (self), r0=r0[2] self.create()
| 0x0000003c 0181f381 loadi r2 1000 ; r2 = 1000
| 0x00000040 44000302 call r0 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00000044 0f000500 settabup 0 5 r0 ; 0x8c0 ; 0 ; _ENV['acc'] = r0
| 0x00000048 0b000005 gettabup r0 0 5 ; @class.lua:17 ; 0x8c0 ; 0 ; r0 = _ENV['acc']
| 0x0000004c 14800004 self r0 r0 proto1 ; r1=r0 (self), r0=r0[4] self.withdraw()
| 0x00000050 01813180 loadi r2 100 ; r2 = 100
| 0x00000054 44000301 call r0 3 1 ; sym.proto1
| ; 0x1000 ; proto1 ; 2 in 0 out
| 0x00000058 46000101 return r0 1 1 ; 0 out
; CALL XREF from entry0 @ 0x54
; CALL XREF from proto1 @ 0x1014
;-- section.fcn.00001000.code:
/ proto1(int self, int balance);
| ; arg int self @ r2
| ; arg int balance @ r3
| ; var int acnt @ r4
| 0x00001000 13010000 newtable r2 0 0 ; r2 = {}; array: 0, hash: 0
| 0x00001004 52000000 extraarg 0 ; extension for previous opcode
| 0x00001008 8b010000 gettabup r3 0 0 ; 0x1820 ; r3 = _ENV['setmetatable']
| 0x0000100c 00020200 move r4 r2 ; r4 = r2
| 0x00001010 8b020001 gettabup r5 0 1 ; 0x1840 ; r5 = _ENV['Account']
| 0x00001014 c4010301 call r3 3 1 ; sym.proto1
| ; 0x1000 ; 2 in 0 out
| 0x00001018 12010201 setfield r2 2 r1 ; table r2['balance'] = r1
| 0x0000101c 48010200 return1 r2 ; return r2
| 0x00001020 c7010100 return0 ; empty return
; CALL XREF from entry0 @ 0x40
;-- section.fcn.00002000.code:
/ proto2(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| 0x00002000 0e010000 getfield r2 r0 0 ; r2 = r0['balance']
| 0x00002004 23010201 sub r2 r2 r1 ; r2 = r2 - r1
| 0x00002008 2e010107 mmbin r2 r1 7 ; sub
| ; 0x1501c ; call metamethod __sub(r2, r1)
| 0x0000200c 12000002 setfield r0 0 r2 ; table r0['balance'] = r2
| 0x00002010 47010100 return0 ; empty return
EOF
RUN
NAME=LUAC: plugin 5.0 vars and functions analysis
FILE=bins/luac/class50.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
pd 42 @ 0x0
pd 16 @ 0x1000
pd 8 @ 0x2000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| 0x00000000 0a000000 newtable r0 0 0 ; [07] -r-x section size 168 named fcn.00000000.code
| 0x00000004 00000000 move r0 r0 ; r0 = r0
| 0x00000008 07000000 setglobal r0 0
| 0x0000000c 00000000 move r0 r0 ; r0 = r0
| 0x00000010 05000000 getglobal r0 0 ; r0 = Gbl[Account]
| 0x00000014 00000000 move r0 r0 ; r0 = r0
| 0x00000018 05000001 getglobal r1 0 ; r1 = Gbl[Account]
| 0x0000001c 00000000 move r0 r0 ; r0 = r0
| 0x00000020 49807d00 settable 0 251 1 ; r0[r251] = r1
| 0x00000024 00000000 move r0 r0 ; r0 = r0
| 0x00000028 05000000 getglobal r0 0 ; r0 = Gbl[Account]
| 0x0000002c 00000000 move r0 r0 ; r0 = r0
| 0x00000030 22000001 closure r1 0 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000034 00000000 move r0 r0 ; r0 = r0
| 0x00000038 49007e00 settable 0 252 1 ; r0[r252] = r1
| 0x0000003c 00000000 move r0 r0 ; r0 = r0
| 0x00000040 05000000 getglobal r0 0 ; r0 = Gbl[Account]
| 0x00000044 00000000 move r0 r0 ; r0 = r0
| 0x00000048 62000001 closure r1 1 ; instantiate proto 2 `proto2` at 0x2000
| 0x0000004c 00000000 move r0 r0 ; r0 = r0
| 0x00000050 49807e00 settable 0 253 1 ; r0[r253] = r1
| 0x00000054 00000000 move r0 r0 ; r0 = r0
| 0x00000058 05000000 getglobal r0 0 ; r0 = Gbl[Account]
| 0x0000005c 00000000 move r0 r0 ; r0 = r0
| 0x00000060 0b3f0000 self r0 r0 252 ; r1=r0 (self), r0=r0[create] self.create()
| 0x00000064 00000000 move r0 r0 ; r0 = r0
| 0x00000068 41010002 loadk r2 5 ; r2 = 1000
| 0x0000006c 00000000 move r0 r0 ; r0 = r0
| 0x00000070 99800100 call r0 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00000074 00000000 move r0 r0 ; r0 = r0
| 0x00000078 07010000 setglobal r0 4
| 0x0000007c 00000000 move r0 r0 ; r0 = r0
| 0x00000080 05010000 getglobal r0 4 ; r0 = Gbl[acc]
| 0x00000084 00000000 move r0 r0 ; r0 = r0
| 0x00000088 4b3f0000 self r0 r0 253 ; r1=r0 (self), r0=r0[withdraw] self.withdraw()
| 0x0000008c 00000000 move r0 r0 ; r0 = r0
| 0x00000090 81010002 loadk r2 6 ; r2 = 100
| 0x00000094 00000000 move r0 r0 ; r0 = r0
| 0x00000098 59800100 call r0 3 1 ; sym.proto1
| ; 0x1000 ; "\n" ; proto1 ; 2 in 0 out
| 0x0000009c 00000000 move r0 r0 ; r0 = r0
\ 0x000000a0 1b800000 return r0 1 ; return r0(args: 0)
0x000000a4 00000000 move r0 r0 ; r0 = r0
; CALL XREF from entry0 @ 0x98
; CALL XREF from proto1 @ 0x1020
;-- section.fcn.00001000.code:
/ proto1(int self, int balance);
| ; arg int self @ r2
| ; arg int balance @ r3
| ; var int acnt @ r4
| 0x00001000 0a000002 newtable r2 0 0 ; [03] -r-x section size 64 named fcn.00001000.code
| 0x00001004 00000000 move r0 r0 ; r0 = r0
| 0x00001008 05000003 getglobal r3 0 ; r3 = Gbl[setmetatable]
| 0x0000100c 00000000 move r0 r0 ; r0 = r0
| 0x00001010 00000104 move r4 r2 ; r4 = r2
| 0x00001014 00000000 move r0 r0 ; r0 = r0
| 0x00001018 45000005 getglobal r5 1 ; r5 = Gbl[Account]
| 0x0000101c 00000000 move r0 r0 ; r0 = r0
| 0x00001020 59800103 call r3 3 1 ; sym.proto1
| ; 0x1000 ; "\n" ; 2 in 0 out
| 0x00001024 00000000 move r0 r0 ; r0 = r0
| 0x00001028 49007e02 settable 2 252 1 ; r2[r252] = r1
| 0x0000102c 00000000 move r0 r0 ; r0 = r0
| 0x00001030 1b000102 return r2 2 ; return r2(args: 1)
| 0x00001034 00000000 move r0 r0 ; r0 = r0
\ 0x00001038 1b800000 return r0 1 ; return r0(args: 0)
0x0000103c 00000000 move r0 r0 ; r0 = r0
; CALL XREF from entry0 @ 0x70
;-- section.fcn.00002000.code:
/ proto2(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| 0x00002000 863e0002 gettable r2 r0 r250 ; r2 = r0[r250]
| 0x00002004 00000000 move r0 r0 ; r0 = r0
| 0x00002008 4d000102 sub 2 2 1 ; r2 = r2 - r1
| 0x0000200c 00000000 move r0 r0 ; r0 = r0
| 0x00002010 89007d00 settable 0 250 2 ; r0[r250] = r2
| 0x00002014 00000000 move r0 r0 ; r0 = r0
\ 0x00002018 1b800000 return r0 1 ; return r0(args: 0)
0x0000201c 00000000 move r0 r0 ; r0 = r0
EOF
RUN
NAME=LUAC: plugin 5.1 vars and functions analysis
FILE=bins/luac/sample0-51.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
pd 20 @ 0x0
pd 17 @ 0x1000
pd 10 @ 0x2000
pd 14 @ 0x3000
pd 13 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 24000000 closure r0 0 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000004 40000000 move r1 r0 ; r1 = r0
| 0x00000008 81000000 loadk r2 -1 ; r2 = 1000
| 0x0000000c 5c800001 call r1 2 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000010 8b40c000 self r2 r1 -2 ; r3=r1 (self), r2=r1[batch_deposit] self.batch_deposit()
| 0x00000014 01810000 loadk r4 -3 ; r4 = 100
| 0x00000018 41c10000 loadk r5 -4 ; r5 = 200
| 0x0000001c 81010100 loadk r6 -5 ; r6 = 300
| 0x00000020 9c408002 call r2 5 1 ; sym.proto1
| ; 0x1000 ; "@" ; proto1 ; 4 in 0 out
| 0x00000024 8b40c100 self r2 r1 -6 ; r3=r1 (self), r2=r1[withdraw] self.withdraw()
| 0x00000028 01810100 loadk r4 -7 ; r4 = 500
| 0x0000002c 9c808001 call r2 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000030 9a000000 test r2 0
| ,==< 0x00000034 16000180 jmp 0 5 ; jump to 0x4c
| |`-> 0x00000038 85c00100 getglobal r2 -8 ; r2 = Gbl[print]
| | 0x0000003c c1000200 loadk r3 -9 ; r3 = New balance:
| | 0x00000040 0641c200 gettable r4 r1 -10 ; r4 = r1[balance]
| | 0x00000044 d5008101 concat r3 r3 r4
\ | 0x00000048 9c400001 call r2 2 1 ; sym.proto1
\ | ; 0x1000 ; "@" ; proto1 ; 1 in 0 out
`--> 0x0000004c 1e008000 return r0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0x20, 0x48
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int balance @ r2
| ; var int Account @ r3
| ; var int self @ r4
| 0x00001000 40000000 move r1 r0 ; r1 = r0
| 0x00001004 8a800000 newtable r2 0 2
| 0x00001008 89404080 settable r2 -1 -2 ; r2[owner] = Admin
| 0x0000100c e4000000 closure r3 0 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001010 89c00081 settable r2 -3 r3 ; r2[calculate_interest] = r3
| 0x00001014 89808081 settable r2 -4 r2 ; r2[__index] = r2
| 0x00001018 c5000100 getglobal r3 -5 ; r3 = Gbl[setmetatable]
| 0x0000101c 0a410000 newtable r4 0 1
| 0x00001020 09418082 settable r4 -6 r1 ; r4[balance] = r1
| 0x00001024 40010001 move r5 r2 ; r5 = r2
| 0x00001028 dc808001 call r3 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x0000102c 24410000 closure r4 1 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001030 c9000183 settable r3 -7 r4 ; r3[withdraw] = r4
| 0x00001034 24810000 closure r4 2 ; instantiate proto 3 `proto4` at 0x4000
| 0x00001038 c9008183 settable r3 -8 r4 ; r3[batch_deposit] = r4
\ 0x0000103c de000001 return r3 2 ; return r3(args: 1)
0x00001040 1e008000 return r0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0xc, 0x2c
; CALL XREF from proto1 @ 0x1028
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for index) @ r7
| ; var int (for limit) @ r8
| ; var int (for step) @ r9
| ; var int i @ r10
| 0x00002000 c6004000 gettable r3 r0 -1 ; r3 = r0[balance]
| 0x00002004 01410000 loadk r4 -2 ; r4 = 1
| 0x00002008 40018000 move r5 r1 ; r5 = r1
| 0x0000200c 81410000 loadk r6 -2 ; r6 = 1
| ,=< 0x00002010 20410080 forprep r4 2
| .--> 0x00002014 0e828001 mul r8 r3 r2 ; r8 = r3 * r2
| :| 0x00002018 cc008201 add r3 r3 r8 ; r3 = r3 + r8
| ``-> 0x0000201c 1f01ff7f forloop r4 -3 ; to 0x2014
\ 0x00002020 de000001 return r3 2 ; return r3(args: 1)
0x00002024 1e008000 return r0 1 ; return r0(args: 0)
;-- section.fcn.00003000.code:
/ proto3(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 18400080 lt 0 -1 r1 ; [07] -r-x section size 56 named fcn.00003000.code
| ,==< 0x00003004 16000280 jmp 0 9 ; jump to 0x302c
| |`-> 0x00003008 86404000 gettable r2 r0 -2 ; r2 = r0[balance]
| |,=< 0x0000300c 19808000 le 0 r1 r2
| ,===< 0x00003010 16400180 jmp 0 6 ; jump to 0x302c
| ||`-> 0x00003014 86404000 gettable r2 r0 -2 ; r2 = r0[balance]
| || 0x00003018 8d400001 sub r2 r2 r1 ; r2 = r2 - r1
| || 0x0000301c 09808080 settable r0 -2 r2 ; r0[balance] = r2
| ||,=< 0x00003020 82008000 loadbool r2 1 0
| ||| 0x00003024 9e000001 return r2 2 ; return r2(args: 1)
| ,==`-> 0x00003028 16400080 jmp 0 2 ; jump to 0x3034
| |``,=< 0x0000302c 82000000 loadbool r2 0 0
\ | | 0x00003030 9e000001 return r2 2 ; return r2(args: 1)
`--`-> 0x00003034 1e008000 return r0 1 ; return r0(args: 0)
; CALL XREF from proto4 @ 0x4014
;-- section.fcn.00004000.code:
/ proto4(int self);
| ; arg int self @ r2
| ; var int arg @ r3
| ; var int args @ r4
| ; var int (for generator) @ r5
| ; var int (for state) @ r6
| ; var int (for control) @ r7
| ; var int _ @ r8
| ; var int val @ r9
| 0x00004000 8a000000 newtable r2 0 0 ; [10] -r-x section size 52 named fcn.00004000.code
| 0x00004004 e5000000 vararg r3 0
| 0x00004008 a2400000 setlist r2 0 1
| 0x0000400c c5000000 getglobal r3 -1 ; r3 = Gbl[ipairs]
| 0x00004010 00010001 move r4 r2 ; r4 = r2
| 0x00004014 dc000101 call r3 2 4 ; sym.proto4
| ; 0x4000 ; 1 in 3 out
| ,==< 0x00004018 16800080 jmp 0 3 ; jump to 0x4028
| .---> 0x0000401c 06424000 gettable r8 r0 -2 ; r8 = r0[balance]
| :| 0x00004020 0cc20104 add r8 r8 r7 ; r8 = r8 + r7
| :| 0x00004024 09008280 settable r0 -2 r8 ; r0[balance] = r8
| :`,=< 0x00004028 e1800000 tforloop 3 -131069 ; to 0xfffffffffff84038
\ `===< 0x0000402c 1680fe7f jmp 0 -5 ; jump to 0x401c
| 0x00004030 1e008000 return r0 1 ; return r0(args: 0)
EOF
RUN
NAME=LUAC: plugin 5.2 vars and functions analysis
FILE=bins/luac/sample0-52.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
pd 20 @ 0x0
pd 17 @ 0x1000
pd 10 @ 0x2000
pd 14 @ 0x3000
pd 13 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 25000000 closure 0 0 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000004 40000000 move r1 r0 ; r1 = r0
| 0x00000008 81000000 loadk 2 -1 ; r2 = 1000
| 0x0000000c 5d800001 call 1 2 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000010 8c40c000 self 2 1 -2 ; r3=r1 (self), r2=r1[batch_deposit] self.batch_deposit()
| 0x00000014 01810000 loadk 4 -3 ; r4 = 100
| 0x00000018 41c10000 loadk 5 -4 ; r5 = 200
| 0x0000001c 81010100 loadk 6 -5 ; r6 = 300
| 0x00000020 9d408002 call 2 5 1 ; sym.proto1
| ; 0x1000 ; "@" ; proto1 ; 4 in 0 out
| 0x00000024 8c40c100 self 2 1 -6 ; r3=r1 (self), r2=r1[withdraw] self.withdraw()
| 0x00000028 01810100 loadk 4 -7 ; r4 = 500
| 0x0000002c 9d808001 call 2 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000030 9b000000 test 2 0
| ,==< 0x00000034 17000180 jmp 0 5 ; jump to 0x4c
| |`-> 0x00000038 86c04100 gettabup 2 0 -8
| | 0x0000003c c1000200 loadk 3 -9 ; r3 = New balance:
| | 0x00000040 0741c200 gettable 4 1 -10 ; r4 = r1[balance]
| | 0x00000044 d6008101 concat 3 3 4
\ | 0x00000048 9d400001 call 2 2 1 ; sym.proto1
\ | ; 0x1000 ; "@" ; proto1 ; 1 in 0 out
`--> 0x0000004c 1f008000 return 0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0x20, 0x48
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int balance @ r2
| ; var int Account @ r3
| ; var int self @ r4
| 0x00001000 40000000 move r1 r0 ; r1 = r0
| 0x00001004 8b800000 newtable 2 0 2
| 0x00001008 8a404080 settable 2 -1 -2 ; r2[owner] = Admin
| 0x0000100c e5000000 closure 3 0 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001010 8ac00081 settable 2 -3 3 ; r2[calculate_interest] = r3
| 0x00001014 8a808081 settable 2 -4 2 ; r2[__index] = r2
| 0x00001018 c6004100 gettabup 3 0 -5
| 0x0000101c 0b410000 newtable 4 0 1
| 0x00001020 0a418082 settable 4 -6 1 ; r4[balance] = r1
| 0x00001024 40010001 move r5 r2 ; r5 = r2
| 0x00001028 dd808001 call 3 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x0000102c 25410000 closure 4 1 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001030 ca000183 settable 3 -7 4 ; r3[withdraw] = r4
| 0x00001034 25810000 closure 4 2 ; instantiate proto 3 `proto4` at 0x4000
| 0x00001038 ca008183 settable 3 -8 4 ; r3[batch_deposit] = r4
\ 0x0000103c df000001 return 3 2 ; return r3(args: 1)
0x00001040 1f008000 return 0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0xc, 0x2c
; CALL XREF from proto1 @ 0x1028
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for index) @ r7
| ; var int (for limit) @ r8
| ; var int (for step) @ r9
| ; var int i @ r10
| 0x00002000 c7004000 gettable 3 0 -1 ; r3 = r0[balance]
| 0x00002004 01410000 loadk 4 -2 ; r4 = 1
| 0x00002008 40018000 move r5 r1 ; r5 = r1
| 0x0000200c 81410000 loadk 6 -2 ; r6 = 1
| ,=< 0x00002010 21410080 forprep 4 2 ; to 0x201c
| .--> 0x00002014 0f828001 mul 8 3 2 ; r8 = r3 * r2
| :| 0x00002018 cd008201 add 3 3 8 ; r3 = r3 + r8
| ``-> 0x0000201c 2001ff7f forloop 4 -3 ; to 0x2014
\ 0x00002020 df000001 return 3 2 ; return r3(args: 1)
0x00002024 1f008000 return 0 1 ; return r0(args: 0)
;-- section.fcn.00003000.code:
/ proto3(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 19400080 lt 0 -1 1 ; [08] -r-x section size 56 named fcn.00003000.code
| ,==< 0x00003004 17000280 jmp 0 9 ; jump to 0x302c
| |`-> 0x00003008 87404000 gettable 2 0 -2 ; r2 = r0[balance]
| |,=< 0x0000300c 1a808000 le 0 1 2
| ,===< 0x00003010 17400180 jmp 0 6 ; jump to 0x302c
| ||`-> 0x00003014 87404000 gettable 2 0 -2 ; r2 = r0[balance]
| || 0x00003018 8e400001 sub 2 2 1 ; r2 = r2 - r1
| || 0x0000301c 0a808080 settable 0 -2 2 ; r0[balance] = r2
| ||,=< 0x00003020 83008000 loadbool 2 1 0
| ||| 0x00003024 9f000001 return 2 2 ; return r2(args: 1)
| ,==`-> 0x00003028 17400080 jmp 0 2 ; jump to 0x3034
| |``,=< 0x0000302c 83000000 loadbool 2 0 0
\ | | 0x00003030 9f000001 return 2 2 ; return r2(args: 1)
`--`-> 0x00003034 1f008000 return 0 1 ; return r0(args: 0)
; CALL XREF from proto4 @ 0x4014
;-- section.fcn.00004000.code:
/ proto4(int self);
| ; arg int self @ r2
| ; var int args @ r3
| ; var int (for generator) @ r4
| ; var int (for state) @ r5
| ; var int (for control) @ r6
| ; var int _ @ r7
| ; var int val @ r8
| 0x00004000 4b000000 newtable 1 0 0 ; [12] -r-x section size 52 named fcn.00004000.code
| 0x00004004 a6000000 vararg 2 0
| 0x00004008 64400000 setlist 1 0 1
| 0x0000400c 86004000 gettabup 2 0 -1
| 0x00004010 c0008000 move r3 r1 ; r3 = r1
| 0x00004014 9d000101 call 2 2 4 ; sym.proto4
| ; 0x4000 ; "K" ; 1 in 3 out
| ,=< 0x00004018 17800080 jmp 0 3 ; jump to 0x4028
| .--> 0x0000401c c7414000 gettable 7 0 -2 ; r7 = r0[balance]
| :| 0x00004020 cd818103 add 7 7 6 ; r7 = r7 + r6
| :| 0x00004024 0ac08180 settable 0 -2 7 ; r0[balance] = r7
| :`-> 0x00004028 a2800000 tforcall 2 2
\ `==< 0x0000402c 2381fe7f tforloop 4 -5 ; to 0x401c
0x00004030 1f008000 return 0 1 ; return r0(args: 0)
EOF
RUN
NAME=LUAC: plugin 5.3 vars and functions analysis
FILE=bins/luac/sample0-53.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
pd 20 @ 0x0
pd 17 @ 0x1000
pd 10 @ 0x2000
pd 14 @ 0x3000
pd 13 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 2c000000 closure r0 0 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000004 40000000 move r1 r0 ; r1 = r0
| 0x00000008 81000000 loadk r2 -1 ; r2 = 1000
| 0x0000000c 64800001 call r1 2 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000010 8c40c000 self r2 r1 -2 ; r3=r1 (self), r2=r1[batch_deposit] self.batch_deposit()
| 0x00000014 01810000 loadk r4 -3 ; r4 = 100
| 0x00000018 41c10000 loadk r5 -4 ; r5 = 200
| 0x0000001c 81010100 loadk r6 -5 ; r6 = 300
| 0x00000020 a4408002 call r2 5 1 ; sym.proto1
| ; 0x1000 ; "@" ; proto1 ; 4 in 0 out
| 0x00000024 8c40c100 self r2 r1 -6 ; r3=r1 (self), r2=r1[withdraw] self.withdraw()
| 0x00000028 01810100 loadk r4 -7 ; r4 = 500
| 0x0000002c a4808001 call r2 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000030 a2000000 test r2 0
| ,==< 0x00000034 1e000180 jmp 0 5 ; jump to 0x4c
| |`-> 0x00000038 86c04100 gettabup r2 0 -8 ; 0x2900 ; r2 = _ENV['print']
| | 0x0000003c c1000200 loadk r3 -9 ; r3 = New balance:
| | 0x00000040 0741c200 gettable r4 r1 -10 ; r4 = r1[balance]
| | 0x00000044 dd008101 concat r3 r3 r4
\ | 0x00000048 a4400001 call r2 2 1 ; sym.proto1
\ | ; 0x1000 ; "@" ; proto1 ; 1 in 0 out
`--> 0x0000004c 26008000 return r0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0x20, 0x48
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int balance @ r2
| ; var int Account @ r3
| ; var int self @ r4
| 0x00001000 40000000 move r1 r0 ; r1 = r0
| 0x00001004 8b800000 newtable r2 0 2
| 0x00001008 8a404080 settable r2 -1 -2 ; r2[owner] = Admin
| 0x0000100c ec000000 closure r3 0 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001010 8ac00081 settable r2 -3 r3 ; r2[calculate_interest] = r3
| 0x00001014 8a808081 settable r2 -4 r2 ; r2[__index] = r2
| 0x00001018 c6004100 gettabup r3 0 -5 ; 0x38a0 ; r3 = _ENV['setmetatable']
| 0x0000101c 0b410000 newtable r4 0 1
| 0x00001020 0a418082 settable r4 -6 r1 ; r4[balance] = r1
| 0x00001024 40010001 move r5 r2 ; r5 = r2
| 0x00001028 e4808001 call r3 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x0000102c 2c410000 closure r4 1 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001030 ca000183 settable r3 -7 r4 ; r3[withdraw] = r4
| 0x00001034 2c810000 closure r4 2 ; instantiate proto 3 `proto4` at 0x4000
| 0x00001038 ca008183 settable r3 -8 r4 ; r3[batch_deposit] = r4
\ 0x0000103c e6000001 return r3 2 ; return r3(args: 1)
0x00001040 26008000 return r0 1 ; return r0(args: 0)
; CALL XREFS from entry0 @ 0xc, 0x2c
; CALL XREF from proto1 @ 0x1028
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for index) @ r7
| ; var int (for limit) @ r8
| ; var int (for step) @ r9
| ; var int i @ r10
| 0x00002000 c7004000 gettable r3 r0 -1 ; r3 = r0[balance]
| 0x00002004 01410000 loadk r4 -2 ; r4 = 1
| 0x00002008 40018000 move r5 r1 ; r5 = r1
| 0x0000200c 81410000 loadk r6 -2 ; r6 = 1
| ,=< 0x00002010 28410080 forprep r4 2 ; to 0x201c
| .--> 0x00002014 0f828001 mul r8 r3 r2 ; r8 = r3 * r2
| :| 0x00002018 cd008201 add r3 r3 r8 ; r3 = r3 + r8
| ``-> 0x0000201c 2701ff7f forloop r4 -3 ; to 0x2014
\ 0x00002020 e6000001 return r3 2 ; return r3(args: 1)
0x00002024 26008000 return r0 1 ; return r0(args: 0)
;-- section.fcn.00003000.code:
/ proto3(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 20400080 lt 0 -1 r1 ; [10] -r-x section size 56 named fcn.00003000.code
| ,==< 0x00003004 1e000280 jmp 0 9 ; jump to 0x302c
| |`-> 0x00003008 87404000 gettable r2 r0 -2 ; r2 = r0[balance]
| |,=< 0x0000300c 21808000 le 0 r1 r2
| ,===< 0x00003010 1e400180 jmp 0 6 ; jump to 0x302c
| ||`-> 0x00003014 87404000 gettable r2 r0 -2 ; r2 = r0[balance]
| || 0x00003018 8e400001 sub r2 r2 r1 ; r2 = r2 - r1
| || 0x0000301c 0a808080 settable r0 -2 r2 ; r0[balance] = r2
| ||,=< 0x00003020 83008000 loadbool r2 1 0
| ||| 0x00003024 a6000001 return r2 2 ; return r2(args: 1)
| ,==`-> 0x00003028 1e400080 jmp 0 2 ; jump to 0x3034
| |``,=< 0x0000302c 83000000 loadbool r2 0 0
\ | | 0x00003030 a6000001 return r2 2 ; return r2(args: 1)
`--`-> 0x00003034 26008000 return r0 1 ; return r0(args: 0)
; CALL XREF from proto4 @ 0x4014
;-- section.fcn.00004000.code:
/ proto4(int self);
| ; arg int self @ r2
| ; var int args @ r3
| ; var int (for generator) @ r4
| ; var int (for state) @ r5
| ; var int (for control) @ r6
| ; var int _ @ r7
| ; var int val @ r8
| 0x00004000 4b000000 newtable r1 0 0 ; [14] -r-x section size 52 named fcn.00004000.code
| 0x00004004 ad000000 vararg r2 0
| 0x00004008 6b400000 setlist r1 0 1
| 0x0000400c 86004000 gettabup r2 0 -1 ; 0x6820 ; r2 = _ENV['ipairs']
| 0x00004010 c0008000 move r3 r1 ; r3 = r1
| 0x00004014 a4000101 call r2 2 4 ; sym.proto4
| ; 0x4000 ; "K" ; 1 in 3 out
| ,=< 0x00004018 1e800080 jmp 0 3 ; jump to 0x4028
| .--> 0x0000401c c7414000 gettable r7 r0 -2 ; r7 = r0[balance]
| :| 0x00004020 cd818103 add r7 r7 r6 ; r7 = r7 + r6
| :| 0x00004024 0ac08180 settable r0 -2 r7 ; r0[balance] = r7
| :`-> 0x00004028 a9800000 tforcall 2 2
\ `==< 0x0000402c 2a81fe7f tforloop r4 -5 ; to 0x401c
0x00004030 26008000 return r0 1 ; return r0(args: 0)
EOF
RUN
NAME=LUAC: plugin 5.4 vars and functions analysis
FILE=bins/luac/sample0-54.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
aa
pd 21 @ 0x0
pd 19 @ 0x1000
pd 12 @ 0x2000
pd 15 @ 0x3000
pd 17 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 51000000 varargprep 0 ; @sample0.lua:1 ; prepare varargs, 0 fixed args
| 0x00000004 4f000000 closure r0 0 ; @sample0.lua:42 ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000008 80000000 move r1 r0 ; @sample0.lua:45 ; r1 = r0
| 0x0000000c 0181f381 loadi r2 1000 ; r2 = 1000
| 0x00000010 c4000202 call r1 2 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000014 14810100 self r2 r1 0 ; @sample0.lua:46 ; r3=r1 (self), r2=r1[0] self.batch_deposit()
| 0x00000018 01823180 loadi r4 100 ; r4 = 100
| 0x0000001c 81826380 loadi r5 200 ; r5 = 200
| 0x00000020 01839580 loadi r6 300 ; r6 = 300
| 0x00000024 44010501 call r2 5 1 ; sym.proto1
| ; 0x1000 ; proto1 ; 4 in 0 out
| 0x00000028 14810101 self r2 r1 1 ; @sample0.lua:48 ; r3=r1 (self), r2=r1[1] self.withdraw()
| 0x0000002c 0182f980 loadi r4 500 ; r4 = 500
| 0x00000030 44010302 call r2 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000034 42010000 test r2
| ,==< 0x00000038 38020080 jmp 5 ; jump to 0x50
| |`-> 0x0000003c 0b010002 gettabup r2 0 2 ; @sample0.lua:49 ; 0x860 ; 0 ; r2 = _ENV['print']
| | 0x00000040 83810100 loadk r3 3 ; r3 = New balance:
| | 0x00000044 0e020104 getfield r4 r1 4 ; r4 = r1['balance']
| | 0x00000048 b5010200 concat r3 r2
| | 0x0000004c 44010201 call r2 2 1 ; sym.proto1
| | ; 0x1000 ; proto1 ; 1 in 0 out
| `--> 0x00000050 46010101 return r2 1 1 ; @sample0.lua:50 ; 0 out
; CALL XREFS from entry0 @ 0x24, 0x4c
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int balance @ r2
| ; var int Account @ r3
| ; var int self @ r4
| 0x00001000 80000000 move r1 r0 ; r1 = r0
| 0x00001004 13010200 newtable r2 2 0 ; r2 = {}; array: 2, hash: 0
| 0x00001008 52000000 extraarg 0 ; extension for previous opcode
| 0x0000100c 12810001 setfield r2 0 1k ; table r2['owner'] = 1
| 0x00001010 cf010000 closure r3 0 ; sym.proto2
| ; 0x2000 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001014 12010203 setfield r2 2 r3 ; table r2['calculate_interest'] = r3
| 0x00001018 12010302 setfield r2 3 r2 ; table r2['__index'] = r2
| 0x0000101c 8b010004 gettabup r3 0 4 ; 0x18a0 ; r3 = _ENV['setmetatable']
| 0x00001020 13020100 newtable r4 1 0 ; r4 = {}; array: 1, hash: 0
| 0x00001024 52000000 extraarg 0 ; extension for previous opcode
| 0x00001028 12020501 setfield r4 5 r1 ; table r4['balance'] = r1
| 0x0000102c 80020200 move r5 r2 ; r5 = r2
| 0x00001030 c4010302 call r3 3 2 ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00001034 4f820000 closure r4 1 ; sym.proto3
| ; 0x3000 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001038 92010604 setfield r3 6 r4 ; table r3['withdraw'] = r4
| 0x0000103c 4f020100 closure r4 2 ; sym.proto4
| ; 0x4000 ; instantiate proto 3 `proto4` at 0x4000
| 0x00001040 92010704 setfield r3 7 r4 ; table r3['batch_deposit'] = r4
| 0x00001044 c8010200 return1 r3 ; return r3
| 0x00001048 47020100 return0 ; empty return
; CALL XREFS from entry0 @ 0x10, 0x30
; CALL XREF from proto1 @ 0x1030
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for state) @ r7
| ; var int i @ r10
| 0x00002000 8e010000 getfield r3 r0 0 ; r3 = r0['balance']
| 0x00002004 01020080 loadi r4 1 ; r4 = 1
| 0x00002008 80020100 move r5 r1 ; r5 = r1
| 0x0000200c 01030080 loadi r6 1 ; r6 = 1
| ,=< 0x00002010 4a020200 forprep 4 4 ; to 0x2028
| .--> 0x00002014 24040302 mul r8 r3 r2 ; r8 = r3 * r2
| :| 0x00002018 ae010208 mmbin r3 r2 8 ; mul
| :| ; 0x15020 ; call metamethod __mul(r3, r2)
| :| 0x0000201c a2010308 add r3 r3 r8 ; r3 = r3 + r8
| :| 0x00002020 ae010806 mmbin r3 r8 6 ; add
| :| ; 0x15018 ; call metamethod __add(r3, r8)
| `==< 0x00002024 49820200 forloop 4 5
| `-> 0x00002028 c8010200 return1 r3 ; return r3
| 0x0000202c 47020100 return0 ; empty return
;-- section.fcn.00003000.code:
/ proto3(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 c0007f00 gti r1 0 0 ; [10] -r-x section size 60 named fcn.00003000.code
| ,==< 0x00003004 b8040080 jmp 10 ; jump to 0x3030
| |`-> 0x00003008 0e010000 getfield r2 r0 0 ; r2 = r0['balance']
| |,=< 0x0000300c bb000200 le r1 r2
| ,===< 0x00003010 38030080 jmp 7 ; jump to 0x3030
| ||`-> 0x00003014 0e010000 getfield r2 r0 0 ; r2 = r0['balance']
| || 0x00003018 23010201 sub r2 r2 r1 ; r2 = r2 - r1
| || 0x0000301c 2e010107 mmbin r2 r1 7 ; sub
| || ; 0x1501c ; call metamethod __sub(r2, r1)
| || 0x00003020 12000002 setfield r0 0 r2 ; table r0['balance'] = r2
| || 0x00003024 07010000 loadtrue r2
| || 0x00003028 48010200 return1 r2 ; return r2
| ||,=< 0x0000302c b8000080 jmp 2 ; jump to 0x3038
| ``--> 0x00003030 05010000 loadfalse r2
| | 0x00003034 48010200 return1 r2 ; return r2
| `-> 0x00003038 47010100 return0 ; empty return
:: ;-- section.fcn.00004000.code:
/ proto4(int self);
| :: ; arg int self @ r2
| :: ; var int args @ r3
| :: ; var int (for state) @ r4
| :: ; var int _ @ r8
| :: ; var int val @ r9
| :: 0x00004000 d1000000 varargprep 1 ; prepare varargs, 1 fixed args
| :: 0x00004004 93000000 newtable r1 0 0 ; r1 = {}; array: 0, hash: 0
| :: 0x00004008 52000000 extraarg 0 ; extension for previous opcode
| :: 0x0000400c 50010000 vararg r2 0 ; r2... = varargs (all)
| :: 0x00004010 ce000000 setlist r1 0 0
| :: 0x00004014 0b010000 gettabup r2 0 0 ; 0x4820 ; r2 = _ENV['ipairs']
| :: 0x00004018 80010100 move r3 r1 ; r3 = r1
| :: 0x0000401c 44010205 call r2 2 5 ; 0x5000 ; 1 in 4 out
| ,==< 0x00004020 4b010200 tforprep 2 4 ; to 0x4034
| .---> 0x00004024 0e040001 getfield r8 r0 1 ; r8 = r0['balance']
| :|: 0x00004028 22040807 add r8 r8 r7 ; r8 = r8 + r7
| :|: 0x0000402c 2e040706 mmbin r8 r7 6 ; add
| :|: ; 0x15018 ; call metamethod __add(r8, r7)
| :|: 0x00004030 12000108 setfield r0 1 r8 ; table r0['balance'] = r8
| :`--> 0x00004034 4c010002 tforcall r2 2
| `=`=< 0x00004038 4d010300 tforloop 2 6 ; to 0x4024
| 0x0000403c 36010000 close r2
| 0x00004040 46810102 return r2 1 2 k ; 0 out
EOF
RUN
NAME=LUAC: plugin pseudo 5.0 version
FILE=bins/luac/sample0-54.luac
CMDS=<<EOF
e asm.arch=luac
e asm.bytes=true
ao~disasm
ao~pseudo
ao~jump
sd +4
ao~disasm
ao~pseudo
ao~jump
sd +4
ao~disasm
ao~pseudo
ao~jump
EOF
EXPECT=<<EOF
disasm: varargprep 0
pseudo: varargs, 0
jump: 0x00000004
disasm: closure r0 0
pseudo: r0 := closure(0)
jump: 0x00000008
disasm: move r1 r0
pseudo: r1 := r0
jump: 0x0000000c
EOF
RUN
NAME=LUAC: pseudo
FILE=bins/luac/class54.luac
CMDS=<<EOF
e asm.pseudo=true
af
aa
pd 23 @ 0x0
pd 9 @ 0x1000
pd 5 @ 0x2000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| 0x00000000 varargs, 0 ; @class.lua:1 ; prepare varargs, 0 fixed args
| 0x00000004 r0 := {} (size = 0,0) ; r0 = {}; array: 0, hash: 0
| 0x00000008 extra (larger) argument for previous opcode (0) ; extension for previous opcode
| 0x0000000c UpValue[0][K[0]:shortstring] := RK(r0) ; 0x820 ; 0 ; _ENV['Account'] = r0
| 0x00000010 r0 := UpValue[0][K[0]:shortstring] ; @class.lua:2 ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000014 r1 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r1 = _ENV['Account']
| 0x00000018 r0[K[1]:shortstring] := RK(r1) ; table r0['__index'] = r1
| 0x0000001c r0 := UpValue[0][K[0]:shortstring] ; @class.lua:4 ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000020 r1 := closure(0) ; @class.lua:9 ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000024 r0[K[2]:shortstring] := RK(r1) ; @class.lua:4 ; table r0['create'] = r1
| 0x00000028 r0 := UpValue[0][K[3]:shortstring] ; @class.lua:11 ; 0x880 ; 0 ; r0 = _ENV['Account']
| 0x0000002c r1 := closure(1) ; @class.lua:13 ; sym.proto2
| ; 0x2000 ; instantiate proto 2 `proto2` at 0x2000
| 0x00000030 r0[K[4]:shortstring] := RK(r1) ; @class.lua:11 ; table r0['withdraw'] = r1
| 0x00000034 r0 := UpValue[0][K[3]:shortstring] ; @class.lua:16 ; 0x880 ; 0 ; r0 = _ENV['Account']
| 0x00000038 r0 := r0 (self), section.fcn.00000000.const := r0[2k] ; r1=r0 (self), r0=r0[2] self.create()
| 0x0000003c r2 := 1000 ; r2 = 1000
| 0x00000040 call r0; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00000044 UpValue[0][K[5]:shortstring] := RK(r0) ; 0x8c0 ; 0 ; _ENV['acc'] = r0
| 0x00000048 r0 := UpValue[0][K[5]:shortstring] ; @class.lua:17 ; 0x8c0 ; 0 ; r0 = _ENV['acc']
| 0x0000004c r0 := r0 (self), proto1 := r0[4k] ; r1=r0 (self), r0=r0[4] self.withdraw()
| 0x00000050 r2 := 100 ; r2 = 100
| 0x00000054 call r0; (3 in; 3 out) ; sym.proto1
| ; 0x1000 ; proto1 ; 2 in 0 out
| 0x00000058 return r0, ... ,r[1] ; 0 out
; CALL XREF from entry0 @ 0x54
; CALL XREF from proto1 @ 0x1014
;-- section.fcn.00001000.code:
/ proto1(int self, int balance);
| ; arg int self @ r2
| ; arg int balance @ r3
| ; var int acnt @ r4
| 0x00001000 r2 := {} (size = 0,0) ; r2 = {}; array: 0, hash: 0
| 0x00001004 extra (larger) argument for previous opcode (0) ; extension for previous opcode
| 0x00001008 r3 := UpValue[0][K[0]:shortstring] ; 0x1820 ; r3 = _ENV['setmetatable']
| 0x0000100c r4 := r2 ; r4 = r2
| 0x00001010 r5 := UpValue[0][K[1]:shortstring] ; 0x1840 ; r5 = _ENV['Account']
| 0x00001014 call r3; (3 in; 3 out) ; sym.proto1
| ; 0x1000 ; 2 in 0 out
| 0x00001018 r2[K[2]:shortstring] := RK(r1) ; table r2['balance'] = r1
| 0x0000101c return1 r2 ; return r2
| 0x00001020 return; ; empty return
; CALL XREF from entry0 @ 0x40
;-- section.fcn.00002000.code:
/ proto2(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| 0x00002000 r2 := r0[K[0]:shortstring] ; r2 = r0['balance']
| 0x00002004 r2 := r2 - r1 ; r2 = r2 - r1
| 0x00002008 call 7 metamethod over r2 and r1 ; sub
| ; 0x1501c ; call metamethod __sub(r2, r1)
| 0x0000200c r0[K[0]:shortstring] := RK(r2) ; table r0['balance'] = r2
| 0x00002010 return; ; empty return
EOF
RUN
NAME=LUAC: pseudo 5.5
FILE=bins/luac/class55.luac
CMDS=<<EOF
e asm.pseudo=true
af
aa
pd 23 @ 0x0
pd 9 @ 0x1000
pd 5 @ 0x2000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| 0x00000000 varargs, r0 ; prepare varargs, 0 fixed args
| 0x00000004 r0 := {} (size = 0,0) ; r0 = {}; array: 0, hash: 0
| 0x00000008 extra (larger) argument for previous opcode (0)
| 0x0000000c UpValue[0][K[0]:shortstring] := RK(r0) ; 0x820 ; 0 ; _ENV['Account'] = r0
| 0x00000010 r0 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000014 r1 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r1 = _ENV['Account']
| 0x00000018 r0[K[1]:shortstring] := RK(r1) ; table r0['__index'] = r1
| 0x0000001c r0 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000020 r1 := closure(0) ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000024 r0[K[2]:shortstring] := RK(r1) ; table r0['create'] = r1
| 0x00000028 r0 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x0000002c r1 := closure(1) ; sym.proto2
| ; 0x2000 ; instantiate proto 2 `proto2` at 0x2000
| 0x00000030 r0[K[3]:shortstring] := RK(r1) ; table r0['withdraw'] = r1
| 0x00000034 r0 := UpValue[0][K[0]:shortstring] ; 0x820 ; 0 ; r0 = _ENV['Account']
| 0x00000038 r0 := r0 (self), r2 := r0[r2] ; r1=r0 (self), r0=r0[r2] self.create()
| 0x0000003c r2 := 1000 ; r2 = 1000
| 0x00000040 call r0; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00000044 UpValue[0][K[4]:shortstring] := RK(r0) ; 0x8a0 ; 0 ; _ENV['acc'] = r0
| 0x00000048 r0 := UpValue[0][K[4]:shortstring] ; 0x8a0 ; 0 ; r0 = _ENV['acc']
| 0x0000004c r0 := r0 (self), r3 := r0[r3] ; r1=r0 (self), r0=r0[r3] self.withdraw()
| 0x00000050 r2 := 100 ; r2 = 100
| 0x00000054 call r0; (3 in; 3 out) ; sym.proto1
| ; 0x1000 ; proto1 ; 2 in 0 out
| 0x00000058 return r0, ... ,r[1] ; 0 out
; CALL XREF from entry0 @ 0x54
; CALL XREF from proto1 @ 0x1014
;-- section.fcn.00001000.code:
/ proto1(int self, int unknown);
| ; arg int self @ r2
| ; arg int unknown @ r3
| ; var int acnt @ r4
| 0x00001000 r2 := {} (size = 0,0) ; @class.lua:5 ; r2 = {}; array: 0, hash: 0
| 0x00001004 extra (larger) argument for previous opcode (0)
| 0x00001008 r3 := UpValue[0][K[0]:shortstring] ; @class.lua:6 ; 0x1820 ; r3 = _ENV['setmetatable']
| 0x0000100c r4 := r2 ; r4 = r2
| 0x00001010 r5 := UpValue[0][K[1]:shortstring] ; 0x1840 ; r5 = _ENV['Account']
| 0x00001014 call r3; (3 in; 3 out) ; sym.proto1
| ; 0x1000 ; 2 in 0 out
| 0x00001018 r2[K[2]:shortstring] := RK(r1) ; @class.lua:7 ; table r2['balance'] = r1
| 0x0000101c return1 r2 ; @class.lua:8 ; return r2
| 0x00001020 return; ; @class.lua:9 ; empty return
; CALL XREF from entry0 @ 0x40
;-- section.fcn.00002000.code:
/ proto2(int unknown, int amount);
| ; arg int unknown @ r2
| ; arg int amount @ r3
| 0x00002000 r2 := r0[K[0]:shortstring] ; r2 = r0['Account']
| 0x00002004 r2 := r2 - r1 ; r2 = r2 - r1
| 0x00002008 call 7 metamethod over r2 and r1 ; sub
| ; 0x1501c ; call metamethod __sub(r2, r1)
| 0x0000200c r0[K[0]:shortstring] := RK(r2) ; table r0['Account'] = r2
| 0x00002010 return; ; empty return
EOF
RUN
NAME=LUAC: pseudo 5.4
FILE=bins/luac/sample0-54.luac
CMDS=<<EOF
e asm.pseudo=true
af
aa
pd 21 @ 0x0
pd 19 @ 0x1000
pd 12 @ 0x2000
pd 15 @ 0x3000
pd 17 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 varargs, 0 ; @sample0.lua:1 ; prepare varargs, 0 fixed args
| 0x00000004 r0 := closure(0) ; @sample0.lua:42 ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000008 r1 := r0 ; @sample0.lua:45 ; r1 = r0
| 0x0000000c r2 := 1000 ; r2 = 1000
| 0x00000010 call r1; (2 in; 2 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000014 r1 := r2 (self), 0 := r1[0k] ; @sample0.lua:46 ; r3=r1 (self), r2=r1[0] self.batch_deposit()
| 0x00000018 r4 := 100 ; r4 = 100
| 0x0000001c r5 := 200 ; r5 = 200
| 0x00000020 r6 := 300 ; r6 = 300
| 0x00000024 call r2; (5 in; 5 out) ; sym.proto1
| ; 0x1000 ; proto1 ; 4 in 0 out
| 0x00000028 r1 := r2 (self), 1 := r1[1k] ; @sample0.lua:48 ; r3=r1 (self), r2=r1[1] self.withdraw()
| 0x0000002c r4 := 500 ; r4 = 500
| 0x00000030 call r2; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000034 if (r2 != k) then pc++
| ,==< 0x00000038 goto pc + 5 ; jump to 0x50
| |`-> 0x0000003c r2 := UpValue[0][K[2]:shortstring] ; @sample0.lua:49 ; 0x860 ; 0 ; r2 = _ENV['print']
| | 0x00000040 r3 := K[3] ; r3 = New balance:
| | 0x00000044 r4 := r1[K[4]:shortstring] ; r4 = r1['balance']
| | 0x00000048 r3 := r3..r2
| | 0x0000004c call r2; (2 in; 2 out) ; sym.proto1
| | ; 0x1000 ; proto1 ; 1 in 0 out
| `--> 0x00000050 return r2, ... ,r[1] ; @sample0.lua:50 ; 0 out
; CALL XREFS from entry0 @ 0x24, 0x4c
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int balance @ r2
| ; var int Account @ r3
| ; var int self @ r4
| 0x00001000 r1 := r0 ; r1 = r0
| 0x00001004 r2 := {} (size = 2,0) ; r2 = {}; array: 2, hash: 0
| 0x00001008 extra (larger) argument for previous opcode (0) ; extension for previous opcode
| 0x0000100c r2[K[0]:shortstring] := RK(1k) ; table r2['owner'] = 1
| 0x00001010 r3 := closure(0) ; sym.proto2
| ; 0x2000 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001014 r2[K[2]:shortstring] := RK(r3) ; table r2['calculate_interest'] = r3
| 0x00001018 r2[K[3]:shortstring] := RK(r2) ; table r2['__index'] = r2
| 0x0000101c r3 := UpValue[0][K[4]:shortstring] ; 0x18a0 ; r3 = _ENV['setmetatable']
| 0x00001020 r4 := {} (size = 1,0) ; r4 = {}; array: 1, hash: 0
| 0x00001024 extra (larger) argument for previous opcode (0) ; extension for previous opcode
| 0x00001028 r4[K[5]:shortstring] := RK(r1) ; table r4['balance'] = r1
| 0x0000102c r5 := r2 ; r5 = r2
| 0x00001030 call r3; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00001034 r4 := closure(1) ; sym.proto3
| ; 0x3000 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001038 r3[K[6]:shortstring] := RK(r4) ; table r3['withdraw'] = r4
| 0x0000103c r4 := closure(2) ; sym.proto4
| ; 0x4000 ; instantiate proto 3 `proto4` at 0x4000
| 0x00001040 r3[K[7]:shortstring] := RK(r4) ; table r3['batch_deposit'] = r4
| 0x00001044 return1 r3 ; return r3
| 0x00001048 return; ; empty return
; CALL XREFS from entry0 @ 0x10, 0x30
; CALL XREF from proto1 @ 0x1030
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for state) @ r7
| ; var int i @ r10
| 0x00002000 r3 := r0[K[0]:shortstring] ; r3 = r0['balance']
| 0x00002004 r4 := 1 ; r4 = 1
| 0x00002008 r5 := r1 ; r5 = r1
| 0x0000200c r6 := 1 ; r6 = 1
| ,=< 0x00002010 <check values and prepare counters>; if not to run then pc+=4; ; to 0x2028
| .--> 0x00002014 r8 := r3 * r2 ; r8 = r3 * r2
| :| 0x00002018 call 8 metamethod over r3 and r2 ; mul
| :| ; 0x15020 ; call metamethod __mul(r3, r2)
| :| 0x0000201c r3 := r3 + r8 ; r3 = r3 + r8
| :| 0x00002020 call 6 metamethod over r3 and r8 ; add
| :| ; 0x15018 ; call metamethod __add(r3, r8)
| `==< 0x00002024 update counters; if loop continues then pc-=5;
| `-> 0x00002028 return1 r3 ; return r3
| 0x0000202c return; ; empty return
;-- section.fcn.00003000.code:
/ proto3(int self, int amount);
| ; arg int self @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 if ((r1 > 0) ~= k) then pc++ ; [10] -r-x section size 60 named fcn.00003000.code
| ,==< 0x00003004 goto pc + 10 ; jump to 0x3030
| |`-> 0x00003008 r2 := r0[K[0]:shortstring] ; r2 = r0['balance']
| |,=< 0x0000300c if ((r1 <= r2) ~= k) then pc++
| ,===< 0x00003010 goto pc + 7 ; jump to 0x3030
| ||`-> 0x00003014 r2 := r0[K[0]:shortstring] ; r2 = r0['balance']
| || 0x00003018 r2 := r2 - r1 ; r2 = r2 - r1
| || 0x0000301c call 7 metamethod over r2 and r1 ; sub
| || ; 0x1501c ; call metamethod __sub(r2, r1)
| || 0x00003020 r0[K[0]:shortstring] := RK(r2) ; table r0['balance'] = r2
| || 0x00003024 r2 := true
| || 0x00003028 return1 r2 ; return r2
| ||,=< 0x0000302c goto pc + 2 ; jump to 0x3038
| ``--> 0x00003030 r2 := false
| | 0x00003034 return1 r2 ; return r2
| `-> 0x00003038 return; ; empty return
:: ;-- section.fcn.00004000.code:
/ proto4(int self);
| :: ; arg int self @ r2
| :: ; var int args @ r3
| :: ; var int (for state) @ r4
| :: ; var int _ @ r8
| :: ; var int val @ r9
| :: 0x00004000 varargs, 1 ; prepare varargs, 1 fixed args
| :: 0x00004004 r1 := {} (size = 0,0) ; r1 = {}; array: 0, hash: 0
| :: 0x00004008 extra (larger) argument for previous opcode (0) ; extension for previous opcode
| :: 0x0000400c r2, r[..+1], ..., r[..+0-2] = vararg ; r2... = varargs (all)
| :: 0x00004010 r1[0] := r[r1+i], 1 <= i <= 0
| :: 0x00004014 r2 := UpValue[0][K[0]:shortstring] ; 0x4820 ; r2 = _ENV['ipairs']
| :: 0x00004018 r3 := r1 ; r3 = r1
| :: 0x0000401c call r2; (2 in; 2 out) ; 0x5000 ; 1 in 4 out
| ,==< 0x00004020 create upvalue for r[2 + 3]; pc+=4 ; to 0x4034
| .---> 0x00004024 r8 := r0[K[1]:shortstring] ; r8 = r0['balance']
| :|: 0x00004028 r8 := r8 + r7 ; r8 = r8 + r7
| :|: 0x0000402c call 6 metamethod over r8 and r7 ; add
| :|: ; 0x15018 ; call metamethod __add(r8, r7)
| :|: 0x00004030 r0[K[1]:shortstring] := RK(r8) ; table r0['balance'] = r8
| :`--> 0x00004034 r[r2+4], ... ,r[r2+3+2] := r2(r[r2+1], r[r2+2]);
| `=`=< 0x00004038 if r[2] ~= nil then { 2=r[2+2]; pc -= 6 } ; to 0x4024
| 0x0000403c close all upvalues >= r2
| 0x00004040 return r2, ... ,r[1] ; 0 out
EOF
RUN
NAME=LUAC: pseudo 5.5
FILE=bins/luac/sample0-55.luac
CMDS=<<EOF
e asm.pseudo=true
af
aa
pd 21 @ 0x0
pd 19 @ 0x1000
pd 12 @ 0x2000
pd 15 @ 0x3000
pd 17 @ 0x4000
EOF
EXPECT=<<EOF
;-- section.fcn.00000000.code:
/ entry0();
| ; var int create_account @ r1
| ; var int my_acc @ r2
| 0x00000000 varargs, r0 ; prepare varargs, 0 fixed args
| 0x00000004 r0 := closure(0) ; sym.proto1
| ; 0x1000 ; instantiate proto 1 `proto1` at 0x1000
| 0x00000008 r1 := r0 ; r1 = r0
| 0x0000000c r2 := 1000 ; r2 = 1000
| 0x00000010 call r1; (2 in; 2 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 1 in 1 out
| 0x00000014 r1 := r2 (self), r0 := r1[r0] ; r3=r1 (self), r2=r1[r0] self.batch_deposit()
| 0x00000018 r4 := 100 ; r4 = 100
| 0x0000001c r5 := 200 ; r5 = 200
| 0x00000020 r6 := 300 ; r6 = 300
| 0x00000024 call r2; (5 in; 5 out) ; sym.proto1
| ; 0x1000 ; proto1 ; 4 in 0 out
| 0x00000028 r1 := r2 (self), r1 := r1[r1] ; r3=r1 (self), r2=r1[r1] self.withdraw()
| 0x0000002c r4 := 500 ; r4 = 500
| 0x00000030 call r2; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| ,=< 0x00000034 if (r2 != k) then pc++
| ,==< 0x00000038 goto pc + 5 ; jump to 0x50
| |`-> 0x0000003c r2 := UpValue[0][K[2]:shortstring] ; 0x860 ; 0 ; r2 = _ENV['print']
| | 0x00000040 r3 := K[3] ; r3 = New balance:
| | 0x00000044 r4 := r1[K[4]:shortstring] ; r4 = r1['balance']
| | 0x00000048 r3 := r3..r2
| | 0x0000004c call r2; (2 in; 2 out) ; sym.proto1
| | ; 0x1000 ; proto1 ; 1 in 0 out
| `--> 0x00000050 return r2, ... ,r[1] ; 0 out
; CALL XREFS from entry0 @ 0x24, 0x4c
;-- section.fcn.00001000.code:
/ proto1(int initial_balance);
| ; arg int initial_balance @ r1
| ; var int unknown @ r2
| ; var int Account @ r3
| 0x00001000 r1 := r0 ; r1 = r0
| 0x00001004 r2 := {} (size = 2,0) ; r2 = {}; array: 2, hash: 0
| 0x00001008 extra (larger) argument for previous opcode (0)
| 0x0000100c r2[K[0]:shortstring] := RK(1k) ; table r2['owner'] = 1
| 0x00001010 r3 := closure(0) ; sym.proto2
| ; 0x2000 ; instantiate proto 1 `proto2` at 0x2000
| 0x00001014 r2[K[2]:shortstring] := RK(r3) ; table r2['calculate_interest'] = r3
| 0x00001018 r2[K[3]:shortstring] := RK(r2) ; table r2['__index'] = r2
| 0x0000101c r3 := UpValue[0][K[4]:shortstring] ; 0x18a0 ; r3 = _ENV['setmetatable']
| 0x00001020 r4 := {} (size = 1,0) ; r4 = {}; array: 1, hash: 0
| 0x00001024 extra (larger) argument for previous opcode (0)
| 0x00001028 r4[K[5]:shortstring] := RK(r1) ; table r4['balance'] = r1
| 0x0000102c r5 := r2 ; r5 = r2
| 0x00001030 call r3; (3 in; 3 out) ; sym.proto2
| ; 0x2000 ; proto2 ; 2 in 1 out
| 0x00001034 r4 := closure(1) ; sym.proto3
| ; 0x3000 ; instantiate proto 2 `proto3` at 0x3000
| 0x00001038 r3[K[6]:shortstring] := RK(r4) ; table r3['withdraw'] = r4
| 0x0000103c r4 := closure(2) ; sym.proto4
| ; 0x4000 ; "S" ; instantiate proto 3 `proto4` at 0x4000
| 0x00001040 r3[K[7]:shortstring] := RK(r4) ; table r3['batch_deposit'] = r4
\ 0x00001044 return1 r3 ; return r3
0x00001048 return; ; empty return
; CALL XREFS from entry0 @ 0x10, 0x30
; CALL XREF from proto1 @ 0x1030
;-- section.fcn.00002000.code:
/ proto2(int self, int years, int rate);
| ; arg int self @ r3
| ; arg int years @ r4
| ; arg int rate @ r5
| ; var int total @ r6
| ; var int (for state) @ r7
| ; var int unknown @ r8
| ; var int i @ r9
| 0x00002000 r3 := r0[K[0]:shortstring] ; @sample0.lua:10 ; r3 = r0['balance']
| 0x00002004 r4 := 1 ; @sample0.lua:11 ; r4 = 1
| 0x00002008 r5 := r1 ; r5 = r1
| 0x0000200c r6 := 1 ; r6 = 1
| ,=< 0x00002010 <check values and prepare counters>; if not to run then pc+=4; ; to 0x2028
| .--> 0x00002014 r7 := r3 * r2 ; @sample0.lua:12 ; r7 = r3 * r2
| :| 0x00002018 call 8 metamethod over r3 and r2 ; mul
| :| ; 0x15020 ; call metamethod __mul(r3, r2)
| :| 0x0000201c r3 := r3 + r7 ; r3 = r3 + r7
| :| 0x00002020 call 6 metamethod over r3 and r7 ; add
| :| ; 0x15018 ; call metamethod __add(r3, r7)
| `==< 0x00002024 update counters; if loop continues then pc-=5; ; @sample0.lua:11
| `-> 0x00002028 return1 r3 ; @sample0.lua:14 ; return r3
| 0x0000202c return; ; @sample0.lua:15 ; empty return
;-- section.fcn.00003000.code:
/ proto3(int unknown, int amount);
| ; arg int unknown @ r2
| ; arg int amount @ r3
| ,=< 0x00003000 if ((r1 > 0) ~= k) then pc++ ; [10] -r-x section size 60 named fcn.00003000.code
| ,==< 0x00003004 goto pc + 10 ; jump to 0x3030
| |`-> 0x00003008 r2 := r0[K[0]:shortstring] ; r2 = r0['balance']
| |,=< 0x0000300c if ((r1 <= r2) ~= k) then pc++
| ,===< 0x00003010 goto pc + 7 ; jump to 0x3030
| ||`-> 0x00003014 r2 := r0[K[0]:shortstring] ; r2 = r0['balance']
| || 0x00003018 r2 := r2 - r1 ; r2 = r2 - r1
| || 0x0000301c call 7 metamethod over r2 and r1 ; sub
| || ; 0x1501c ; call metamethod __sub(r2, r1)
| || 0x00003020 r0[K[0]:shortstring] := RK(r2) ; table r0['balance'] = r2
| || 0x00003024 r2 := true
| || 0x00003028 return1 r2 ; return r2
| ||,=< 0x0000302c goto pc + 2 ; jump to 0x3038
| ``--> 0x00003030 r2 := false
| | 0x00003034 return1 r2 ; return r2
| `-> 0x00003038 return; ; empty return
:: ;-- section.fcn.00004000.code:
/ proto4(int unknown);
| :: ; arg int unknown @ r2
| :: ; var int (vararg table) @ r3
| :: ; var int args @ r4
| :: ; var int _ @ r8
| :: ; var int val @ r9
| :: 0x00004000 varargs, r0 ; prepare varargs, 0 fixed args
| :: 0x00004004 r2 := {} (size = 0,0) ; r2 = {}; array: 0, hash: 0
| :: 0x00004008 extra (larger) argument for previous opcode (0)
| :: 0x0000400c r3, r[..+1], ..., r[..+0-2] = vararg ; r3... = varargs (all)
| :: 0x00004010 r2[0] := r[r2+i], 1 <= i <= 0
| :: 0x00004014 r3 := UpValue[0][K[0]:shortstring] ; 0x4820 ; r3 = _ENV['ipairs']
| :: 0x00004018 r4 := r2 ; r4 = r2
| :: 0x0000401c call r3; (2 in; 2 out) ; 0x5000 ; 1 in 4 out
| ,==< 0x00004020 create upvalue for r[3 + 3]; pc+=4 ; to 0x4034
| .---> 0x00004024 r8 := r0[K[1]:shortstring] ; r8 = r0['balance']
| :|: 0x00004028 r8 := r8 + r7 ; r8 = r8 + r7
| :|: 0x0000402c call 6 metamethod over r8 and r7 ; add
| :|: ; 0x15018 ; call metamethod __add(r8, r7)
| :|: 0x00004030 r0[K[1]:shortstring] := RK(r8) ; table r0['balance'] = r8
| :`--> 0x00004034 r[r3+4], ... ,r[r3+3+2] := r3(r[r3+1], r[r3+2]);
| `=`=< 0x00004038 if r[3] ~= nil then { 3=r[3+2]; pc -= 6 } ; to 0x4024
| 0x0000403c close all upvalues >= r3
| 0x00004040 return r3, ... ,r[1] ; 0 out
EOF
RUN