Go/Goのプログラムがどんなアセンブリにコンパイルされるか?
表示
< Go
Goのプログラムがどんなアセンブリにコンパイルされるか?
[編集]Goは簡素化された構文とキャッシュの使用により、非常に高速にコンパイルされますが、(中間コードではなく)ネイティブな機械語を生成します。
では、実際にどのようなコードが生成されるかを検証してみましょう。
Hello, World を逆アセンブル
[編集]- hello.go
package main import "fmt" func main() { fmt.Println("Hello, World") }
上のような単純で完全なプログラム hello.go を用意します。
% % go build hello.go
helloにコンパイル結果が出力されます。- go tool objdump という Go の逆アセンブラーは、実効形式を理解できます(-S はソースも併せて表示するオプションです)。
% go tool objdump -S -s main.main hello > hello.objdump
- hello.objdump
TEXT main.main(SB) /home/eguchi/tut/go/hello.go func main() { 0x48fd80 493b6610 CMPQ SP, 0x10(R14) 0x48fd84 7646 JBE 0x48fdcc 0x48fd86 55 PUSHQ BP 0x48fd87 4889e5 MOVQ SP, BP 0x48fd8a 4883ec38 SUBQ $0x38, SP fmt.Println("Hello, World") 0x48fd8e 488d156b970000 LEAQ 0x976b(IP), DX 0x48fd95 4889542428 MOVQ DX, 0x28(SP) 0x48fd9a 488d15076d0400 LEAQ 0x46d07(IP), DX 0x48fda1 4889542430 MOVQ DX, 0x30(SP) return Fprintln(os.Stdout, a...) 0x48fda6 488b1dbb9b0c00 MOVQ os.Stdout(SB), BX 0x48fdad 488d05f4720400 LEAQ go:itab.*os.File,io.Writer(SB), AX 0x48fdb4 488d4c2428 LEAQ 0x28(SP), CX 0x48fdb9 bf01000000 MOVL $0x1, DI 0x48fdbe 4889fe MOVQ DI, SI 0x48fdc1 e8baafffff CALL fmt.Fprintln(SB) } 0x48fdc6 4883c438 ADDQ $0x38, SP 0x48fdca 5d POPQ BP 0x48fdcb c3 RET func main() { 0x48fdcc e80faafdff CALL runtime.morestack_noctxt.abi0(SB) 0x48fdd1 ebad JMP main.main(SB)
- ターゲットは AMD64 なのですが、あまり見慣れないニーモニックだと思います。
- これは、Plan9 のアセンブラフォーマットでIntelともAT&Tとも違います。
- レジスタは8086の頃にあったものならば8086当時の名前で、AMD64で追加されたレジスタはRnnの形式で表示されます。
- 演算や転送の幅は SUBQ や MOVL のようにオペレーションの末尾の文字で指定されます。
Goはコンパイラーですが、コンパイラー自体がGoで書かれ、ソースコードとともに配布されており、他にも
go tool nm
や
go tool pack
の様なハウスキーピング用のコマンドがあります(機会を見て紹介します)。
脚註
[編集]
参考文献
[編集]- “A Quick Guide to Go's Assembler”. 2021年10月22日閲覧。