続々々々々続GShell − 動的リンク

開発:さて今日は、GShellの動的リンク機能にチャレンジしたいと思います。

社長:タイムスリッパでやってたのがちょうど一ヶ月前ですね。

開発:それがもう、恐ろしいくらいに何も覚えてないのですが、ブログと、残されたコードを頼りにして行きたいと思います。

基盤:一ヶ月前というとあの血染めの帰宅の頃ですが、あの時脳震盪で記憶が飛んだとか?

開発:それでまず、Goプログラム自体を動的リンクモードで生成するという話が気になっていたのでこれを…

開発:そうですか。ではLinuxで。

社長:尋常では無い遅さですね。

開発:gshell自体に1度だけ動的リンクしようという話と方向違いですからね。毎回動的リンクをやってるわけで。まあでも、macOSだと3ミリ秒のところが、Linuxなら1ミリ秒で起動するようです。

開発:さてそれで、発掘しましたタイムスリッパ。7月13日05:50のタイムスタンプのあるlibgasket.so.1 です。これをかませてやると1970年にタイムスリップするはず…

開発:あれ?

基盤:しないですね。

開発:そういえばmacOSの場合には、ビルド時になにかやる必要があったような…

社長:いや、Jan 1 09:10:44 (1970) にスリップしてるんでは。

開発:あそうか… /bin/dateは動的ライブラリでスリップしてくれないという話でしたね。というか、さっきから DYLD_ 設定しなくても勝手にスリップするんですが… かと思うと他の端末ではそういう事はない…

社長:動的ライブラリのキャッシュっぽいですね。

開発:確かに。タイムスリッパ版 gettimeofday がキャッシュされていると思われるような症状です… そういえば DYLD_ほにゃららにキャッシュを無効にするというのがあったような… man dyld。まずはトレースですね。DYLD_PRINT_LIBRARIES= DYLD_PRINT_BINDINGS= gsh ・・・

基盤:うわわわ…

開発:発見しました。

社長:なるほど。macOSでは動的ライブラリが細分されているんですごい数をロードする、それで起動に3ミリ秒もかかるということですかね。

開発:ちょっと邪魔なのでdyldの出力は別ファイルに出します。 DYLD_PRINT_TO_FILE=dylog。うーむ、起動するまでに120ファイルの .dyld をロードしてます。1ファイル25マイクロ秒でロードできちゃってると… まあ、オンメモリだからなんでしょうけど。

基盤:macos dyld cache clear で検索。どうも実体は /private/var/db/dyld の下にありますね。1.4GBもあるんだがどうしたらいいんだみたいな質問が。うちのMacMiniはどうかと言うと…

一同:(苦笑)

基盤:でもこの中にgasketは無いんですよね。これはシステムのdylib専用のキャッシュなんですかね?こっちは3ヶ月使ってきたMacMiniですが、まだあんまり活動してない iMacはというと。

開発:タイムスタンプも大きさもほぼ同じですね。要するに Catalina 10.15.6 に共通ということですかね。何が違うんでしょう?

基盤:.map のdiffを取ると、まあアドレスは連鎖的に変わるでしょうけど、大きな違いは2つdylibが加わったということのようです。

社長:で、プライベートなキャッシュはどこにあるんですかね。端末というか、セッションごとにあるように見えますが。

基盤:ところでこのdyldって、なんて読むんですかね。ディル… って読むとヤバいと思うんですがw

開発:単にダイエルディーって読んでましたが。

開発:ああそれで、dyldinfo -bind gsh で、動的にリンクされているシンボルを眺めたのですが、やはり差し替えたら面白いと思うのは、ファイル名を解釈する部分、つまり openとexecveかなと思います。ホスト名についてはgetaddrinfoとgetpeername。これで名前空間をいじって簡易マウントする。それから、出力をteeしちゃうという意味ではwriteとsend。入力をteeするという意味では read と recvfrom。

社長:端末入出力の記録がわかりやすいので、read / write から行きましょう。

開発:了解。ではまず、gettimeofdayのラッピングは外して…

基盤:今日に戻りました(^-^)

開発:ああ、どうもGoで区切り記号を省略する癖がついてCでもやっちゃいますねw。むむ、read をラップして __read を呼ぶという戦法は Macのリンカーには通じないのかな… とりあえず read としてエラーを返すことにします。こんな感じ。

開発:で、これを動的ライブラリにしてgshにリンクさせると。

基盤:入れ替わってますね。

開発:さてでは、どうやって本物に中継するかですが。システムコールなら syscall でイケばy位とは思いますが。

基盤:7/12のタイムスリッパでも、Linux は func を入れ替えて本物は __funcを呼ぶでイケる、macOSは不明なのでペンディングということになってますね。

開発:うーん、dyldinfo を見ても、__ を前置するという流儀のように見えるんですが…

基盤:なんとなく、macOS固有の拡張シンボルにつけてるようにも見えますが。

社長:なんにしても、動的ライブラリがシンボルとしてエクスポートしてないとどうにもならないですね。

開発:Linux GCCではどうなっているかと言うと…

開発:この i というのは GNU の拡張で indirection とかの意味だそうです。あるいは、read 関係。

社長:もともと Weak になってたりするんですね。というか、fread は差し替えたら自作しなさいってことですかね??

開発:ポリシーが全くわからないですね。そもそもどういう意図でこういう2種類を提供しているのかも。

開発:どうも macOSでも同じような感じですね。タイムスリッパのgettimeofdayがうまく行ったのはこうなっていたから。

開発:一方で read はこんな感じなのでダメ。

開発:あれ?でも libsystem_c.dylib にはやっぱり、___symbol シリーズがありますね。ほとんどのシステムコールに… なぜ read には無いのか?あ、これですかね?

社長:その noncancel 版の仕様が公開されているかですが… というか、readv を呼ぶのが一番簡単では。

開発:そうですね。これでどうかな。

開発:でもってgshを起動…

基盤:大成功!

開発:明るい未来が見えた気がした。

社長:いけそうですね。

開発:どうもmacOSの動的ライブラリのキャッシュの挙動がわからないですが、原理的には問題ないようですね。

* * *

社長:帰りました。外は今日は普通に夏日よりでした。

社長:きょうはひや麦でした。あれは、カップ麺では実現できない世界ですね。

基盤:室内も34.4度にとどまっています。

社長:ところてんを買ってきました。冷蔵庫で冷やして食べましょう。

経理:その冷蔵庫なんですが、少し深刻な事態に。これを見て下さい。

経理:昨日までの3日間ですが、一昨日に冷蔵庫の電源を入れる前は200W+、一昨日は洗濯機の稼働もありましたが、昨日の様相を見ると300Wには達していると見られます。つまり、冷蔵庫が100W消費しているのではないかと。

開発:まあ100Wで生活が豊かになるならそれはそれで良いかなとも思いますけどね。

基盤:ところでさきほどベランダに打ち水というか、バケツ一杯の水をぶちまけたのですが、0.1度ばかり室温が下がったように見えます。

* * *

社長:さてそれでは、動的ライブラリをリンクして呼び出すのをやってみましょうかね。

開発:それが、syscall に dlopen が無いようなのです…

社長:そういえば、たしかに関数名や変数名が動的にリンクできたとしても、相手とスタックの構造が違うとどうなるんだという事はあるかもですね。

開発:ですが、これまでやったように、gettimeofdayやらreadやらのCのライブラリは普通に動的リンクできて呼び出せちゃうわけなんですが…

社長:つまりわれわれとしては、何かのCの標準関数のふりをして繋がる作戦ですか。

開発:標準的には pluginというパッケージがあるようではあります。これだと、通常のgoプログラムが取り込める。で、ソースファイルに書いてある例のとおりにやったのですが、なぜか関数名をリゾルブしてくれないんです。go build -buildmode=plugin hello.go とすると hello.so という動的ライブラリが出来るので、nm hello.soで見てみるわけですが、その関数名が出てこない。

関数:それでもういちど例をじっと眺めたのですが、例では関数名が大文字なんですね。まさかと思って大文字にしたら、通りましたw。つまり、Goでは大文字で始まる名前だけがエクスポートされるっていう流儀なんだと思います。で、こんなふうになりました。

開発:一度目の呼び出しはいつものように3ミリ秒かかっていますが、2度目以降は100マイクロ秒以下で終わっています。

基盤:やった!30倍速

開発:まあ、2回目以降はいきなりプロセス内部での呼び出しですからね。

開発:ちなみに中身はこのようなものです。

社長:素晴らしい。これなら、内部コマンド同様に使えますね。内部コマンドでも30usくらいかかりますからね。100マイクロ秒なら、大粒の内部関数としても使えるレベルでしょう。うーむ素晴らしい。お祝いにスイカを食べましょう。

開発:まあ、内部の関数と同様に仕様を記述して普通に呼び出せればもっと良いのですけどね。

* * *

基盤:今朝方WordPressを5.5に上げたのですが、こんな事になっちゃいましたね。

開発:青の時代が終わった。

社長:いやそれで、前々からインライン画像の配置のデフォルトが中央寄せで無いのが嫌だったのですが、5.5から中央寄せになりましたね。ところが私はこういう端末画面の貼り付けは左詰めにしようと最近決めたのです。ところが、左詰めに変更すると次の段落が右の隙間に入り込むようになっちゃって、なんというかWordPress本体による破壊テロかと。

基盤:まあ、短い段落にインライン画像を時々はさむだけの編集機能でしたら、別にWordPressでなくても、なんでもいいっちゃいいんですよね。

— 2020-0813 SatoxITS