This page follows Lua 5.3’s ldump.c, lundump.c,
lundump.h and lopcodes.h (5.3.6). The format is not
documented by the Lua authors. Lua 5.3 added a separate integer type, so the header
checks the sizes of both integers and floats, and stores a sample of each so the
loader can detect a different byte order or float format.
Header
| Offset | Size | Field | Meaning |
|---|---|---|---|
0 | 4 | signature | 1B 4C 75 61. |
4 | 1 | version | 0x53. |
5 | 1 | format | 0, the official format. |
6 | 6 | LUAC_DATA | 19 93 0D 0A 1A 0A, compared byte for byte; a mismatch means a corrupted chunk. |
12 | 1 | sizeof(int) | Bytes in an int. |
13 | 1 | sizeof(size_t) | Bytes in a size_t. |
14 | 1 | sizeof(Instruction) | Bytes in an instruction. |
15 | 1 | sizeof(lua_Integer) | Bytes in an integer. |
16 | 1 | sizeof(lua_Number) | Bytes in a float. |
17 | 8* | LUAC_INT | The integer 0x5678 as a lua_Integer, which reveals the byte order. |
25* | 8* | LUAC_NUM | The float 370.5 as a lua_Number, which reveals the float format. |
33* | 1 | upvalues | Number of upvalues of the main closure. |
* With 8-byte lua_Integer and lua_Number.
There is no endianness byte: the sample integer replaces it.
Basic types
| Type | Encoding |
|---|---|
| byte | One byte. |
| int | sizeof(int) bytes, native byte order. |
| integer | sizeof(lua_Integer) bytes. |
| number | sizeof(lua_Number) bytes. |
| string | A size byte holding the length plus one; 00 means no string; FF means the length plus one follows as a size_t. Then the bytes, with no terminating zero. |
| list of T | An int count, then that many T. |
Function prototype
| Field | Type | Meaning |
|---|---|---|
| source | string | Source name; when absent, the parent function’s source is used. |
| linedefined | int | First line. |
| lastlinedefined | int | Last line. |
| numparams | byte | Fixed parameters. |
| is_vararg | byte | Whether the function takes .... |
| maxstacksize | byte | Registers needed. |
| code | list of Instruction | 4 bytes each. |
| constants | list of constant | Below. |
| upvalues | list of (byte, byte) | instack and idx, one byte each. |
| protos | list of function | Nested prototypes. |
| lineinfo | list of int | Line of each instruction. |
| locvars | list of (string, int, int) | Name, start pc, end pc. |
| upvalue names | list of string | Upvalue names in order. |
Constants
| Tag byte | Type | Then |
|---|---|---|
0x00 | nil | nothing |
0x01 | boolean | one byte |
0x03 | float (LUA_TNUMFLT) | a number |
0x13 | integer (LUA_TNUMINT) | an integer |
0x04 | short string (LUA_TSHRSTR) | a string |
0x14 | long string (LUA_TLNGSTR) | a string |
The tag is the basic type in the low four bits and a variant in bits 4–5.
Instructions
| Mode | Bits 31–23 | Bits 22–14 | Bits 13–6 | Bits 5–0 |
|---|---|---|---|---|
iABC | B (9) | C (9) | A (8) | opcode (6) |
iABx | Bx (18) | A (8) | opcode (6) | |
iAsBx | sBx (18), stored + 131,071 | A (8) | opcode (6) | |
iAx | Ax (26) | opcode (6) | ||
RK(x) is constant x − 256 when bit 8 is set, otherwise
register x. SETLIST’s batch size FPF is
LFIELDS_PER_FLUSH (50 in 5.1; not re-read for 5.3). Every skip assumes
the next instruction is a jump.
| Op | Name | Mode | Action |
|---|---|---|---|
| 0 | MOVE | A B | R(A) := R(B) |
| 1 | LOADK | A Bx | R(A) := Kst(Bx) |
| 2 | LOADKX | A | R(A) := Kst(extra arg) |
| 3 | LOADBOOL | A B C | R(A) := (Bool)B; if C, skip next |
| 4 | LOADNIL | A B | R(A), …, R(A+B) := nil |
| 5 | GETUPVAL | A B | R(A) := UpValue[B] |
| 6 | GETTABUP | A B C | R(A) := UpValue[B][RK(C)] |
| 7 | GETTABLE | A B C | R(A) := R(B)[RK(C)] |
| 8 | SETTABUP | A B C | UpValue[A][RK(B)] := RK(C) |
| 9 | SETUPVAL | A B | UpValue[B] := R(A) |
| 10 | SETTABLE | A B C | R(A)[RK(B)] := RK(C) |
| 11 | NEWTABLE | A B C | R(A) := {} (size B, C) |
| 12 | SELF | A B C | R(A+1) := R(B); R(A) := R(B)[RK(C)] |
| 13 | ADD | A B C | R(A) := RK(B) + RK(C) |
| 14 | SUB | A B C | R(A) := RK(B) − RK(C) |
| 15 | MUL | A B C | R(A) := RK(B) × RK(C) |
| 16 | MOD | A B C | R(A) := RK(B) % RK(C) |
| 17 | POW | A B C | R(A) := RK(B) ^ RK(C) |
| 18 | DIV | A B C | R(A) := RK(B) / RK(C) |
| 19 | IDIV | A B C | R(A) := RK(B) // RK(C) |
| 20 | BAND | A B C | R(A) := RK(B) & RK(C) |
| 21 | BOR | A B C | R(A) := RK(B) | RK(C) |
| 22 | BXOR | A B C | R(A) := RK(B) ~ RK(C) |
| 23 | SHL | A B C | R(A) := RK(B) << RK(C) |
| 24 | SHR | A B C | R(A) := RK(B) >> RK(C) |
| 25 | UNM | A B | R(A) := −R(B) |
| 26 | BNOT | A B | R(A) := ~R(B) |
| 27 | NOT | A B | R(A) := not R(B) |
| 28 | LEN | A B | R(A) := length of R(B) |
| 29 | CONCAT | A B C | R(A) := R(B) .. … .. R(C) |
| 30 | JMP | A sBx | pc += sBx; if A, close upvalues at or above R(A−1) |
| 31 | EQ | A B C | if (RK(B) == RK(C)) ~= A then skip next |
| 32 | LT | A B C | if (RK(B) < RK(C)) ~= A then skip next |
| 33 | LE | A B C | if (RK(B) <= RK(C)) ~= A then skip next |
| 34 | TEST | A C | if not (R(A) <=> C) then skip next |
| 35 | TESTSET | A B C | if R(B) <=> C then R(A) := R(B) else skip next |
| 36 | CALL | A B C | R(A), …, R(A+C−2) := R(A)(R(A+1), …, R(A+B−1)) |
| 37 | TAILCALL | A B C | return R(A)(R(A+1), …, R(A+B−1)) |
| 38 | RETURN | A B | return R(A), …, R(A+B−2) |
| 39 | FORLOOP | A sBx | R(A) += R(A+2); if within R(A+1), pc += sBx and R(A+3) := R(A) |
| 40 | FORPREP | A sBx | R(A) −= R(A+2); pc += sBx |
| 41 | TFORCALL | A C | R(A+3), …, R(A+2+C) := R(A)(R(A+1), R(A+2)) |
| 42 | TFORLOOP | A sBx | if R(A+1) ~= nil then R(A) := R(A+1); pc += sBx |
| 43 | SETLIST | A B C | R(A)[(C−1) × FPF + i] := R(A+i), 1 ≤ i ≤ B |
| 44 | CLOSURE | A Bx | R(A) := closure(KPROTO[Bx]) |
| 45 | VARARG | A B | R(A), …, R(A+B−2) := vararg |
| 46 | EXTRAARG | Ax | A larger argument for the previous instruction |
Example
1B 4C 75 61 53 00 signature, version 5.3, format 0
19 93 0D 0A 1A 0A LUAC_DATA
04 08 04 08 08 sizes: int, size_t, Instruction, lua_Integer, lua_Number
78 56 00 00 00 00 00 00 LUAC_INT 0x5678 (little-endian)
00 00 00 00 00 28 77 40 LUAC_NUM 370.5 (0x4077280000000000)
01 main closure has 1 upvalue
0B 40 68 65 6C 6C 6F 2E 6C 75 61 source "@hello.lua" (length 10, stored as 11)
Sizes and the source name are illustrative.
Sources
Lua 5.3.6 source (lua.org and the
lua/lua repository):
lundump.c (checkHeader, LoadFunction, constants,
strings), lundump.h (LUAC_DATA, LUAC_INT,
LUAC_NUM, LUAC_VERSION, LUAC_FORMAT),
lobject.h (constant tags and variant bits) and lopcodes.h
(field sizes, BITRK, MAXARG_sBx, every opcode and its
comment). The value of 370.5 as bytes is worked out from IEEE 754.