runtime of golang

サポート中

面白いWebを見つけたので友人に紹介した所、重くてとても見る気にならないと言われた。 オイラーの所では、何の苦もなく見られるんだけどなあ。ひょっとして、ネットが遅くなっていないかい?

https://www.google.com/search?client=firefox-b-d&q=speed+test

https://www.speedtest.net/ja

https://fast.com/ja/

https://speedtest.gate02.ne.jp/

こんなのを紹介してテストして貰った。下りは10Mぐらい。時間帯によっては、2Mぐらいとの事。何それ、ひと昔のADSL並みじゃん。KDDIの光回線らしい。 友人は、3密(へへ、今年の流行語大賞だな)エリアに住んでいる。超渋滞、みんな会社に行かないで、家でZoomの人達が、回りにわんさかいるのかな?

ひょっとしてWiFiが混信してるかな? 一応潰しておいて貰おう。一番簡単なのは、無線接続を止めて、有線接続でどうか確認してもらう事。生活スタイルが変わって、パソコンの設置場所を変えた時、Wifiにしたって言ってたから、まだLANケーブルを所有してるかも。

若し持っていないようなら買ってきてテストする? ちょいと無駄っぽい。混信してるか、パソコンにモニターを入れてもらうのがいいけど、気軽に勧められないな。一度WiFiの親機の電源をOFFにしてもらって、再起動してどうか? 

高級なWiFiだと、自動的に混信を避けてくれるだろうけど、多分そんなの使っていないだろう。 再起動時に、電波状況をスキャンして、空いてる所で通信を始めるはずだから、それでどうなるかだな。

もしかしたら、プロバイダーが意地悪してないか? 局内にある光モデムを束ねてる所で、同じサブネットに属するユーザーが無茶をするから、シェーピングしちゃえとか。

情報の流れを電流に置き換えると、要するインピーダンスを上げる操作をしてないかって事だ。 そうすれば、無理を封じ込める事が出来るからね。

一般人に分かるようなたとえだと、一部のジャンクションで、交通規制が行われています。その影響で、下り線の流れが滞っております。渋滞を避けてのご利用をお願い致します。

今年は、コロナで、田舎の親から帰って来るな宣告を突きつけられている人も居ると聞いている。こういう、何時もの渋滞情報が流れるのだろうか?

と言う事で、サポートはまだまだ続く。。。

超優れもののgolang

前回、ダイナミックロードを調べていた時、ランタイムを内蔵したアプリを作るシステムとして、golangが有る事を思い出した。

自前のランタイムを内蔵してるんで、アプリを一つ持って行くだけで、どんな所でも動く。 どんな所でもって、例えばLinux上で開発してたのをWindowsに持って行って動くのか? さすがにそれは無理。

でも、一手間かければ、それが可能になる。いわゆるクロスコンパイルね。以前実際にやって、動く事を確認してる。クロスコンパイル環境って作るの大変では?

そんな事は全く無い。golang自体に、クロスコンパイル環境を内包してるからね。 https://golang.org/dl/ から落としてきた物だけで、用が足りる。素晴らしいシステムだよ。

ob$ go version
go version go1.15.2 openbsd/amd64
ob$ GOOS=windows GOARCH=amd64 go build main.go
ob$ ls
main.exe* main.go
ob$ file main.exe
main.exe: MS-DOS executable PE  for MS Windows (console) Mono/.Net assembly

久しぶりに使ってみるか、ハロワじゃつまらないので、 https://golang.org/pkg/net/http/#pkg-examples にあるGetを試す事にします。ぐぐるのスパイダー・ロボット向け契約文書の取り出し。

ob$ go build main.go
ob$ gdb -q main
Reading symbols from main...done.
Loading Go Runtime support.
(gdb) b main.main
Breakpoint 1 at 0x644d80: file /tmp/main.go, line 10.
(gdb) r
Starting program: /tmp/main
[New thread 387631]
[New thread 298157]
[New thread 478028]
[New thread 356557]
[New thread 273783]

Thread 1 hit Breakpoint 1, main.main () at /tmp/main.go:10
10      func main() {
(gdb) n
11              res, err := http.Get("http://www.google.com/robots.txt")
(gdb) s
net/http.(*Client).Get (c=0x87ed40, url="http://www.google.com/robots.txt",
    resp=<optimized out>, err=...) at /usr/local/go/src/net/http/client.go:470
470     func (c *Client) Get(url string) (resp *Response, err error) {
(gdb)
471             req, err := NewRequest("GET", url, nil)
(gdb)
net/http.NewRequest (method=..., url="http://www.google.com/robots.txt",
    body=...) at /usr/local/go/src/net/http/request.go:813
813             return NewRequestWithContext(context.Background(), method, url,body)
(gdb) bt
#0  net/http.NewRequest (method=..., url="http://www.google.com/robots.txt",
    body=...) at /usr/local/go/src/net/http/request.go:813
#1  net/http.(*Client).Get (c=0x87ed40,
    url="http://www.google.com/robots.txt", resp=<optimized out>, err=...)
    at /usr/local/go/src/net/http/client.go:471
#2  0x0000000000644dd4 in net/http.Get (url=..., resp=<optimized out>, err=...)
    at /tmp/main.go:11
#3  main.main () at /tmp/main.go:11

特別な事をしなくても、gdbが使えちゃった。正式には、下記を見ておけばおk。

https://golang.org/doc/gdb

GDBを使用してデバッグする

golangのruntime

上で見た、クロスコンパイルは、どんなOSや石に対して実行出来るの? きっとそれはggしたら得られるでしょう。オイラーはそんなのに頼らない。ソース嫁。

src/runtile辺りを見れば良いかな。

debian:runtime$ ls rt0_*
rt0_aix_ppc64.s        rt0_js_wasm.s        rt0_netbsd_arm64.s
rt0_android_386.s      rt0_linux_386.s      rt0_netbsd_arm.s
rt0_android_amd64.s    rt0_linux_amd64.s    rt0_openbsd_386.s
rt0_android_arm64.s    rt0_linux_arm64.s    rt0_openbsd_amd64.s
rt0_android_arm.s      rt0_linux_arm.s      rt0_openbsd_arm64.s
rt0_darwin_amd64.s     rt0_linux_mips64x.s  rt0_openbsd_arm.s
rt0_darwin_arm64.s     rt0_linux_mipsx.s    rt0_plan9_386.s
rt0_dragonfly_amd64.s  rt0_linux_ppc64le.s  rt0_plan9_amd64.s
rt0_freebsd_386.s      rt0_linux_ppc64.s    rt0_plan9_arm.s
rt0_freebsd_amd64.s    rt0_linux_riscv64.s  rt0_solaris_amd64.s
rt0_freebsd_arm64.s    rt0_linux_s390x.s    rt0_windows_386.s
rt0_freebsd_arm.s      rt0_netbsd_386.s     rt0_windows_amd64.s
rt0_illumos_amd64.s    rt0_netbsd_amd64.s   rt0_windows_arm.s

darwinってのはMacの事だな。plan9は、あの人の20%ルールでの成果を役得で反映したのかな。リナには早々とriscv64なんていう石が登録されてる。

たまたま、rt0な接頭語のファイルを挙げてみたけど、他にもsysで始まるファイル群がある。 一つ選んで覗いてみるか。 sys_openbsd_386.s

TEXT runtime·mmap(SB),NOSPLIT,$36
        LEAL    addr+0(FP), SI
        LEAL    4(SP), DI
        CLD
        MOVSL                           // arg 1 - addr
        MOVSL                           // arg 2 - len
        MOVSL                           // arg 3 - prot
        MOVSL                           // arg 4 - flags
        MOVSL                           // arg 5 - fd
        MOVL    $0, AX
        STOSL                           // arg 6 - pad
        MOVSL                           // arg 7 - offset
        MOVL    $0, AX                  // top 32 bits of file offset
        STOSL
        MOVL    $197, AX                // sys_mmap
        INT     $0x80
        JAE     ok
        MOVL    $0, p+24(FP)
        MOVL    AX, err+28(FP)
        RET
ok:
        MOVL    AX, p+24(FP)
        MOVL    $0, err+28(FP)
        RET

ちょっと長いけど、mmapのシステムコールを実現してるユーザーランド側のコードだな。 こういう風に、前回の記事を引きずっているって、なんかしりとりゲームみたい。

他のソースもチラ見したけど、このランタイムは、置かれた環境(OSとCPUの種別)を選ばない、ブルトーザーみたいな奴なんだな。このおかげで、クロスコンパイルと協力して、どこでも動くんだな。

でも、インプリメントされてるシステムコールを精査すると、余りに少ない事に気が付く。例えば、ネット系で必須の、socketとかconnect等がここには無いのだ。

まあ、ネット系はWeb屋さん向けなんで、それは別パッケージで対応しましょう。runtimeは、せいぜいC語で言うlibcのサブセットぐらいなんでしょう。何から何まで抱え込んでしまうと、バイナリーが肥大化しますから。

じゃ、ネット系を使った時はどうなる?

over runtime

例に有った、http.Getだけど、キーは下記の一分

res, err := http.Get("http://www.google.com/robots.txt")

ぐぐるに繋いで、ファイルを一つ取ってこい。細かい事はいいからさ。でもプログラムは細かい部分が無いと動かない。きっと、システムコールも、出来たバイナリーに内包されているんだろう。

golangのシステムには、開発環境が日照り?のWindows向けに、pkg/toolが用意されてる。

debian:linux_386$ ls
addr2line*  cgo*      dist*  link*     pack*       trace*
asm*        compile*  doc*   nm*       pprof*      vet*
buildid*    cover*    fix*   objdump*  test2json*

例えば、objdumpってどう使うかは、こう調べる

debian:linux_386$ go doc cmd/objdump
Objdump disassembles executable files.

Usage:

    go tool objdump [-s symregexp] binary

Objdump prints a disassembly of all text symbols (code) in the binary. If
the -s option is present, objdump only disassembles symbols with names
matching the regular expression.
    :

これが分かれば、Windowsなユーザーでも

debian:t$ go tool nm main | grep socket
 817bdc0 T net.socket
 840ffbc D net.socketFunc
 80d6510 T syscall.rawsocketcall
 82d4a48 r syscall.rawsocketcall.args_stackmap
 80d4a10 T syscall.socket
 80d64c0 T syscall.socketcall
 82d4a58 r syscall.socketcall.args_stackmap

えっ、Windowsにはまともなgrepが無い? これぐらいならfindで用が足りるのかな? unixユーザーなら、go toolのお世話にならなくても、普通にnmすれば良い。ちゃんとunixのマナーに沿っていますからね。

そんじゃ、お楽しみのやつ

debian:t$ gdb -q main
Reading symbols from main...
warning: Unsupported auto-load script at offset 0 in section .debug_gdb_scripts
of file /tmp/t/main.
Use `info auto-load python-scripts [REGEXP]' to list them.
(gdb) b syscall.socket
Breakpoint 1 at 0x80d4a10: file /usr/local/go/src/syscall/syscall_linux_386.go,line 276.
(gdb) r
Starting program: /tmp/t/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
[New Thread 0xa7b11b40 (LWP 24724)]
[New Thread 0xa7310b40 (LWP 24725)]
[New Thread 0xa67ffb40 (LWP 24726)]
[New Thread 0xa5ffeb40 (LWP 24727)]

Thread 1 "main" hit Breakpoint 1, syscall.socket (domain=2, typ=526338,
    proto=0, fd=<optimized out>, err=...)
    at /usr/local/go/src/syscall/syscall_linux_386.go:276
276     func socket(domain int, typ int, proto int) (fd int, err error) {

何処を見ろと教えてくれるのが貴重な資料になるねぇ。

(gdb) bt
#0  syscall.socket (domain=2, typ=526338, proto=0, fd=<optimized out>, err=...)
    at /usr/local/go/src/syscall/syscall_linux_386.go:276
#1  0x080d5351 in syscall.Socket (domain=2, typ=526338, proto=0,
    fd=<optimized out>, err=...)
    at /usr/local/go/src/syscall/syscall_unix.go:346
#2  0x0817b9d0 in net.sysSocket (family=2, sotype=2, proto=0,
    ~r3=<optimized out>, ~r4=...) at /usr/local/go/src/net/sock_cloexec.go:21
#3  0x0817bdf5 in net.socket (ctx=..., net=..., family=2, sotype=2, proto=0,
    ipv6only=false, laddr=..., raddr=..., ctrlFn=
    {void (string, string, syscall.RawConn, error *)} 0x88ce9ac,
    fd=<optimized out>, err=...) at /usr/local/go/src/net/sock_posix.go:19
#4  0x08175eda in net.internetSocket (ctx=..., net=..., laddr=..., raddr=...,
    sotype=2, proto=0, mode=..., ctrlFn=
    {void (string, string, syscall.RawConn, error *)} 0x88ce9f0,
    fd=<optimized out>, err=...) at /usr/local/go/src/net/ipsock_posix.go:141
#5  0x0817fe56 in net.(*sysDialer).dialUDP (sd=0x887c5a0, ctx=..., laddr=0x0,
    raddr=0x8844e20, ~r3=<optimized out>, ~r4=...)
    at /usr/local/go/src/net/udpsock_posix.go:98
#6  0x08168ca6 in net.(*sysDialer).dialSingle (sd=0x887c5a0, ctx=..., ra=...,
    c=..., err=...) at /usr/local/go/src/net/dial.go:583
#7  0x08168281 in net.(*sysDialer).dialSerial (sd=0x887c5a0, ctx=..., ras=...,
    ~r2=..., ~r3=...) at /usr/local/go/src/net/dial.go:548
#8  0x08167790 in net.(*Dialer).DialContext (d=0x88cec44, ctx=...,
    network=..., address=..., ~r3=..., ~r4=...)
    at /usr/local/go/src/net/dial.go:425
    :

そして何時もの、追跡調査。

(gdb) info th
  Id   Target Id                            Frame
 * 1    Thread 0xb7fd05c0 (LWP 24720) "main" syscall.socket (domain=2,
    typ=526338, proto=0, fd=<optimized out>, err=...)
    at /usr/local/go/src/syscall/syscall_linux_386.go:276
  2    Thread 0xa7b11b40 (LWP 24724) "main" runtime.usleep ()
    at /usr/local/go/src/runtime/sys_linux_386.s:164
  3    Thread 0xa7310b40 (LWP 24725) "main" runtime.futex ()
    at /usr/local/go/src/runtime/sys_linux_386.s:503
  4    Thread 0xa67ffb40 (LWP 24726) "main" runtime.futex ()
    at /usr/local/go/src/runtime/sys_linux_386.s:503
  5    Thread 0xa5ffeb40 (LWP 24727) "main" 0xb7e9d6c4 in clone ()
   from /lib/i386-linux-gnu/libc.so.6

スレッドで協力し合ってるのか。

to Windows

debianで作ったやつを、Windows10へ持って行く

debian:t$ go version
go version go1.15.6 linux/386
debian:t$ GOOS=windows GOARCH=amd64 go build main.go

ちゃんとWindows10でも実行出来たよ。ならば

sakae@atom:/mnt/c/work$ gdb -q main.exe
Reading symbols from main.exe...done.
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
of file /mnt/c/work/main.exe.
Use `info auto-load python-scripts [REGEXP]' to list them.
(gdb) b syscall.connect
Breakpoint 1 at 0x4a7360: file /usr/local/go/src/syscall/zsyscall_windows.go, line 1475.
(gdb) r
Starting program: /mnt/c/work/main.exe
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x4a7360

(gdb)

生まれた所のソースの在処が埋め込まれているのね。あっ、gdbを普通に使っちゃったけど、WSLのやつね。やっぱり微妙なやつは駄目なのね。

sakae@atom:/mnt/c/work$ go.exe build main.go
sakae@atom:/mnt/c/work$ gdb -q main.exe
Reading symbols from main.exe...done.
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
of file /mnt/c/work/main.exe.
Use `info auto-load python-scripts [REGEXP]' to list them.
(gdb) b syscall.connect
Breakpoint 1 at 0x48f240: file C:/Go/src/syscall/zsyscall_windows.go, line 1475.
(gdb) r
Starting program: /mnt/c/work/main.exe
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x48f240

(gdb)

ひょっとしたら、Windows環境でコンパイルすれば、、、と思って試してみたけど、やっぱり駄目だったわい。どうしてもdebugしたいなら、 Golang開発環境構築 - Windows10 / VisualStudioCode この辺りなのかなあ。面倒過ぎるんで、ここまで凝らなくてもいいか。 Windows用の開発環境を一つ選べと言われたら、きっとgolangだけを入れて、それを裸で使うでしょうね。


This year's Index

Home