[インデックス 13316] ファイルの概要
このコミットは、Goコンパイラ(cmd/gc)におけるアセンブリ出力の挙動を変更するものです。具体的には、-Sフラグによるアセンブリ出力からデータセクションの逆アセンブルを除外し、データセクションの出力は新しい-SSフラグに限定するように変更しています。これにより、-Sフラグがよりコードの逆アセンブルに特化し、その有用性が向上することを目的としています。
コミット
commit b185de82a4e2b8982e5a6c211a436b749a9735c4
Author: Russ Cox <rsc@golang.org>
Date: Thu Jun 7 12:05:34 2012 -0400
cmd/gc: limit data disassembly to -SS
This makes -S useful again.
R=ken2
CC=golang-dev
https://golang.org/cl/6302054
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b185de82a4e2b8982e5a6c211a436b749a9735c4
元コミット内容
cmd/gc: limit data disassembly to -SS
This makes -S useful again.
変更の背景
Goコンパイラには、生成されたアセンブリコードを表示するための-Sフラグが存在します。しかし、このフラグがコードだけでなくデータセクション(初期化されたグローバル変数など)の逆アセンブルも出力するようになっていたため、出力が冗長になり、純粋なコードの挙動を追跡する際に不便が生じていました。特に、大規模なプログラムではデータセクションの出力が非常に大きくなり、コードの分析を妨げる可能性がありました。
このコミットの目的は、-Sフラグの出力をコードのみに限定することで、その本来の目的である「コードの逆アセンブル表示」としての有用性を回復させることにあります。データセクションの逆アセンブルが必要な場合には、新たに導入される-SSフラグを使用するように分離することで、ユーザーが目的に応じて適切な粒度でアセンブリ出力を得られるように改善されています。
前提知識の解説
Goコンパイラ (cmd/gc)
Go言語の公式コンパイラは、gc(Go Compiler)と呼ばれます。これは、Goのソースコードを機械語に変換する役割を担っています。cmd/gcは、Goのツールチェインの一部であり、go buildコマンドなどを介して間接的に利用されます。コンパイラは、ソースコードの解析、中間表現の生成、最適化、そして最終的な機械語コードの生成という一連のプロセスを実行します。
アセンブリ言語と逆アセンブル
- アセンブリ言語: コンピュータのプロセッサが直接実行できる機械語命令を、人間が理解しやすいニーモニック(例:
MOV,ADD,JMP)で表現した低水準プログラミング言語です。CPUのレジスタ操作やメモリへのアクセスなど、ハードウェアに近いレベルでの操作を記述します。 - 逆アセンブル (Disassembly): 機械語コードをアセンブリ言語に変換するプロセスです。これにより、コンパイル済みのバイナリがどのような機械語命令で構成されているかを人間が読み取れる形式で確認できます。デバッグ、パフォーマンス分析、セキュリティ分析などで利用されます。
コンパイラのデバッグフラグ (-S, -SS)
多くのコンパイラには、コンパイルプロセスや生成されるコードに関する詳細な情報を出力するためのデバッグフラグが用意されています。Goコンパイラの-Sフラグもその一つで、生成されたアセンブリコードを標準出力に出力するために使用されます。
-Sフラグ: このコミット以前は、Goコンパイラにおいて、生成されたアセンブリコード(命令)とデータセクション(初期化されたグローバル変数など)の両方を標準出力に逆アセンブルして表示する役割を担っていました。- データセクションの逆アセンブル: プログラムの実行に必要な静的なデータ(文字列リテラル、初期化されたグローバル変数、定数など)が格納されるメモリ領域の内容をアセンブリ形式で表示することです。
gobj.c ファイル
Goコンパイラのソースコードにおいて、gobj.c(例: src/cmd/5g/gobj.c, src/cmd/6g/gobj.c, src/cmd/8g/gobj.c)は、各アーキテクチャ(5gはARM、6gはx86-64、8gはx86-32など)に対応するオブジェクトファイル生成に関連する処理や、アセンブリ出力のロジックが含まれているC言語のソースファイルです。このファイル内で、-Sフラグが有効な場合にアセンブリを出力する処理が実装されています。
debug['S']
Goコンパイラの内部では、コマンドラインで指定されたデバッグフラグが、debugというグローバルなマップまたは配列のような構造体で管理されています。debug['S']は、-Sフラグが指定されたかどうか、またはその詳細レベルを示す値として使用されます。例えば、-Sが指定されればdebug['S']は1となり、-SSが指定されればdebug['S']は2となる、といった形で利用されます。
技術的詳細
このコミットの技術的な核心は、Goコンパイラのバックエンドにおけるアセンブリ出力ロジックの条件分岐の変更と、ドキュメントの更新にあります。
gobj.c における変更
変更は、src/cmd/5g/gobj.c, src/cmd/6g/gobj.c, src/cmd/8g/gobj.c の3つのファイルに共通して適用されています。これらのファイルは、それぞれ異なるCPUアーキテクチャ(ARM, x86-64, x86-32)に対応するコンパイラのバックエンド部分です。
変更前のコードは以下のようになっていました。
if(debug['S']) {
// ... アセンブリ出力ロジック ...
}
これは、-Sフラグが指定されていれば(debug['S']が真であれば)、コードとデータの両方のアセンブリを出力するという意味です。
変更後のコードは以下のようになっています。
// -S prints code; -SS prints code and data
if(debug['S'] && (pl->name || debug['S']>1)) {
// ... アセンブリ出力ロジック ...
}
この変更により、アセンブリ出力の条件がより厳密になりました。
debug['S']: これは、-Sまたは-SSフラグが指定されていることを示します。pl->name: これは、現在処理しているシンボルが関数(コード)である場合に真となる条件です。plはProgリスト(プログラム命令のリスト)の要素を指し、pl->nameはその命令が属する関数のシンボル名を示します。debug['S']>1: これは、-SSフラグが指定されていることを示します。Goコンパイラの内部では、-Sはdebug['S'] = 1、-SSはdebug['S'] = 2のように処理されることが一般的です。
したがって、新しい条件式 debug['S'] && (pl->name || debug['S']>1) は以下を意味します。
-
-Sフラグのみが指定された場合 (debug['S'] == 1):pl->nameが真の場合(つまり、現在のシンボルが関数コードの場合)にのみアセンブリが出力されます。debug['S']>1は偽となるため、データセクションは出力されません。 これにより、-Sはコードのみの逆アセンブルに限定されます。
-
-SSフラグが指定された場合 (debug['S'] == 2以上):pl->nameが真の場合(関数コード)はもちろん、debug['S']>1が真となるため、pl->nameが偽の場合(データセクション)でもアセンブリが出力されます。 これにより、-SSはコードとデータの両方の逆アセンブルを出力します。
このロジック変更により、-Sと-SSの挙動が明確に分離され、ユーザーの意図に応じたアセンブリ出力が可能になります。
doc.go における変更
src/cmd/gc/doc.go は、Goコンパイラのドキュメントの一部であり、コマンドラインフラグの説明が含まれています。このファイルも、新しい-SSフラグの導入に合わせて更新されています。
変更前:
-S
write assembly language text to standard output
変更後:
-S
write assembly language text to standard output (code only)
-SS
write assembly language text to standard output (code and data)
このドキュメントの更新は、ユーザーが新しい-SSフラグの存在と、-Sフラグの挙動変更を理解するために不可欠です。これにより、コンパイラの利用者が混乱することなく、適切なフラグを選択できるようになります。
コアとなるコードの変更箇所
src/cmd/5g/gobj.c
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -198,7 +198,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/6g/gobj.c
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -244,7 +244,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/8g/gobj.c
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -242,7 +242,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/gc/doc.go
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -47,7 +47,9 @@ Flags:
-N
disable optimizations
-S
- write assembly language text to standard output
+ write assembly language text to standard output (code only)
+ -SS
+ write assembly language text to standard output (code and data)
-u
disallow importing packages not marked as safe
-V
コアとなるコードの解説
上記のgobj.cファイル群における変更は、dumpfuncs関数(またはそれに類するアセンブリ出力を行う関数)内の条件分岐を修正しています。
元のコードでは、if(debug['S']) という単純な条件でアセンブリ出力が制御されていました。これは、-Sフラグが指定されていれば、すべての逆アセンブル(コードとデータ)を行うことを意味します。
変更後のコードでは、if(debug['S'] && (pl->name || debug['S']>1)) という複合条件が導入されています。
debug['S']: これは、-Sまたは-SSフラグが有効であることを確認するための基本的なチェックです。pl->name: これは、現在処理しているアセンブリが、名前を持つシンボル(通常は関数)に関連しているかどうかを判断します。つまり、コードセクションの逆アセンブルを行うための条件です。debug['S']>1: これは、-SSフラグが指定されているかどうかを判断します。Goコンパイラの内部実装では、-Sがdebug['S']=1、-SSがdebug['S']=2といった形で処理されるため、debug['S']が1より大きい場合は-SSが有効であると判断できます。
この論理積と論理和の組み合わせにより、以下の挙動が実現されます。
-
-Sのみが指定された場合 (debug['S'] == 1):debug['S']は真。pl->nameは、関数コードの場合に真。debug['S']>1は偽。- 結果として、
true && (pl->name || false)となり、pl->nameが真の場合(つまりコードセクション)にのみアセンブリが出力されます。データセクションは出力されません。
-
-SSが指定された場合 (debug['S'] == 2など):debug['S']は真。pl->nameは、関数コードの場合に真。debug['S']>1は真。- 結果として、
true && (pl->name || true)となり、常に真となります。これにより、コードセクションとデータセクションの両方のアセンブリが出力されます。
この変更により、-Sフラグは「コードのみ」の逆アセンブルに特化し、よりクリーンで分析しやすい出力を提供するようになります。一方、データセクションを含む完全な逆アセンブルが必要な場合は、明示的に-SSフラグを使用するようにユーザーに促す形になります。
doc.goの変更は、この新しい挙動をユーザーに明確に伝えるためのドキュメント更新であり、コンパイラの使いやすさを向上させる上で非常に重要です。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
- Goコンパイラのソースコード: https://github.com/golang/go/tree/master/src/cmd/compile (現在の
cmd/gcはcmd/compileに統合されています)
参考にした情報源リンク
- Goのソースコード(GitHub): https://github.com/golang/go
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージにある
https://golang.org/cl/6302054はGerritの変更リストへのリンクです) - アセンブリ言語に関する一般的な情報源 (例: Wikipedia)
- コンパイラの設計に関する一般的な情報源 (例: Dragon Book)
- Goコンパイラの内部構造に関するブログ記事や解説(一般的な知識として)
- Goの
debugフラグに関する情報(Goのソースコードや関連ドキュメントから得られる情報) - Goの
cmd/compile(旧cmd/gc)の役割に関する情報 - Goの各アーキテクチャ向けコンパイラ(5g, 6g, 8gなど)に関する情報# [インデックス 13316] ファイルの概要
このコミットは、Goコンパイラ(cmd/gc)におけるアセンブリ出力の挙動を変更するものです。具体的には、-Sフラグによるアセンブリ出力からデータセクションの逆アセンブルを除外し、データセクションの出力は新しい-SSフラグに限定するように変更しています。これにより、-Sフラグがよりコードの逆アセンブルに特化し、その有用性が向上することを目的としています。
コミット
commit b185de82a4e2b8982e5a6c211a436b749a9735c4
Author: Russ Cox <rsc@golang.org>
Date: Thu Jun 7 12:05:34 2012 -0400
cmd/gc: limit data disassembly to -SS
This makes -S useful again.
R=ken2
CC=golang-dev
https://golang.org/cl/6302054
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b185de82a4e2b8982e5a6c211a436b749a9735c4
元コミット内容
cmd/gc: limit data disassembly to -SS
This makes -S useful again.
変更の背景
Goコンパイラには、生成されたアセンブリコードを表示するための-Sフラグが存在します。しかし、このフラグがコードだけでなくデータセクション(初期化されたグローバル変数など)の逆アセンブルも出力するようになっていたため、出力が冗長になり、純粋なコードの挙動を追跡する際に不便が生じていました。特に、大規模なプログラムではデータセクションの出力が非常に大きくなり、コードの分析を妨げる可能性がありました。
このコミットの目的は、-Sフラグの出力をコードのみに限定することで、その本来の目的である「コードの逆アセンブル表示」としての有用性を回復させることにあります。データセクションの逆アセンブルが必要な場合には、新たに導入される-SSフラグを使用するように分離することで、ユーザーが目的に応じて適切な粒度でアセンブリ出力を得られるように改善されています。
前提知識の解説
Goコンパイラ (cmd/gc)
Go言語の公式コンパイラは、gc(Go Compiler)と呼ばれます。これは、Goのソースコードを機械語に変換する役割を担っています。cmd/gcは、Goのツールチェインの一部であり、go buildコマンドなどを介して間接的に利用されます。コンパイラは、ソースコードの解析、中間表現の生成、最適化、そして最終的な機械語コードの生成という一連のプロセスを実行します。
アセンブリ言語と逆アセンブル
- アセンブリ言語: コンピュータのプロセッサが直接実行できる機械語命令を、人間が理解しやすいニーモニック(例:
MOV,ADD,JMP)で表現した低水準プログラミング言語です。CPUのレジスタ操作やメモリへのアクセスなど、ハードウェアに近いレベルでの操作を記述します。 - 逆アセンブル (Disassembly): 機械語コードをアセンブリ言語に変換するプロセスです。これにより、コンパイル済みのバイナリがどのような機械語命令で構成されているかを人間が読み取れる形式で確認できます。デバッグ、パフォーマンス分析、セキュリティ分析などで利用されます。
コンパイラのデバッグフラグ (-S, -SS)
多くのコンパイラには、コンパイルプロセスや生成されるコードに関する詳細な情報を出力するためのデバッグフラグが用意されています。Goコンパイラの-Sフラグもその一つで、生成されたアセンブリコードを標準出力に出力するために使用されます。
-Sフラグ: このコミット以前は、Goコンパイラにおいて、生成されたアセンブリコード(命令)とデータセクション(初期化されたグローバル変数など)の両方を標準出力に逆アセンブルして表示する役割を担っていました。-SSフラグ: このコミットで新しく導入されたフラグで、コードとデータの両方のアセンブリを詳細に出力するために使用されます。- データセクションの逆アセンブル: プログラムの実行に必要な静的なデータ(文字列リテラル、初期化されたグローバル変数、定数など)が格納されるメモリ領域の内容をアセンブリ形式で表示することです。
gobj.c ファイル
Goコンパイラのソースコードにおいて、src/cmd/5g/gobj.c, src/cmd/6g/gobj.c, src/cmd/8g/gobj.c といったファイルは、それぞれ異なるCPUアーキテクチャ(5gはARM、6gはx86-64、8gはx86-32など)に対応するコンパイラのバックエンド部分であり、オブジェクトファイル生成に関連する処理や、アセンブリ出力のロジックが含まれています。これらのファイル内で、-Sフラグが有効な場合にアセンブリを出力する処理が実装されています。
debug['S']
Goコンパイラの内部では、コマンドラインで指定されたデバッグフラグが、debugというグローバルなマップまたは配列のような構造体で管理されています。debug['S']は、-Sフラグが指定されたかどうか、またはその詳細レベルを示す値として使用されます。例えば、-Sが指定されればdebug['S']は1となり、-SSが指定されればdebug['S']は2となる、といった形で利用されます。
技術的詳細
このコミットの技術的な核心は、Goコンパイラのバックエンドにおけるアセンブリ出力ロジックの条件分岐の変更と、ドキュメントの更新にあります。
gobj.c における変更
変更は、src/cmd/5g/gobj.c, src/cmd/6g/gobj.c, src/cmd/8g/gobj.c の3つのファイルに共通して適用されています。これらのファイルは、それぞれ異なるCPUアーキテクチャに対応するコンパイラのバックエンド部分です。
変更前のコードは以下のようになっていました。
if(debug['S']) {
// ... アセンブリ出力ロジック ...
}
これは、-Sフラグが指定されていれば(debug['S']が真であれば)、コードとデータの両方のアセンブリを出力するという意味です。
変更後のコードは以下のようになっています。
// -S prints code; -SS prints code and data
if(debug['S'] && (pl->name || debug['S']>1)) {
// ... アセンブリ出力ロジック ...
}
この変更により、アセンブリ出力の条件がより厳密になりました。
debug['S']: これは、-Sまたは-SSフラグが指定されていることを示します。pl->name: これは、現在処理しているシンボルが関数(コード)である場合に真となる条件です。plはProgリスト(プログラム命令のリスト)の要素を指し、pl->nameはその命令が属する関数のシンボル名を示します。debug['S']>1: これは、-SSフラグが指定されていることを示します。Goコンパイラの内部では、-Sはdebug['S'] = 1、-SSはdebug['S'] = 2のように処理されることが一般的です。
したがって、新しい条件式 debug['S'] && (pl->name || debug['S']>1) は以下を意味します。
-
-Sフラグのみが指定された場合 (debug['S'] == 1):pl->nameが真の場合(つまり、現在のシンボルが関数コードの場合)にのみアセンブリが出力されます。debug['S']>1は偽となるため、データセクションは出力されません。 これにより、-Sはコードのみの逆アセンブルに限定されます。
-
-SSフラグが指定された場合 (debug['S'] == 2以上):pl->nameが真の場合(関数コード)はもちろん、debug['S']>1が真となるため、pl->nameが偽の場合(データセクション)でもアセンブリが出力されます。 これにより、-SSはコードとデータの両方の逆アセンブルを出力します。
このロジック変更により、-Sと-SSの挙動が明確に分離され、ユーザーの意図に応じたアセンブリ出力が可能になります。
doc.go における変更
src/cmd/gc/doc.go は、Goコンパイラのドキュメントの一部であり、コマンドラインフラグの説明が含まれています。このファイルも、新しい-SSフラグの導入に合わせて更新されています。
変更前:
-S
write assembly language text to standard output
変更後:
-S
write assembly language text to standard output (code only)
-SS
write assembly language text to standard output (code and data)
このドキュメントの更新は、ユーザーが新しい-SSフラグの存在と、-Sフラグの挙動変更を理解するために不可欠です。これにより、コンパイラの利用者が混乱することなく、適切なフラグを選択できるようになります。
コアとなるコードの変更箇所
src/cmd/5g/gobj.c
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -198,7 +198,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/6g/gobj.c
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -244,7 +244,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/8g/gobj.c
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -242,7 +242,8 @@ dumpfuncs(void)
if(isblank(pl->name))
continue;
- if(debug['S']) {
+ // -S prints code; -SS prints code and data
+ if(debug['S'] && (pl->name || debug['S']>1)) {
s = S;
if(pl->name != N)
s = pl->name->sym;
src/cmd/gc/doc.go
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -47,7 +47,9 @@ Flags:
-N
disable optimizations
-S
- write assembly language text to standard output
+ write assembly language text to standard output (code only)
+ -SS
+ write assembly language text to standard output (code and data)
-u
disallow importing packages not marked as safe
-V
コアとなるコードの解説
上記のgobj.cファイル群における変更は、dumpfuncs関数(またはそれに類するアセンブリ出力を行う関数)内の条件分岐を修正しています。
元のコードでは、if(debug['S']) という単純な条件でアセンブリ出力が制御されていました。これは、-Sフラグが指定されていれば、すべての逆アセンブル(コードとデータ)を行うことを意味します。
変更後のコードでは、if(debug['S'] && (pl->name || debug['S']>1)) という複合条件が導入されています。
debug['S']: これは、-Sまたは-SSフラグが有効であることを確認するための基本的なチェックです。pl->name: これは、現在処理しているアセンブリが、名前を持つシンボル(通常は関数)に関連しているかどうかを判断します。つまり、コードセクションの逆アセンブルを行うための条件です。debug['S']>1: これは、-SSフラグが指定されているかどうかを判断します。Goコンパイラの内部実装では、-Sがdebug['S']=1、-SSがdebug['S']=2といった形で処理されるため、debug['S']が1より大きい場合は-SSが有効であると判断できます。
この論理積と論理和の組み合わせにより、以下の挙動が実現されます。
-
-Sのみが指定された場合 (debug['S'] == 1):debug['S']は真。pl->nameは、関数コードの場合に真。debug['S']>1は偽。- 結果として、
true && (pl->name || false)となり、pl->nameが真の場合(つまりコードセクション)にのみアセンブリが出力されます。データセクションは出力されません。
-
-SSが指定された場合 (debug['S'] == 2など):debug['S']は真。pl->nameは、関数コードの場合に真。debug['S']>1は真。- 結果として、
true && (pl->name || true)となり、常に真となります。これにより、コードセクションとデータセクションの両方のアセンブリが出力されます。
この変更により、-Sフラグは「コードのみ」の逆アセンブルに特化し、よりクリーンで分析しやすい出力を提供するようになります。一方、データセクションを含む完全な逆アセンブルが必要な場合は、明示的に-SSフラグを使用するようにユーザーに促す形になります。
doc.goの変更は、この新しい挙動をユーザーに明確に伝えるためのドキュメント更新であり、コンパイラの使いやすさを向上させる上で非常に重要です。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
- Goコンパイラのソースコード: https://github.com/golang/go/tree/master/src/cmd/compile (現在の
cmd/gcはcmd/compileに統合されています)
参考にした情報源リンク
- Goのソースコード(GitHub): https://github.com/golang/go
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージにある
https://golang.org/cl/6302054はGerritの変更リストへのリンクです) - Go compiler -S -SS flags assembly output: https://go.dev/doc/articles/go-tool-compile (Goの
go tool compileコマンドに関する情報) - アセンブリ言語に関する一般的な情報源 (例: Wikipedia)
- コンパイラの設計に関する一般的な情報源 (例: Dragon Book)
- Goの
debugフラグに関する情報(Goのソースコードや関連ドキュメントから得られる情報) - Goの
cmd/compile(旧cmd/gc)の役割に関する情報 - Goの各アーキテクチャ向けコンパイラ(5g, 6g, 8gなど)に関する情報