[インデックス 1366] ファイルの概要
このコミットは、Go言語の初期のランタイムおよびデバッグツールの一部であるlibmach
ライブラリにおいて、16進数を出力する際に常に0x
プレフィックスを付加するように変更するものです。これにより、出力される数値が16進数であることが明確になり、可読性とデバッグ時の理解が向上します。
コミット
commit eaa2a364a784a0462d8a5a7132e255abf76d66f7
Author: Russ Cox <rsc@golang.org>
Date: Thu Dec 18 18:23:48 2008 -0800
libmach: always print 0x on hex numbers
R=r
DELTA=3 (0 added, 0 deleted, 3 changed)
OCL=21558
CL=21558
---
src/libmach_amd64/8db.c | 12 ++++++------
src/libmach_amd64/machdata.c | 4 ++--
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/libmach_amd64/8db.c b/src/libmach_amd64/8db.c
index 040dd1e861..bab5ffb9b1 100644
--- a/src/libmach_amd64/8db.c
+++ b/libmach_amd64/8db.c
@@ -301,7 +301,7 @@ enum{
REXX = 1<<1, /* extend sib index */
REXB = 1<<0 /* extend modrm r/m, sib base, or opcode reg */
};
-
+
/* Operand Format codes */
/*
%A - address size register modifier (!asize -> 'E')
@@ -361,7 +361,7 @@ enum {
OPOVER, /* Operand size override */
ADDOVER, /* Address size override */
};
-
+
static Optable optab0F00[8]=
{
[0x00] 0,0, "MOVW LDT,%e",
@@ -859,7 +859,7 @@ static Optable optabD8[8+8] =\
[0x0f] 0,0, "FDIVRD %f,F0",
};
/*
- *\toptabD9 and optabDB use the following encoding:
+ *\toptabD9 and optabDB use the following encoding:
*\tif (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
*\telse instruction = optabDx[(modrm&0x3f)+8];
*\
@@ -1931,7 +1931,7 @@ immediate(Instr *ip, vlong val)\
w = -w;\
if (issymref(ip, &s, w, val)) {\
if (w)\
- bprint(ip, "%s+%lux(SB)", s.name, w);\
+ bprint(ip, "%s+%#lux(SB)", s.name, w);\
else\
bprint(ip, "%s(SB)", s.name);\
return;\
@@ -1942,7 +1942,7 @@ immediate(Instr *ip, vlong val)\
if (w < 0)\
w = -w;\
if (w < 4096) {\
- bprint(ip, "%s-%lux(SB)", s.name, w);\
+ bprint(ip, "%s-%#lux(SB)", s.name, w);\
return;\
}\
}\
@@ -2250,7 +2250,7 @@ i386foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)\
return 1;\
default:\
break;\
- }\t\t
+ }\
if (strncmp(op->proto,"JMP", 3) == 0 || strncmp(op->proto,"CALL", 4) == 0)\
return 1;\
foll[n++] = pc+i.n;\
diff --git a/src/libmach_amd64/machdata.c b/src/libmach_amd64/machdata.c
index dfbce3acd6..2b7368ddeb 100644
--- a/src/libmach_amd64/machdata.c
+++ b/src/libmach_amd64/machdata.c
@@ -113,7 +113,7 @@ symoff(char *buf, int n, uvlong v, int space)\
if (s.type != 't' && s.type != 'T' && delta >= 4096)\
return snprint(buf, n, "%llux", v);\
else if (delta)\
- return snprint(buf, n, "%s+%lux", s.name, delta);\
+ return snprint(buf, n, "%s+%#lux", s.name, delta);\
else\
return snprint(buf, n, "%s", s.name);\
}
@@ -150,7 +150,7 @@ fpformat(Map *map, Reglist *rp, char *buf, int n, int modif)\
if (rp->rformat == 'F')\
return 1;\
return 2;\
- }\t
+ }\
/* treat it like 'f' */\
if (get1(map, rp->roffs, (uchar *)reg, 4) < 0)\
return -1;\
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/eaa2a364a784a0462d8a5a7132e255abf76d66f7
元コミット内容
このコミットの目的は、libmach
ライブラリが16進数値を文字列として出力する際に、常に0x
プレフィックスを付加するように修正することです。これにより、出力された数値が16進数であることが一目でわかるようになり、特にデバッグ時やログ解析時における数値の解釈ミスを防ぎ、可読性を向上させます。
変更の背景
Go言語の初期開発段階において、libmach
のような低レベルのデバッグツールやランタイムライブラリは、システムの内部状態やメモリの内容を頻繁に16進数で表示する必要がありました。しかし、従来の出力形式では、例えば100
という値が10進数の100なのか、それとも16進数の0x100
(256)なのかが曖昧になる可能性がありました。このような曖昧さは、特に複雑なシステムをデバッグする際に混乱を招き、誤った解釈につながる恐れがあります。
この問題を解決し、出力の明確性を高めるために、16進数表示には標準的な0x
プレフィックスを常に付加するという決定がなされました。これは、プログラミングコミュニティにおける16進数表記の一般的な慣習に則ったものであり、Goのツールがより使いやすく、理解しやすいものになるための改善の一環です。
前提知識の解説
libmach
: Go言語の初期のツールチェインの一部であり、主にデバッグやプロファイリング、低レベルのシステム情報へのアクセスを目的としたライブラリ群です。mach
は「machine」の略であり、特定のアーキテクチャ(この場合はamd64
)に依存する低レベルの操作を抽象化します。これは、Goのランタイムがどのようにメモリを管理し、レジスタを操作し、命令を実行するかを理解するために重要でした。- 16進数表記 (Hexadecimal Notation): 基数が16の数値表現システムです。0から9までの数字と、AからFまでのアルファベット(A=10, B=11, ..., F=15)を使用して値を表します。コンピュータサイエンスでは、メモリアドレス、バイトデータ、色コードなどを簡潔に表現するためによく用いられます。慣習的に、16進数であることを示すために
0x
(C言語系)や$
(アセンブリ言語系)などのプレフィックスが付けられます。 printf
系関数とフォーマット指定子: C言語の標準ライブラリ関数であるprintf
や、その派生であるsprintf
、snprintf
などは、書式指定文字列(フォーマット指定子)を使って様々な型のデータを整形して出力します。%x
または%lx
(long hex): 符号なし16進数として出力します。この指定子だけでは0x
プレフィックスは付加されません。%#x
または%#lx
:x
の前に#
を付けると、代替形式(alternate form)が適用され、16進数出力に0x
プレフィックスが自動的に付加されます。このコミットの核心はこの変更点にあります。
bprint
/snprint
: これらはGoの初期のlibmach
内で使用されていた、printf
ライクな書式付き出力関数であると考えられます。bprint
はバッファへの出力、snprint
は指定されたバッファサイズ内で文字列を生成する関数と推測されます。
技術的詳細
このコミットは、src/libmach_amd64/8db.c
とsrc/libmach_amd64/machdata.c
の2つのファイルに対して行われています。変更の核心は、printf
系のフォーマット指定子において、16進数を出力する%lx
(または%llux
)を%#lx
(または%#llux
)に変更することです。
具体的には、以下の箇所で変更が行われています。
-
src/libmach_amd64/8db.c
内のimmediate
関数: この関数は、命令の即値オペランドを整形して出力する役割を担っています。シンボル参照(issymref
)に関連するオフセット値を出力する際に、bprint
関数が使用されています。- 変更前:
bprint(ip, "%s+%lux(SB)", s.name, w);
- 変更後:
bprint(ip, "%s+%#lux(SB)", s.name, w);
- 変更前:
bprint(ip, "%s-%lux(SB)", s.name, w);
- 変更後:
bprint(ip, "%s-%#lux(SB)", s.name, w);
ここで、%lux
が%#lux
に変更されています。lux
はlong unsigned hexadecimal
を意味し、#
プレフィックスが付くことで、出力される16進数に0x
が自動的に付加されるようになります。
- 変更前:
-
src/libmach_amd64/machdata.c
内のsymoff
関数: この関数は、シンボルとオフセットを組み合わせて文字列として出力する役割を担っています。- 変更前:
return snprint(buf, n, "%s+%lux", s.name, delta);
- 変更後:
return snprint(buf, n, "%s+%#lux", s.name, delta);
ここでも同様に、%lux
が%#lux
に変更されています。
- 変更前:
これらの変更により、libmach
が生成するデバッグ出力やシンボル情報において、オフセット値などの16進数表現が常に0x
プレフィックス付きで表示されるようになります。これにより、数値が16進数であることが明確になり、デバッグ情報の可読性が大幅に向上します。
また、コードの変更点とは直接関係ありませんが、8db.c
とmachdata.c
内のコメント行の末尾にある不要なタブ文字が削除されています。これはコードの整形とクリーンアップの一環であり、機能的な変更ではありません。
コアとなるコードの変更箇所
src/libmach_amd64/8db.c
--- a/src/libmach_amd64/8db.c
+++ b/src/libmach_amd64/8db.c
@@ -1931,7 +1931,7 @@ immediate(Instr *ip, vlong val)\
w = -w;\
if (issymref(ip, &s, w, val)) {\
if (w)\
- bprint(ip, "%s+%lux(SB)", s.name, w);\
+ bprint(ip, "%s+%#lux(SB)", s.name, w);\
else\
bprint(ip, "%s(SB)", s.name);\
return;\
@@ -1942,7 +1942,7 @@ immediate(Instr *ip, vlong val)\
if (w < 0)\
w = -w;\
if (w < 4096) {\
- bprint(ip, "%s-%lux(SB)", s.name, w);\
+ bprint(ip, "%s-%#lux(SB)", s.name, w);\
return;\
}\
}\
src/libmach_amd64/machdata.c
--- a/src/libmach_amd64/machdata.c
+++ b/src/libmach_amd64/machdata.c
@@ -113,7 +113,7 @@ symoff(char *buf, int n, uvlong v, int space)\
if (s.type != 't' && s.type != 'T' && delta >= 4096)\
return snprint(buf, n, "%llux", v);\
else if (delta)\
- return snprint(buf, n, "%s+%lux", s.name, delta);\
+ return snprint(buf, n, "%s+%#lux", s.name, delta);\
else\
return snprint(buf, n, "%s", s.name);\
}
コアとなるコードの解説
変更の核心は、printf
系のフォーマット指定子である%lux
(または%llux
)を%#lux
(または%#llux
)に変更した点にあります。
%lux
: これは、符号なしlong
整数を16進数形式で出力するためのフォーマット指定子です。この指定子だけでは、出力される16進数には0x
プレフィックスは付加されません。例えば、値が256
の場合、100
と出力されます。%#lux
:x
の前に#
フラグを追加することで、printf
系の関数は「代替形式」を使用するようになります。16進数(x
またはX
)の場合、この代替形式は出力に0x
(または0X
)プレフィックスを付加します。したがって、値が256
の場合、0x100
と出力されるようになります。
このシンプルな変更により、libmach
が生成するすべての16進数オフセットやアドレスが、標準的な0x
プレフィックス付きで表示されるようになり、デバッグ情報の明確性と一貫性が大幅に向上しました。これは、低レベルのシステムプログラミングやデバッグにおいて、数値の基数を誤解することなく迅速に情報を把握するために非常に重要な改善です。
関連リンク
- Go言語の公式ウェブサイト: https://go.dev/
- Go言語の初期のコミット履歴は、現在のGitHubリポジトリで確認できます。
参考にした情報源リンク
- C言語
printf
フォーマット指定子に関するドキュメント(#
フラグについて):- https://www.cplusplus.com/reference/cstdio/printf/ (C++のドキュメントですが、Cの
printf
にも適用されます) - https://en.cppreference.com/w/c/io/fprintf (C言語の
fprintf
に関する詳細な説明)
- https://www.cplusplus.com/reference/cstdio/printf/ (C++のドキュメントですが、Cの
- Go言語の歴史に関する情報(
libmach
の文脈を理解するため):- Go言語の公式ブログや初期の設計ドキュメントなどが参考になりますが、特定のURLはコミット当時の情報を見つけるのが困難な場合があります。
- Goのソースコードリポジトリ自体が最も正確な情報源です。