Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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や、その派生であるsprintfsnprintfなどは、書式指定文字列(フォーマット指定子)を使って様々な型のデータを整形して出力します。
    • %x または %lx (long hex): 符号なし16進数として出力します。この指定子だけでは0xプレフィックスは付加されません。
    • %#x または %#lx: xの前に#を付けると、代替形式(alternate form)が適用され、16進数出力に0xプレフィックスが自動的に付加されます。このコミットの核心はこの変更点にあります。
  • bprint / snprint: これらはGoの初期のlibmach内で使用されていた、printfライクな書式付き出力関数であると考えられます。bprintはバッファへの出力、snprintは指定されたバッファサイズ内で文字列を生成する関数と推測されます。

技術的詳細

このコミットは、src/libmach_amd64/8db.csrc/libmach_amd64/machdata.cの2つのファイルに対して行われています。変更の核心は、printf系のフォーマット指定子において、16進数を出力する%lx(または%llux)を%#lx(または%#llux)に変更することです。

具体的には、以下の箇所で変更が行われています。

  1. 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に変更されています。luxlong unsigned hexadecimalを意味し、#プレフィックスが付くことで、出力される16進数に0xが自動的に付加されるようになります。
  2. 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.cmachdata.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 フォーマット指定子に関するドキュメント(#フラグについて):
  • Go言語の歴史に関する情報(libmachの文脈を理解するため):
    • Go言語の公式ブログや初期の設計ドキュメントなどが参考になりますが、特定のURLはコミット当時の情報を見つけるのが困難な場合があります。
    • Goのソースコードリポジトリ自体が最も正確な情報源です。