The Man Who Fell From The Wrong Side Of The Sky:2013年11月22日分

[最新版] [一覧] [前月] [今月] [翌月]

2013/11/22(Fri)

[386BSD(の子孫)ソースコードシリーズ (334)][な阪関無] sys/cdefs.hとは何ですか? (その9)

@ まえがき

飽きた、 引き続きNetBSD1.3までに追加されたマクロです。

@ _C_LABEL()マクロ

昔の環境のlibcにおいてシンボルは全てアンスコが付いてました。テニスの下着の方でないアンダースコアすなわち「_」です。

NetBSD 1.3.3だとこんな感じ。

$ uname -sr
NetBSD 1.3.3

$ nm /usr/lib/libc.so.12.20 | grep vfprintf
0004adb4 T _vfprintf

なぜこんなことやってんのかちゅーと、みんな大好き Linker & Loadersの「1.6 リンクの実例」に

大域シンボルの先頭にはそれぞれアンダースコアが付加されている。この理由については第5章で説明する

と書かれてます。

んでんでんで、興奮を抑えきれずに 淫夢5章をめくると「5.3.1 CとFortranの単純な名前の変形」にすっげーわかりにくい説明があります、ザックリ要約すると

ということです、カレー臭くさい(確信)。

@ name mangling の導入

そんでこの大域シンボル衝突を回避するためにどうしたらいいか、と頭悩ませた結果

そうだ、名前をまんぐり返そう(真剣)

という事になったわけですやね。

ルールとしては

というようになっとります、C++のネームマンドリルより簡単ですな。

@ _C_LABEL() マクロの使用例

アンダースコア付への変換はCコンパイラが勝手にやるので通常は意識しません。ただしアセンブラソースや淫乱アセンブラからCの大域シンボル参照する時とかには手マンする必要があります。

例えば こ↑こ↓の2nd stage boot loaderのコードですが

…
	movzbl	%dl, %edx
	push	%ebp			/* high 32 bits of first sector */
	push	%ebx			/* first sector of bios partition */
	push	%edx			/* bios disk */
	call	boot2			/* C bootstrap code */
…

boot2 は C ABI なのでアンスコ付けてやらんとならんわけですが

	call	_boot2			/* C bootstrap code */

わざわざ手マンせず _C_LABEL() マグロを使って↓と書くわけですな

	call	_C_LABEL(boot2)		/* C bootstrap code */

つーかタイプ量10倍になっとるじゃんとお思いでしょうが

ちゅー意味があるわけでして。

@ 加藤良三、ライブラリインタフェースをCに統一

Unixは移植性の為にプログラミング言語Cで書き直されることになります *14th Editionあたりでその作業はほぼ完了し、アセンブラで書かれたライブラリ絶滅しました。もはやアセンブラとそれ以外を区別するための前アンスコは不要になったのです。

そうなると前アンスコ撲滅したくなるのが人情、特にシンボル名8文字制限(当時)のうち常に1文字アンスコに奪われるのは嫌だもんげ。しかしながら実行するには

ちゅー難題が待っております、これ現実的には無理なんで長らく放置されることになります。

@ 成し遂げたぜ。

まずCコンパイラの修正は gcc に -fleading-underscore/-fno-leading-underscore というスイッチが実装されname mangle有り無しを切り替え可能になりました。

あとはライブラリを全て再コンパイルするタイミングなのですが、これはもっと時代が後になります。バイナリフォーマットをa.outからELFへスイッチするタイミングであれば互換性は全部切り捨てられるわけで、それが選ばれました。

ちなみにELF化されたNetBSD 1.5.3だとこんな感じ。

$ uname -sr
NetBSD 1.5.3

$ nm /usr/lib/libc.so.12.62.1 | grep vfprintf
00041ef0 T vfprintf

前アンスコが無くなったのがお分かり頂けますでしょうか?

現在のコードはこんな感じ

#ifdef __LEADING_UNDERSCORE
#define	_C_LABEL(x)	__CONCAT(_,x)
#else
#define	_C_LABEL(x)	x
#endif

-fleading-underscoreの場合は前アンスコあり、-fno-leading-underscoreの場合はなしで_C_LABEL()は展開されます。

Fortranも前アンスコは不要になりました、ただし後アンスコア健在なはず。詳しくはそこら歩いてる数学屋をとっ捕まえて聞いてください。

@ 次回予告

ヒッ


*1:そのことで なぜ localtime(3) の引数は time_t のポインタなのか?という不条理も生まれましたが、気にしたら負け。


[ホームへ] [ページトップへ]