日記どす

ただの日記とポエムどす。

Lua 5.3の逆アセンブラを書いたこと

はじめに

Lua 5.3のソースコードを追っていたのですが、コンパイラの部分で詰まってしまいました。 処理自体は特に難しいことはやっていないはずなのですが、Luaコンパイラは1パスで、構文解析、意味解析、バイトコードの生成処理がグチャグチャに入り組んでおり非常に読み辛いです。

複雑に絡み合ったCコードを読んでいるうちに、ソースコードから処理を把握するよりは、吐き出されるバイトコードから逆に実装を追った方が理解が進むのではないかと次第に思い始めました。 ということでLua 5.3のバイトコードの逆アセンブラを作成しました。

github.com

インストール

LuaRocksを入れて以下のコマンドを叩いてください。

git clone https://github.com/tacigar/lhades.git
cd lhades
luarocks make

簡単!LuaRocks最高!

使い方

luacが吐くバイトコードのファイルlhades に食わせてください。

lhades <filename>

利用例

例として、以下の3回 "Hello! John" と叫ぶだけのLuaプログラム準備し、 test.lua として保存します。

local name = "John"

function hello_world(count)
    for i = 1, count do
        print("Hello!, " .. name)
    end
end

hello_world(3)

次に、以下のコマンドでこのプログラムをコンパイルしてください。

luac test.lua

すると、以下のバイトコードが書かれたluac.outというファイルが生成されるはずです。

1b4c 7561 5300 1993 0d0a 1a0a 0408 0408
0878 5600 0000 0000 0000 0000 0000 2877
4001 0a40 7465 7374 2e6c 7561 0000 0000
0000 0000 0002 0307 0000 0001 0000 006c
0000 0008 4080 8046 4040 0081 8000 0064
4000 0126 0080 0003 0000 0004 054a 6f68
6e04 0c68 656c 6c6f 5f77 6f72 6c64 1303
0000 0000 0000 0001 0000 0001 0001 0000
0000 0300 0000 0700 0000 0100 080b 0000
0041 0000 0080 0000 00c1 0000 0068 0001
8046 4140 0081 8100 00c5 0180 009d c101
0364 4100 0167 40fe 7f26 0080 0003 0000
0013 0100 0000 0000 0000 0406 7072 696e
7404 0948 656c 6c6f 212c 2002 0000 0000
0001 0000 0000 000b 0000 0004 0000 0004
0000 0004 0000 0004 0000 0005 0000 0005
0000 0005 0000 0005 0000 0005 0000 0004
0000 0007 0000 0005 0000 0006 636f 756e
7400 0000 000b 0000 000c 2866 6f72 2069
6e64 6578 2903 0000 000a 0000 000c 2866
6f72 206c 696d 6974 2903 0000 000a 0000
000b 2866 6f72 2073 7465 7029 0300 0000
0a00 0000 0269 0400 0000 0900 0000 0200
0000 055f 454e 5605 6e61 6d65 0700 0000
0100 0000 0700 0000 0300 0000 0900 0000
0900 0000 0900 0000 0900 0000 0100 0000
056e 616d 6501 0000 0007 0000 0001 0000
0005 5f45 4e56                         

このファイルを以下のコマンドでlhadesに食わせてください。

lhades luac.out

アセンブリコードが標準出力されるはずです!やったぜ!

source name "@test.lua": 0 - 0: 0 params, 3 stacks
.codes: 7
  [1] LOADK           0               0    ; R(0) := Kst(0)
  [2] CLOSURE         1               0    ; R(1) := closure(KPROTO[0])
  [3] SETTABUP        0     257       1    ; UpValue[0][RK(257)] := RK(1)
  [4] GETTABUP        1       0     257    ; R(1) := UpValue[0][RK(257)]
  [5] LOADK           2               2    ; R(2) := Kst(2)
  [6] CALL            1       2       1    ; R(1), ... ,R(1+1-2) := R(1)(R(1+1), ... ,R(1+2-1))
  [7] RETURN          0               1    ; return R(0), ... ,R(0+1-2)
.consts: 3
  [0] "John"
  [1] "hello_world"
  [2] 3
.upvalues: 1
  [0] inStack: true, index: 0    ; _ENV
.locals: 1
  [0] "name" (1 - 7)
.protos: 1
  [0] source name "@test.lua": 3 - 7: 1 params, 8 stacks
    .codes: 11
      [ 1] LOADK           1               0    ; R(1) := Kst(0)
      [ 2] MOVE            2               0    ; R(2) := R(0)
      [ 3] LOADK           3               0    ; R(3) := Kst(0)
      [ 4] FORPREP         1               5    ; R(1)-=R(1+2); pc+=5
      [ 5] GETTABUP        5       0     257    ; R(5) := UpValue[0][RK(257)]
      [ 6] LOADK           6               2    ; R(6) := Kst(2)
      [ 7] GETUPVAL        7               1    ; R(7) := UpValue[1]
      [ 8] CONCAT          6       6       7    ; R(6) := R(6).. ... ..R(7)
      [ 9] CALL            5       2       1    ; R(5), ... ,R(5+1-2) := R(5)(R(5+1), ... ,R(5+2-1))
      [10] FORLOOP         1              -6    ; R(1)+=R(1+2); if R(1) <?= R(1+1) then { pc+=-6; R(1+3)=R(1) }
      [11] RETURN          0               1    ; return R(0), ... ,R(0+1-2)
    .consts: 3
      [0] 1
      [1] "print"
      [2] "Hello!, "
    .upvalues: 2
      [0] inStack: false, index: 0    ; _ENV
      [1] inStack: true, index: 0    ; name
    .locals: 5
      [0] "count" (0 - 11)
      [1] "(for index)" (3 - 10)
      [2] "(for limit)" (3 - 10)
      [3] "(for step)" (3 - 10)
      [4] "i" (4 - 9)
    .protos: 0

なお、Luaアセンブリコードが読めない人は以下を参考にしてください(責任放棄)。

Lua 5.3 Bytecode Reference — Ravi Programming Language 0.1 documentation