「Go/Goのプログラムがどんなアセンブリにコンパイルされるか?」の版間の差分

削除された内容 追加された内容
Ef3 (トーク | 投稿記録)
init.
タグ: 2017年版ソースエディター
 
Ef3 (トーク | 投稿記録)
→‎Goのプログラムがどんなアセンブリにコンパイルされるか?: go tool compie でオブジェクトファイルをカレントディレクトリーに生成するようにした。
タグ: 2017年版ソースエディター
18 行
 
:<syntaxhighlight lang=shell>
% go buildtool -xcompile -worko hello.o hello.go
WORK=/var/tmp/go-build4052974754
mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=/home/user1/.cache/go-build/6c/6c139aebf3f27b01d1c318b381b3a00a6cafdd72ce1335188a6c965aae4adbd9-d
<snip/>
</syntaxhighlight>
: <code>hello.o</code>にコンパイル結果が出力されますが、これは。
: /var/tmp/go-build4052974754 以下にコンパイル結果が出力され -work オプションが与えられているのでコンパイル後も削除されません(キャッシュされるので適宜 -a でキャッシュクリアする必要があるかもしれません)。
:<syntaxhighlight lang=shell>
% file fibo.o
% find /var/tmp/go-build4052974754/ -name _pkg_.a
fibo.o: current ar archive
/var/tmp/go-build4052974754/b001/_pkg_.a
</syntaxhighlight>
_pkg_.aがパッケージar(1) コンパアーカル結果です。
:<syntaxhighlight lang=shell>
% ar tv hello.o
% go tool objdump -S /var/tmp/go-build4052974754/b001/_pkg_.a > main.objdump
rw-r--r-- 0/0 92 Jan 1 09:00 1970 __.PKGDEF
rw-r--r-- 0/0 6447 Jan 1 09:00 1970 _go_.o
</syntaxhighlight>
展開してみても
: go tool objdump は Go の逆アセンブラーで -S はソースも併せて表示するオプションです
;main.objdump:<syntaxhighlight lang=c-objdumpshell>
% ar xv hello.o
TEXT main.main(SB) gofile../home/eguchi/Go/hello/hello.go
x - __.PKGDEF
func main() {
x - _go_.o
0x194a 493b6610 CMPQ 0x10(R14), SP [2:2]R_USEIFACE:type.string [2:2]R_USEIFACE:type.*os.File
% file __.PKGDEF _go_.o
0x194e 7656 JBE 0x19a6
__.PKGDEF: data
0x1950 4883ec40 SUBQ $0x40, SP
_go_.o: data
0x1954 48896c2438 MOVQ BP, 0x38(SP)
</syntaxhighlight>
0x1959 488d6c2438 LEAQ 0x38(SP), BP
:と、素性はわかりませんが
fmt.Println("Hello, World")
: go tool objdump という Go の逆アセンブラーをこの形式を理解 きます(-S はソースも併せて表示するオプションです)。
0x195e 440f117c2428 MOVUPS X15, 0x28(SP)
:<syntaxhighlight lang=shell>
0x1964 488d1500000000 LEAQ 0(IP), DX [3:7]R_PCREL:type.string
% go tool objdump -S /var/tmp/go-build4052974754/b001/_pkg_hello.ao > mainhello.objdump
0x196b 4889542428 MOVQ DX, 0x28(SP)
</syntaxhighlight>
0x1970 488d1500000000 LEAQ 0(IP), DX [3:7]R_PCREL:main..stmp_0<1>
;hello.objdump:<syntaxhighlight lang=c-objdump>
0x1977 4889542430 MOVQ DX, 0x30(SP)
0x195e0x14b9 440f117c2428440f117c2440 MOVUPS X15, 0x280x40(SP)
0x19640x14bf 488d1500000000488d0500000000 LEAQ 0(IP), DXAX [3:7]R_PCREL:type.string
0x19540x14c6 48896c24384889442440 MOVQ BPAX, 0x380x40(SP)
0x19700x14cb 488d1500000000488d0500000000 LEAQ 0(IP), DXAX [3:7]R_PCREL:main""..stmp_0<1>
0x196b0x14d2 48895424284889442448 MOVQ DXAX, 0x280x48(SP)
return Fprintln(os.Stdout, a...)
0x197c0x14d7 488b1d00000000488b0500000000 MOVQ 0(IP), BXAX [3:7]R_PCREL:os.Stdout
0x19830x14de 488d0500000000488d0d00000000 LEAQ 0(IP), AXCX [3:7]R_PCREL:go.itab.*os.File,io.Writer
0x198a0x14e5 488d4c242848890c24 LEAQ 0x28 MOVQ CX, 0(SP), CX
0x198f0x14e9 bf010000004889442408 MOVLMOVQ $0x1AX, DI0x8(SP)
0x19940x14ee 4889fe488d442440 LEAQ MOVQ DI0x40(SP), SIAX
0x19970x14f3 e8000000004889442410 CALLMOVQ 0x199cAX, [1:5]R_CALL:fmt.Fprintln0x10(SP)
0x14f8 48c744241801000000 MOVQ $0x1, 0x18(SP)
0x1501 48c744242001000000 MOVQ $0x1, 0x20(SP)
0x19b10x150a c3e800000000 CALL 0x150f RET [1:5]R_CALL:fmt.Fprintln
}
0x199c0x150f 488b6c2438488b6c2450 MOVQ 0x380x50(SP), BP
0x19a10x1514 4883c4404883c458 ADDQ $0x400x58, SP
0x19a50x1518 c3 RET
func main() {
0x19a60x1519 0f1f4000e800000000 CALL 0x151e NOPL 0(AX) [1:5]R_CALL:runtime.morestack_noctxt
0x19aa0x151e e800000000e975ffffff CALLJMP 0x19af [1:5]R_CALL:runtime"".morestack_noctxtmain(SB)
0x19af eb99 JMP main.main(SB)
 
TEXT mainos.init(*File).close(SB) gofile.._gomod_.go<autogenerated>
 
0x19b1 c3 RET
0x19590x16de 488d6c2438488b442408 LEAQMOVQ 0x380x8(SP), BPAX
0x194e0x16e3 7656488b00 MOVQ 0(AX), JBE 0x19a6AX
0x19770x16e6 48895424304889442408 MOVQ DXAX, 0x300x8(SP)
0x19500x16eb 4883ec40450f57ff SUBQXORPS $0x40X15, SPX15
0x19af0x16ef eb99440f117c2410 MOVUPS X15, JMP main.main0x10(SBSP)
0x16f5 e900000000 JMP 0x16fa [1:5]R_CALL:os.(*file).close
</syntaxhighlight>
: ターゲットは AMD64 なのですが、あまり見慣れないニーモニックだと思います。
73 ⟶ 83行目:
: 演算や転送の幅は SUB'''Q''' や MOV'''L''' のようにオペレーションの末尾の文字で指定されます。
 
よく見ると、ソースの mtfmt.Println("Hello, World") が、fmt.Fprintln(os.Stdout,) に置き換えられておりインライン展開が行われていることがわかります。
 
Goはコンパイラーですが、コンパイラー自身もGoで書かれソースコードを含んで配布されており、他にも
 
go tool nm
go tool pack
の様なハウスキーピング用のコマンドがあります(機会を見て紹介します)。
 
{{Nav}}
== 脚註 ==
<references />