Lua
7月になってスーパーの袋が有料化された。これはたまらんと女房がトートバッグを引っ張り出した。No Ruby, No Life. って奴。rubyの伝道師を務めるんだな。オイラーはLuaの伝道師(今の所は)を務めます。
wireshark
前回の調べでは、wiresharkにもluaが使われいるそうなので、本当か最新の3.2.5で確認してみた。確かに使われていたよ。でも、その位置付けを明確に読み取れず。
悔しいので、ソースが有るんでbuildしてみた。mkdir build; cd build; cmake .. なんだけど、GUIを作るQtの環境を用意しないとならない。潔く諦める。乗りかけた船なんで、GUI無しでやってみる。
debian:build$ cmake -DBUILD_wireshark=OFF .. debian:build$ make : [100%] Built target fuzzshark real 27m24.164s user 24m58.925s sys 1m42.720s
run/ の下に出来ている tshark あたりが核になるのかな。tshark.htmlを軽く眺めてみると、tcpdumpの超拡張版のように取れるんだけど。
GUIなんて、皮だからどうでも良い。『UNIXという考え方』新人エンジニアにオススメする技術書 懐かしい本が出て来た。昔読んだ時、そうだよね。マウスでぐりぐりって人が張り付いて作業しなきゃならない方式。オイラーは疲れちゃう。
そこで、スーパーコンピュータ「不老」 ですよ。不老はフロー。フローと言えば、データが流れてくるパイプですよ。ちょっとした事をやりたい場合、スクリプトを書く前に、それってパイプにデータを流して処理出来ないか、真っ先に考えます。それもこれも、unixの偉大な発明、パイプが有ったればこそです。
puTTY 0.74
OpenBSDにpuTTYから接続出来なくなっていた。もう10年も使っている年代物の0.60版だったからしょうがないと諦めていたんだ。
最近、0.74版が出たというので取り寄せてみた。PuTTY: a free SSH and Telnet client そしたら、無事に使えた。zip版を適当な所に置いただけなんだけど、ちゃんと前に使ってた設定が生きていて、何の苦もなく利用出来た。
それはいいんだけど、設定はどこに残っているのかな。前の版もWindows7時代のやつを、そのままdir事Windows10に持ってきただけなんで、古い版の設定なんてM$の管理化には無いはずなんだけどな。
兎も角、これで3wayで接続出来るようになった。PuTTYでの接続、Windows terminalでの接続、Tera Termによるシリアル接続。各種用意してあれば、どれかで接続出来る、安泰である。
世は、WSL2でWindowsにべったりなLinuxってのが流行る兆候が有るけど、なるべくWindowsとは距離を置いておいた方が安心と思うぞ。それにWSL2はリナしか動かなくて、面白く無いしょ。
上で挙げた、puTTYの設定はどうなってる疑問の答えがFAQに出てた。Windowsが用意したDBに保存してますと。だからpuTTYを削除する時は、先に下記の操作をしておけとな。
putty -cleanup
HKEY_CURRENT_USER\Software\SimonTatham\PuTTY
こういう場所に保存されるそうな。だから、MobaXtermが軽々と設定を利用出来たんだな。納得です。
lua
日本語マニュアルが有った。Lua 5.3 リファレンスマニュアル
The Programming Language Lua のソースコードを読みます
追試
上のリンクにもあるように、GCの方式が変わったとな。debian(32it)で試した時は、にわかに信じられないような差が付いていたので、64Bitの方でも試してみる。 debian(64Bit)
sakae@pen:/tmp/lua-5.3.5/src$ time ./lua tak.lua real 0m28.311s user 0m28.306s sys 0m0.004s sakae@pen:/tmp/lua-5.4.0/src$ time ./lua tak.lua real 0m22.776s user 0m22.769s sys 0m0.000s
おまけで、OpenBSD(64Bit)
ob$ ./lua -v Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio ob$ time ./lua tak.lua 0m35.18s real 0m35.18s user 0m00.02s system ob$ ./lua -v Lua 5.4.0 Copyright (C) 1994-2020 Lua.org, PUC-Rio ob$ time ./lua tak.lua 0m32.65s real 0m32.66s user 0m00.00s system
これぐらいの差が妥当な所だと思われる。
lua温故知新
余り新しい物ばかりを追う前に、古いのも見てみろ。ソフトは積み重ねだからね。 そんな訳で、適当に古いと思われる、5.1.5を取ってきた(この版に他意は無い)。
min
今の物と違っておまけが付いていた。まずはetcの中のやつ。
debian:etc$ make min gcc -O2 -Wall -I../src min.c -L../src -llua -lm echo 'print"Hello there!"' | ./a.out Hello there!
簡単なprint文を呼び出すだけなやつ。勿論、事前にluaをコンパイルしておく事。 で、下記のようにしてgdbで取り調べをしてみる。
debian:etc$ cat Z print "Hello there!" debian:etc$ gdb -q a.out Reading symbols from a.out... (gdb) b print Breakpoint 1 at 0x14d0: file min.c, line 14. (gdb) r <Z Starting program: /tmp/lua-5.1.5/etc/a.out <Z Breakpoint 1, print (L=0x41f160) at min.c:14 14 int n=lua_gettop(L); (gdb) bt #0 print (L=0x41f160) at min.c:14 #1 0x00404a92 in luaD_precall (L=<optimized out>, func=0x41f3a8, nresults=0) at ldo.c:320 #2 0x0040dc8d in luaV_execute (L=<optimized out>, nexeccalls=1) at lvm.c:591 #3 0x00404fbb in luaD_call (L=0x41f160, func=0x41f39c, nResults=-1) at ldo.c:378 #4 0x00401625 in f_call (L=0x41f160, ud=0xbffff3f8) at lapi.c:800 #5 0x00404395 in luaD_rawrunprotected (L=0x41f160, f=0x401610 <f_call>, ud=0xbffff3f8) at ldo.c:116 #6 0x00405179 in luaD_pcall (L=0x41f160, func=0x401610 <f_call>, u=0xbffff3f8, old_top=12, ef=0) at ldo.c:464 #7 0x00402a0b in lua_pcall (L=0x41f160, nargs=0, nresults=-1, errfunc=0) at lapi.c:821 #8 0x00401339 in main () at min.c:36
trace-call
test/の中にも、面白いものがあった。とある関数の根もバイナリーサーチに見つけるというluaの例。
debian:test$ lua bisect.lua 0 c=1.5 a=1 b=2 1 c=1.25 a=1 b=1.5 : 20 c=1.3247179985046 a=1.3247175216675 b=1.3247184753418 after 20 steps, root is 1.3247179985046387 with error 9.5e-07, f=1.8e-07
本命はこれじゃなくて、どんな風に関数が呼び出されているか、トレースしちゃいましょって言う、luaで書かれたライブラリィー。
debian:test$ head trace-calls.lua -- trace calls -- example: lua -ltrace-calls bisect.lua
トレーサーの冒頭に、使い方が出てた。-lでライブラリー呼び出しになる。サフィックスは付けないという約束。これだけ分かれば良い。
debian:test$ lua -ltrace-calls bisect.lua 0 >>> ./trace-calls.lua:31 return sethook [C] 0 >>> end ./trace-calls.lua 0 >>> return (C) [C] 0 >>> begin bisect.lua 1 >>> bisect.lua:27 call solve <15:bisect.lua> 2 >>> bisect.lua:17 call f <22:bisect.lua> 3 >>> bisect.lua:17 return f <22:bisect.lua> 2 >>> bisect.lua:17 call f <22:bisect.lua> 3 >>> bisect.lua:17 return f <22:bisect.lua> 2 >>> bisect.lua:17 call bisect <5:bisect.lua> 3 >>> bisect.lua:7 call write [C] 0 c=1.5 a=1 b=2 4 >>> bisect.lua:7 return write [C] 3 >>> bisect.lua:8 call abs [C] 4 >>> bisect.lua:8 return abs [C] : after 20 steps, root is 1.3247179985046387 with error 9.5e-07, f=1.8e-07 1 >>> bisect.lua:18 return write [C] 0 >>> bisect.lua:27 return solve <15:bisect.lua> 0 >>> end bisect.lua 0 >>> return (C) [C]
debugライブラリーをhookして実現してる。楽しそうである。
luadec
何か、こう道具を集めるのが趣味と化している。ならば、逆アセンブラーなんてのが欲しいと思っちゃうな。探してみたら直ぐに見つかった。
LuaDec is a Lua decompiler for lua 5.1 , and experimental for lua 5.2 and 5.3.
色々な所で隠れluaしてるんで、こういうのも有志が作ってくれているんだな。 早速試してみるか。
vbox$ cat hoge.lua function hoge(a,b) local t = a^2 return t + b end print( hoge(2,3) )
vbox$ luadec -dis hoge.lua ; Disassembled using luadec 2.2 rev: 895d923 for Lua 5.1 from https://github.com/viruscamp/luadec ; Command line: -dis hoge.lua ; Function: 0 ; Defined at line: 0 ; #Upvalues: 0 ; #Parameters: 0 ; Is_vararg: 2 ; Max Stack Size: 4 0 [-]: CLOSURE R0 0 ; R0 := closure(Function #0_0) 1 [-]: SETGLOBAL R0 K0 ; hoge := R0 2 [-]: GETGLOBAL R0 K1 ; R0 := print 3 [-]: GETGLOBAL R1 K0 ; R1 := hoge 4 [-]: LOADK R2 K2 ; R2 := 2 5 [-]: LOADK R3 K3 ; R3 := 3 6 [-]: CALL R1 3 0 ; R1 to top := R1(R2 to R3) 7 [-]: CALL R0 0 1 ; := R0(R1 to top) 8 [-]: RETURN R0 1 ; return ; Function: 0_0 ; Defined at line: 2 ; #Upvalues: 0 ; #Parameters: 2 ; Is_vararg: 0 ; Max Stack Size: 4 0 [-]: POW R2 R0 K0 ; R2 := R0 ^ 2 1 [-]: ADD R3 R2 R1 ; R3 := R2 + R1 2 [-]: RETURN R3 2 ; return R3 3 [-]: RETURN R0 1 ; return
lhades
もう一つ日本人が書かれた、逆アセンブラを見つけた。lua 5.3.5 専用なのかな。
インストールには業界標準のパッケージマネージャ luarocks を使っている。rubyで言うgemなんだな。こういう周辺ツールが提供されてるって事は、成熟してる証拠だ。
何はともあれ、走らせてみる。例は上でやったやつ。
sakae@pen:/tmp$ luac hoge.lua sakae@pen:/tmp$ lhades luac.out .codes: 9 [1] CLOSURE 0 0 ; R(0) := closure(KPROTO[0]) [2] SETTABUP 0 256 0 ; UpValue[0][RK(256)] := RK(0) [3] GETTABUP 0 0 257 ; R(0) := UpValue[0][RK(257)] [4] GETTABUP 1 0 256 ; R(1) := UpValue[0][RK(256)] [5] LOADK 2 2 ; R(2) := Kst(2) [6] LOADK 3 3 ; R(3) := Kst(3) [7] CALL 1 3 0 ; R(1), ... ,R(1+0-2) := R(1)(R(1+1), ... ,R(1+3-1)) [8] CALL 0 0 1 ; R(0), ... ,R(0+1-2) := R(0)(R(0+1), ... ,R(0+0-1)) [9] RETURN 0 1 ; return R(0), ... ,R(0+1-2) .consts: 4 [0] "hoge" [1] "print" [2] 2 [3] 3 .upvalues: 1 [0] inStack: true, index: 0 ; _ENV .locals: 0 .protos: 1 [0] source name "@hoge.lua": 1 - 4: 2 params, 4 stacks .codes: 4 [1] POW 2 0 256 ; R(2) := RK(0) ^ RK(256) [2] ADD 3 2 1 ; R(3) := RK(2) + RK(1) [3] RETURN 3 2 ; return R(3), ... ,R(3+2-2) [4] RETURN 0 1 ; return R(0), ... ,R(0+1-2) .consts: 1 [0] 2 .upvalues: 0 .locals: 3 [0] "a" (0 - 4) [1] "b" (0 - 4) [2] "t" (1 - 4) .protos: 0
素晴らしい!!
LuaRocks
LuaRocks が、本拠地。提供されてるモジュールの人気なやつが列挙されてたりする。何となく使われている業界が想像出来たりして。
どうもメインはLinuxとWindowsっぽい。まあ、しょうがないか。
こういうパッケージマネージャが出てくると、オイラーは何となく、引いちゃうんだよな。
上のlhadesを素でコンパイルしようとすると、
sakae@pen:/tmp/lhades$ make g++ -std=c++1y -I -o src/proto.o -c src/proto.cpp g++: error: src/proto.o: No such file or directory make: *** [Makefile:16: src/proto.o] Error 1
こういう、わけわかめなエラーになる。Makefileを見ても素直な奴に思える。いや、眼をこらして見ると、
$(CXX) $(CFLAGS) -I$(LUA_INCDIR) -o $@ $^
この LUA_INCDIR
は何? こういう変数を使われてしまうと、困っちゃうぞ。
sakae@pen:/tmp/lhades$ cat lhades-0.1-1.rockspec : build = { type = "make", build_variables = { LUA_INCDIR = "$(LUA_INCDIR)", },
luarocksが、無駄な介入をしてるっぽい。
sakae@pen:/tmp/lhades$ LUA_INCDIR=/usr/local/include make g++ -std=c++1y -I/usr/local/include -o src/proto.o -c src/proto.cpp : g++ -std=c++1y -I/usr/local/include -o lhades src/proto.o src/reader.o src/upvalue.o src/writer.o src/code.o src/header.o src/constant.o src/main.o src/debug_info.o
g++の非常に不親切(それが伝統よ)なエラー表示によって、無駄な労力を要求されるってどうよ。それを解消する為に luarocks が有るとすれば、情けない限りだ。これが、LinuxとWindows屋の労力削減に役だっているんだな。ブラックボックス増長に断固反対します。
rubyと疎遠になったのも、gemなんて言う余計な奴が幅を利かせるタイミングだったな。
socket
luarocksを入れた時、お試しでsocketパッケージも入れた(ってか、指示通りにしたら入ってしまったのが真相)。折角なんで探ってみる。
sakae@pen:/usr/local/lib/luarocks/rocks-5.3/luasocket/3.0rc1-2$ ls doc etc luasocket-3.0rc1-2.rockspec rock_manifest samples test
gitで提供されてる部分を保存してくれているんだな。ちょいと試してみるか。
sakae@pen:samples$ lua echosrvr.lua 127.0.0.1 2929 Binding to host '127.0.0.1' and port 2929... Waiting packets on 127.0.0.1:2929... timeout timeout Echoing 'hello' to 127.0.0.1:49192
まずサーバーを起動。パケットが届かないと、しびれをきらして、timeoutなんて言って来るのね。はいはい、クライアントを立ち上げますよ。
sakae@pen:samples$ lua echoclnt.lua localhost 2929 Using remote host '127.0.0.1' and port 2929... hello hello
どんなコードになってるか、覗き見。
local socket = require("socket") : assert(udp:settimeout(5)) ip, port = udp:getsockname() assert(ip, port) print("Waiting packets on " .. ip .. ":" .. port .. "...") while 1 do dgram, ip, port = udp:receivefrom() if dgram then print("Echoing '" .. dgram .. "' to " .. ip .. ":" .. port) udp:sendto(dgram, ip, port) else print(ip) end end
サーバーの主要部分は、こんな感じ。5秒待ってパケが来ないと文句を言うようにしてるのね。luaで文字列の連結は、".." だ。そしてperlっぽく、数値はその場で佳きに計らえで文字列に変換される。(逆に文字列を数字に自動変換する場合もある)
socketのパッケージは、coreの部分がC語で書いてあり、それがコンパイルされてcore.soとかになり、/usr/local/lib/lua/5.3/socket に置かれている。 スピードが必要無い、緩い部分は、/usr/local/share/lua/5.3 に鎮座してる。
こういう土地勘が大事だぞ。