[インデックス 1884] ファイルの概要
このコミットは、Go言語のランタイムにおけるlibmach_amd64
ライブラリに、32ビットのMach-O(macOSの実行ファイル形式)およびELF(Linuxなどの実行ファイル形式)バイナリのサポートを追加するものです。これにより、Goのデバッガやプロファイラが、これらの32ビットバイナリをより適切に解析・操作できるようになります。特に、Inferno OSのlibmach
ライブラリから派生したコードが導入され、386アーキテクチャのオブジェクトファイル解析能力が向上しています。
コミット
add .8 support to libmach_amd64 [sic].
add code to handle 32-bit Mach-O and ELF binaries.
R=r
DELTA=452 (365 added, 29 deleted, 58 changed)
OCL=26696
CL=26712
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fcd536d801a60ed0a00152851d42b88c7947a4ce
元コミット内容
add .8 support to libmach_amd64 [sic].
add code to handle 32-bit Mach-O and ELF binaries.
変更の背景
このコミットの主な背景は、Go言語のツールチェイン(特にデバッガやプロファイラ)が、異なるアーキテクチャやオペレーティングシステムで生成されたバイナリをより広範にサポートする必要があったためです。当時、Goはまだ初期段階にあり、クロスコンパイルや異なる環境でのデバッグの重要性が増していました。
具体的には、以下のニーズに対応しています。
- 32ビットバイナリのサポート強化: 64ビットシステム上で32ビットバイナリをデバッグしたり、その情報を解析したりする際に、
libmach_amd64
が適切に機能するようにするため。 - Mach-OとELF形式の拡張: macOS (Mach-O) とLinux (ELF) の両方で、32ビット版の実行ファイル形式を正確に解析する能力を向上させるため。
- Inferno OSの知見の活用: Inferno OSの
libmach
は、様々なアーキテクチャのオブジェクトファイルを解析するための実績あるライブラリであり、そのコードベースをGoに導入することで、堅牢なバイナリ解析機能を実現しようとしています。特に、Plan 9由来のGoツールチェインにとって、8.out
形式(386アーキテクチャのオブジェクトファイル形式)のサポートは自然な流れでした。
これらの変更により、Goのデバッグツールがより多様な実行環境に対応できるようになり、開発者がGoプログラムをより効率的にデバッグ・プロファイルできるようになることが期待されました。
前提知識の解説
このコミットを理解するためには、以下の技術的な概念を把握しておく必要があります。
1. libmach
libmach
は、Plan 9およびInferno OSに由来するライブラリで、実行ファイルやオブジェクトファイルの内部構造を解析するための低レベルな機能を提供します。デバッガやプロファイラが、プログラムのシンボルテーブル、テキストセクション、データセクション、レジスタ情報などを読み取るために使用されます。Go言語のツールチェインは、初期の段階でPlan 9の設計思想やコードベースから多くの影響を受けており、libmach
はその一例です。
2. Mach-O (Mach Object)
Mach-Oは、AppleのmacOS (旧OS X) およびiOSで使用される実行ファイル、オブジェクトコード、共有ライブラリ、およびコアダンプのファイル形式です。Mach-Oファイルは、ヘッダ、ロードコマンド、およびセグメント(セクションを含む)で構成されます。ロードコマンドは、カーネルがバイナリをメモリにロードする方法を記述し、セグメントはコード、データ、スタックなどの領域を定義します。
- 32ビット Mach-O: 32ビットアーキテクチャ(例: Intel i386)向けのMach-Oファイル。
- 64ビット Mach-O: 64ビットアーキテクチャ(例: Intel x86-64)向けのMach-Oファイル。
3. ELF (Executable and Linkable Format)
ELFは、Unix系オペレーティングシステム(Linux、FreeBSDなど)で広く使用されている実行ファイル、オブジェクトコード、共有ライブラリ、およびコアダンプの標準ファイル形式です。ELFファイルもヘッダ、プログラムヘッダテーブル(実行時情報)、セクションヘッダテーブル(リンク時情報)、およびセクションで構成されます。
- 32ビット ELF: 32ビットアーキテクチャ向けのELFファイル。
- 64ビット ELF: 64ビットアーキテクチャ向けのELFファイル。
4. 32ビットと64ビットアーキテクチャ
- 32ビットアーキテクチャ: CPUが32ビットのレジスタとメモリアドレスを使用します。これにより、最大4GBのメモリ空間を直接アドレス指定できます。
- 64ビットアーキテクチャ: CPUが64ビットのレジスタとメモリアドレスを使用します。これにより、理論上は非常に広大なメモリ空間(18エクサバイト)をアドレス指定できます。
デバッガやバイナリ解析ツールは、対象となるバイナリが32ビットか64ビットかによって、レジスタのサイズ、メモリアドレスの解釈、ファイル形式の構造などを適切に処理する必要があります。
5. ptrace
システムコール
ptrace
は、Unix系システムでプロセスをトレース(追跡)するためのシステムコールです。デバッガはこれを使用して、ターゲットプロセスの実行を制御したり、レジスタやメモリの内容を読み書きしたりします。ptrace
は、デバッグ対象のプロセスのレジスタセットを、デバッガ自身のアーキテクチャとは異なる形式で提供することがあります。このコミットでは、64ビットデバッガが32ビットターゲットのレジスタを適切に解釈するためのマッピングが追加されています。
6. Plan 9 8.out
形式
Plan 9オペレーティングシステムでは、各アーキテクチャに番号が割り当てられており、Intel 386アーキテクチャは「8」とされています。したがって、8.out
は386アーキテクチャ向けのオブジェクトファイル形式を指します。このコミットで追加された8obj.c
は、この形式のファイルを解析するためのものです。
7. バイトオーダー (Endianness)
バイトオーダーは、複数バイトで構成されるデータをメモリに格納する際のバイトの順序を指します。
- リトルエンディアン (Little-endian): 最下位バイトが最も小さいアドレスに格納されます。Intel x86/x86-64アーキテクチャで一般的です。
- ビッグエンディアン (Big-endian): 最上位バイトが最も小さいアドレスに格納されます。ネットワークプロトコルや一部のプロセッサで一般的です。
実行ファイル形式の解析では、ファイルのヘッダや構造体内の数値がどのバイトオーダーで格納されているかを正しく解釈する必要があります。このコミットのコードでは、
leswal
(little-endian swap long) やswav
(swap value) といった関数が使われており、バイトオーダーの変換を適切に行っていることが伺えます。
技術的詳細
このコミットは、主にsrc/libmach_amd64
ディレクトリ内のファイル群を変更し、32ビットのMach-OおよびELFバイナリの解析能力を向上させています。
1. src/libmach_amd64/8obj.c
の新規追加
このファイルは、Inferno OSのlibmach/8obj.c
から派生したもので、386アーキテクチャのオブジェクトファイル(Plan 9の8.out
形式)を識別し、解析するためのロジックを含んでいます。
_is8(char *t)
: 与えられたバイト列が386オブジェクトファイルのシグネチャに一致するかを判定します。_read8(Biobuf *bp, Prog* p)
: オブジェクトファイルからプログラム(Prog
構造体)の情報を読み取ります。これには、シンボル名、タイプ(テキスト、データなど)、オフセットなどが含まれます。addr(Biobuf *bp)
: アドレス情報を解析します。オフセット、シンボル参照、型情報などを処理します。type2char(int t)
: 内部的な型定数を文字表現に変換します(例:D_EXTERN
を'U'
に)。
このファイルの追加により、libmach_amd64
は386アーキテクチャのオブジェクトファイルを直接理解できるようになりました。
2. src/libmach_amd64/Makefile
の変更
新しく追加された8obj.c
がビルドプロセスに含まれるように、OFILES
変数に8obj.$O
が追加されています。これにより、8obj.c
がコンパイルされ、libmach_amd64
ライブラリの一部としてリンクされるようになります。
3. src/libmach_amd64/executable.c
の変更
このファイルは、様々な実行ファイル形式を識別し、そのヘッダ情報を解析するための中心的なロジックを含んでいます。
ExecTable
の更新:MACH_MAG
がMACH64_MAG
にリネームされ、64ビットMach-Oを明示的に指すようになりました。- 新しく
MACH32_MAG
が追加され、32ビットMach-Oバイナリの識別と解析がサポートされました。これには、FI386
(386アーキテクチャのファイルタイプ)とmi386
(386アーキテクチャの機械情報)が関連付けられています。
elf64dotout
の変更:- ELF64バイナリの解析において、特定のCPUタイプ(I386, MIPS, SPARC64, POWER, ARM)に対する
mach
とfp->type
の設定ロジックが削除されました。これは、elf64dotout
がAMD64に特化し、他のアーキテクチャのELF64バイナリは別のパスで処理されるか、あるいはこの関数がより汎用的なELF64解析に集中するように変更されたことを示唆しています。 - シンボルテーブルの処理において、
sh
(セクションヘッダ)がph
(プログラムヘッダ)の代わりに使われるようになりました。これは、ELFファイルのシンボル情報がプログラムヘッダではなくセクションヘッダに格納されることが一般的であるため、より正確な解析を行うための修正です。
- ELF64バイナリの解析において、特定のCPUタイプ(I386, MIPS, SPARC64, POWER, ARM)に対する
elfdotout
の変更:- 32ビットELFバイナリの解析において、セクションヘッダテーブル(
Shdr32
)を読み込むロジックが追加されました。これにより、.gosymtab
や.gopclntab
といったGo固有のセクションを正確に特定し、シンボル情報やPC-Lineテーブル(プログラムカウンタとソースコード行のマッピング)を抽出できるようになりました。 - エラーハンドリングが改善され、
sh
(セクションヘッダ)の解放が適切に行われるようになりました。
- 32ビットELFバイナリの解析において、セクションヘッダテーブル(
machdotout
の変更:- Mach-Oファイルの解析において、32ビットと64ビットのMach-Oヘッダを区別するためのロジックが追加されました。
mp->magic
(マジックナンバー)に基づいて、0xFEEDFACE
(32ビットMach-O)と0xFEEDFACF
(64ビットMach-O)を識別します。 - 32ビットMach-O (
MACH_SEGMENT_32
) と64ビットMach-O (MACH_SEGMENT_64
) のセグメント(MachSeg32
,MachSeg64
)とセクション(MachSect32
,MachSect64
)の解析ロジックが分岐されました。これにより、それぞれのアーキテクチャに応じた構造体のオフセットやサイズが正しく処理されます。 - テキストセクションとデータセクションの仮想アドレス (
textva
,datava
) とファイルオフセット (textoff
,dataoff
) の取得方法が、32ビットと64ビットの両方に対応するように修正されました。 settext
とsetdata
関数への引数が、セグメント構造体へのポインタから、直接計算された仮想アドレス、サイズ、オフセットに変更されました。これにより、コードがより汎用的になり、32ビットと64ビットの両方のセグメント情報を統一的に扱えるようになりました。
- Mach-Oファイルの解析において、32ビットと64ビットのMach-Oヘッダを区別するためのロジックが追加されました。
4. src/libmach_amd64/fakeobj.c
の変更
このファイルは、特定のオブジェクトファイル形式のサポートが有効になっていない場合に、ダミーの関数を提供するものです。_is8
と_read8
関数が削除されました。これは、8obj.c
が新しく追加され、386オブジェクトファイルの実際のサポートが提供されるようになったため、これらのダミー関数が不要になったことを意味します。
5. src/libmach_amd64/linux.c
の変更
このファイルは、Linux環境でのデバッグやプロセス操作に関連するロジックを含んでいます。
- 32ビットレジスタマッピングの追加:
go32tolinux64tab
という配列が追加されました。これは、Goの32ビットレジスタのオフセットを、Linuxの64ビットuser_regs_struct
内の対応するレジスタのオフセットにマッピングするためのものです。go32tolinux64(uvlong addr)
関数が追加され、Goの32ビットレジスタアドレスをLinuxの64ビットレジスタセット内のオフセットに変換します。go2linux(uvlong addr)
関数内で、mach == &mi386
(386アーキテクチャの場合)にこの新しい32ビットマッピングを使用するロジックが追加されました。
Ureg
構造体の扱い:Ureg
マクロが一時的にUreg32
に定義され、その後Ureg64
に再定義されることで、32ビットと64ビットのレジスタ構造体を適切に扱うための準備がされています。
- エラーメッセージの改善:
ptraceregrw
関数で、エラーメッセージにn
(バイト数)が追加され、デバッグ情報がより詳細になりました。
これらの変更により、64ビットのデバッガが32ビットのLinuxプロセスをデバッグする際に、レジスタ情報を正しく読み書きできるようになります。
6. src/libmach_amd64/macho.h
の変更
このヘッダファイルは、Mach-Oファイル形式に関連する構造体と定数を定義しています。
- 32ビットMach-O構造体の追加:
MachSeg32
構造体が追加されました。これは、32ビットMach-Oバイナリのセグメント情報を定義します。vmaddr
、vmsize
、fileoff
、filesize
などが32ビット幅になっています。MachSect32
構造体が追加されました。これは、32ビットMach-Oバイナリのセクション情報を定義します。
- 新しい定数の追加:
MACH_CPU_TYPE_X86
(7): 32ビットx86 CPUタイプ。MACH_SEGMENT_32
(1): 32ビットマップされたセグメントのロードコマンドタイプ。MACH32_MAG
: 32ビットMach-Oのマジックナンバー (0xFEEDFACE
)。MACH64_MAG
: 64ビットMach-Oのマジックナンバー (0xFEEDFACF
) が明示的に定義されました(以前はMACH_MAG
)。
これらの定義により、Mach-Oファイルのヘッダを正確に解析し、32ビットと64ビットの構造体の違いをコードで区別できるようになります。
7. src/libmach_amd64/8.c
の変更
このファイルは、386アーキテクチャの機械情報(mi386
構造体)を定義しています。
mi386
構造体のuser stack top
の値が0x7FFFFFFFULL
から0xFFFFFFFFULL
に変更されました。0x7FFFFFFFULL
は、符号付き32ビット整数の最大値であり、32ビットアドレス空間の上限の半分を示唆している可能性があります。0xFFFFFFFFULL
は、符号なし32ビット整数の最大値であり、32ビットアドレス空間の全体(4GB)を示します。 この変更は、32ビット環境におけるユーザースタックの最大アドレスを、より広範な32ビットアドレス空間の最上位に設定し、潜在的なスタックオーバーフローやアドレス計算の不整合を解消することを目的としていると考えられます。
これらの変更全体として、Goのツールチェインが32ビットのMach-OおよびELFバイナリをより正確かつ堅牢に解析・操作できるようになり、クロスアーキテクチャデバッグの能力が向上しました。
コアとなるコードの変更箇所
1. src/libmach_amd64/8obj.c
(新規ファイル)
// Inferno libmach/8obj.c
// ... (copyright and license) ...
/*
* 8obj.c - identify and parse a 386 object file
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach_amd64.h>
#include "../cmd/8l/8.out.h" // Plan 9 386 assembler/linker output format
#include "obj.h"
// ... (typedef struct Addr, static Addr addr, static char type2char, static void skip) ...
int
_is8(char *t)
{
uchar *s = (uchar*)t;
return s[0] == (ANAME&0xff)
&& s[1] == ((ANAME>>8)&0xff)
&& s[2] == D_FILE
&& s[3] == 1
&& s[4] == '<'; // name of file
}
int
_read8(Biobuf *bp, Prog* p)
{
int as, n, c;
Addr a;
as = Bgetc(bp); // as(low)
if(as < 0)
return 0;
c = Bgetc(bp); // as(high)
if(c < 0)
return 0;
as |= ((c & 0xff) << 8);
p->kind = aNone;
p->sig = 0;
if(as == ANAME || as == ASIGNAME){
// ... (name and signature parsing) ...
return 1;
}
if(as == ATEXT)
p->kind = aText;
if(as == AGLOBL)
p->kind = aData;
skip(bp, 4); // lineno(4)
a = addr(bp);
addr(bp);
if(!(a.flags & T_SYM))
p->kind = aNone;
p->sym = a.sym;
return 1;
}
2. src/libmach_amd64/executable.c
の machdotout
関数内
// ... (previous code) ...
hdrsize = 0;
switch(mp->magic) {
case 0xFEEDFACE: // 32-bit mach
if (mp->cputype != MACH_CPU_TYPE_X86) {
werrstr("bad MACH cpu type - not 386");
return 0;
}
// ... (other checks) ...
mach = &mi386;
fp->type = FI386;
hdrsize = 28;
break;
case 0xFEEDFACF: // 64-bit mach
if (mp->cputype != MACH_CPU_TYPE_X86_64) {
werrstr("bad MACH cpu type - not amd64");
return 0;
}
// ... (other checks) ...
mach = &mamd64;
fp->type = FAMD64;
hdrsize = 32;
break;
default:
werrstr("not mach %#ux", mp->magic);
return 0;
}
// ... (command buffer allocation and reading) ...
for(i = 0; i < mp->ncmds; i++) {
cmd[i] = (MachCmd*)cmdp;
c = cmd[i];
c->type = swal(c->type);
c->size = swal(c->size);
switch(c->type) {
case MACH_SEGMENT_32:
if(mp->magic != 0xFEEDFACE) {
werrstr("segment 32 in mach 64");
goto bad;
}
seg32 = (MachSeg32*)c;
// ... (32-bit segment parsing) ...
break;
case MACH_SEGMENT_64:
if(mp->magic != 0xFEEDFACF) {
werrstr("segment 32 in mach 64"); // This error message seems to be a copy-paste error, should be "segment 64 in mach 32"
goto bad;
}
seg = (MachSeg64*)c;
// ... (64-bit segment parsing) ...
break;
// ... (other cases) ...
}
cmdp += c->size;
}
// ... (settext, setdata, setsym calls) ...
3. src/libmach_amd64/linux.c
の go2linux
関数内
// ... (previous code) ...
uint go32tolinux64tab[] = {
14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20
};
static int
go32tolinux64(uvlong addr)
{
int r;
if(addr%4 || addr/4 >= nelem(go32tolinux64tab))
return -1;
r = go32tolinux64tab[addr/4];
if(r < 0)
return -1;
return r*8;
}
extern Mach mi386; // Declaration for mi386 from 8.c
static int
go2linux(uvlong addr)
{
// TODO(rsc): If this file is being compiled in 32-bit mode,
// need to use the go32tolinux32 table instead.
if(mach == &mi386) // Check if the target architecture is 386
return go32tolinux64(addr);
switch(addr){
case offsetof(Ureg64, ax):
return offsetof(struct user_regs_struct, rax);
// ... (other 64-bit register mappings) ...
}
return -1;
}
4. src/libmach_amd64/macho.h
// ... (previous definitions) ...
typedef struct {
MachCmd cmd;
char segname[16]; /* segment name */
uint32 vmaddr; /* memory address of this segment */
uint32 vmsize; /* memory size of this segment */
uint32 fileoff; /* file offset of this segment */
uint32 filesize; /* amount to map from the file */
uint32 maxprot; /* maximum VM protection */
uint32 initprot; /* initial VM protection */
uint32 nsects; /* number of sections in segment */
uint32 flags; /* flags */
} MachSeg32; /* for 32-bit architectures */
// ... (MachSeg64, MachSymSeg) ...
typedef struct {
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint32 addr; /* memory address of this section */
uint32 size; /* size in bytes of this section */
uint32 offset; /* file offset of this section */
uint32 align; /* section alignment (power of 2) */
uint32 reloff; /* file offset of relocation entries */
uint32 nreloc; /* number of relocation entries */
uint32 flags; /* flags (section type and attributes)*/
uint32 reserved1; /* reserved (for offset or index) */
uint32 reserved2; /* reserved (for count or sizeof) */
} MachSect32; /* for 32-bit architectures */
// ... (MachSect64) ...
enum {
MACH_CPU_TYPE_X86_64 = (1<<24)|7,
MACH_CPU_TYPE_X86 = 7, // New: 32-bit x86 CPU type
MACH_CPU_SUBTYPE_X86 = 3,
MACH_EXECUTABLE_TYPE = 2,
MACH_SEGMENT_32 = 1, /* New: 32-bit mapped segment */
MACH_SEGMENT_64 = 0x19, /* 64-bit mapped segment */
MACH_SYMSEG = 3,
MACH_UNIXTHREAD = 0x5,
};
#define MACH64_MAG ((0xcf<<24) | (0xfa<<16) | (0xed<<8) | 0xfe) // Renamed from MACH_MAG
#define MACH32_MAG ((0xce<<24) | (0xfa<<16) | (0xed<<8) | 0xfe) // New: 32-bit Mach-O magic number
コアとなるコードの解説
1. src/libmach_amd64/8obj.c
このファイルは、Plan 9の386アーキテクチャ(通称.8
)のオブジェクトファイルを解析するためのものです。
_is8
関数は、ファイルの先頭数バイトをチェックして、それが386オブジェクトファイルであるかどうかを識別します。具体的には、ANAME
というシンボルタイプとD_FILE
というデータタイプ、そしてファイル名の開始を示す'<'
文字の組み合わせを期待しています。これは、Plan 9のオブジェクトファイルが持つ独特のヘッダ形式です。_read8
関数は、識別された386オブジェクトファイルから、個々のプログラム要素(Prog
構造体)を読み取ります。これには、アセンブリ命令の種類(ATEXT
、AGLOBL
など)、行番号、シンボル情報などが含まれます。この関数は、オブジェクトファイル内のバイト列を解析し、Goの内部表現に変換する役割を担っています。
2. src/libmach_amd64/executable.c
の machdotout
関数
machdotout
関数は、Mach-O形式の実行ファイルを解析し、その構造(テキストセクション、データセクション、シンボルテーブルなど)をGoの内部表現にマッピングします。
- マジックナンバーによる分岐:
mp->magic
(Mach-Oヘッダのマジックナンバー)をチェックすることで、32ビットMach-O (0xFEEDFACE
) と64ビットMach-O (0xFEEDFACF
) を区別します。これにより、それぞれのアーキテクチャに応じたCPUタイプ (MACH_CPU_TYPE_X86
vsMACH_CPU_TYPE_X86_64
) とファイルタイプ (FI386
vsFAMD64
) が設定されます。 - ロードコマンドの解析: Mach-Oファイルは「ロードコマンド」と呼ばれる構造体群を持っており、これらがバイナリのセグメント、シンボルテーブル、スレッド情報などを記述しています。このコードでは、各ロードコマンドのタイプ (
c->type
) をチェックし、MACH_SEGMENT_32
またはMACH_SEGMENT_64
であるかによって、対応する32ビット (MachSeg32
) または64ビット (MachSeg64
) のセグメント構造体として解析します。これにより、テキストセクションやデータセクションの仮想アドレス、ファイルオフセット、サイズなどを正確に抽出できます。
3. src/libmach_amd64/linux.c
の go2linux
関数
go2linux
関数は、Goの内部的なレジスタオフセットを、Linuxのptrace
システムコールが使用するuser_regs_struct
内の対応するレジスタオフセットに変換する役割を担います。
- 32ビットターゲットのサポート:
if(mach == &mi386)
という条件文が追加されました。これは、現在解析しているバイナリが386アーキテクチャ(32ビット)である場合に、特別なレジスタマッピングを行うことを意味します。 go32tolinux64tab
: この配列は、Goの32ビットレジスタの論理的なオフセット(例えば、ax
が0、bx
が4など)を、64ビットLinuxカーネルが提供するuser_regs_struct
内の対応するレジスタのオフセットに変換するためのマッピングテーブルです。例えば、Goの32ビットDI
レジスタがLinuxの64ビットrdi
レジスタの下位32ビットに対応する場合、そのオフセットがこのテーブルに格納されます。go32tolinux64
関数は、このテーブルを使って実際のバイトオフセットを計算します。- 64ビットターゲットのサポート:
switch(addr)
ブロックは、64ビットGoプログラムのレジスタオフセットを、64ビットLinuxのuser_regs_struct
内の対応するレジスタオフセットに変換します。
このロジックにより、64ビットのGoデバッガが32ビットのGoプログラムをLinux上でデバッグする際に、レジスタの値を正しく読み書きできるようになります。
4. src/libmach_amd64/macho.h
このヘッダファイルは、Mach-Oバイナリの構造をC言語の構造体として定義することで、プログラムがMach-Oファイルをバイトレベルで解析できるようにします。
MachSeg32
とMachSect32
: これらの新しい構造体は、32ビットMach-Oバイナリのセグメントとセクションのレイアウトを正確に反映しています。例えば、アドレスやサイズを示すフィールドがuint32
型である点が64ビット版 (MachSeg64
,MachSect64
) と異なります。- マジックナンバーとCPUタイプの定数:
MACH32_MAG
やMACH_CPU_TYPE_X86
といった定数は、Mach-Oファイルのヘッダを読み込んだ際に、それが32ビットのx86アーキテクチャ向けであるかを迅速に判断するために使用されます。
これらの定義は、executable.c
などのファイルがMach-Oバイナリを正しく解釈するための基盤となります。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Inferno OS: https://www.vitanuova.com/inferno/
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Mach-O File Format Reference (Apple Developer Documentation): https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOProgrammingGuide/MachOConcepts/MachOConcepts.html
- ELF (Executable and Linkable Format) (Wikipedia): https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
- ptrace(2) - Linux man page: https://man7.org/linux/man-pages/man2/ptrace.2.html
参考にした情報源リンク
- コミット情報:
commit_data/1884.txt
- GitHub上のコミットページ: https://github.com/golang/go/commit/fcd536d801a60ed0a00152851d42b88c7947a4ce
- Inferno OSのソースコード (特に
utils/libmach/8obj.c
): http://code.google.com/p/inferno-os/source/browse/utils/libmach/8obj.c (これは古いGoogle Codeのリンクですが、Inferno OSのコードベースは現在も利用可能です) - Go言語の初期の設計に関する議論やドキュメント (Goの歴史的背景を理解するため)
- x86およびx86-64アーキテクチャのレジスタセットとメモリモデルに関する一般的な情報
- Mach-OおよびELFファイル形式の仕様に関する一般的な情報
ptrace
システムコールの動作に関する一般的な情報- バイトオーダー (Endianness) に関する一般的な情報