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

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

2013/11/20(Wed)

[Unix C][*BSD][ま君壊] sys/cdefs.hとは何ですか? (その7)

@ 前回の補足

FreeBSDでは__dead/__pureに加えてgcc2.6への変更に伴って__dead2/__pure2が 追加されています、これは

extern void __dead foo() __dead2;

extern int __pure bar(int) __pure2;

と書く事でGCC2.5以前なら

extern void volatile foo() ;

extern int const bar(int) ;

それ以降だと

extern void  foo() __attribute__((noreturn));

extern int  bar(int) __attriute__((const));

になるって寸法ですな、これはFreeBSDの実装の方が正しいね。

NetBSDだと

__dead void foo();

__pure int bar(int);

なので、GCC2.5以前なら

volatile void foo();

const int bar(int);

それ以降だと

__attribute__((noreturn)) void  foo();

__attriute__((const)) int  bar(int);

のように、あまり推奨されない場所にマクロが展開されてしまいます。

gcc2.5以下向け対応なんてスッキリザックリ消していいような気もするんですが、 こういう失敗で、いつまでも古いgccから逃げられない人用なんですかね、まぁgccでサポート切られたCPUで頑張ってる人もいるのかも。

@ まえがき

前回で 4.4BSD-Liteまでの変更履歴を追いました。今回はNetBSD1.0〜1.1で入った変更を取り上げます。

こんなチラシの裏読んでる人には常識と思われますが、NetBSDは4.4BSD-Liteからではなく4.3BSD Net/2を元にした386BSDから派生してます。

4.4BSD-Lite相当の変更を取り込んだのはUCL vs BSDi訴訟が終結してからなのでいろいろと変更が前後したりすることに注意 *1、NetBSDへの取込作業は以下の でやったという話



Branch:		magnum
Description:	?
Status:		?
Start Date:
End Date:
Base Tag:	magnum-base
Maintainer:	?
Scope:		kernel
Notes:

44→44マグナムの連想らしい、全米ライフル協会さんオッスオッス。
ただscopeがkernelとある通り、userlandについては各担当が必要最小限でしかやってないっぽいです。

まぁそのおかげでFreeBSDと違って4.4BSD Runeの 呪い互換性を気にしなくて良かったわけですがね。

@ __warn_references() マクロ

このマクロについては、以前の 記事で軽く触れましたが

場合に使われます。

@ セキュリティ上問題がある関数

産まれたこと自体が罪の関数としては

が挙げられます。

gets(3)に関して、C11においては 既報ですが「ここちょっと消えてますね gets(3)という選手がいたんですけど」状態です。

mktemp(3)に関しては TOGの例のアレ

 APPLICATION USAGE

	Between the time a pathname is created and the file opened, it is possible for some other process to create a file with the same name.
	The mkstemp() function avoids this problem and is preferred over this function.

 FUTURE DIRECTIONS

	This function may be withdrawn in a future version.

危険性があること、将来のPOSIXでは撤回される可能性について触れられています。

また tempnam/ tmpnamについても同罪

 APPLICATION USAGE

	This function only creates filenames. It is the application's responsibility to create and remove the files.
	Between the time a pathname is created and the file is opened, it is possible for some other process to create a file with the same name. 
	Applications may find tmpfile() more useful.

まぁこっちは将来の話は出てないけど。

@ バイナリ互換性の為に残してある関数

これは 過去記事で詳しく説明したので割愛。

@ __warn_references() マクロの使い方

ユーモア欠落症患者のために、ウィキペディアの専門家たちが「 gets(3)」の項目を執筆しています。

例えばGCCでは、getsを使用するプログラムをコンパイルすると「the `gets' function is dangerous and should not be used. 
('gets' 関数は危険なため使うべきではありません。)」と警告される。

うーんこの、これはgccが警告出してるわけではなくリンカすなわちbinutilsのld(1)が出してます。実際問題Cygwinではこんなメッセージでえへんし、NetBSDでは違うメッセージです。

このメッセージ自体はglibc2のものですやね、 ソース見ると最後に

#ifdef _LIBC
link_warning (gets, "the `gets' function is dangerous and should not be used.")
#endif

とあります、このlink_warningというマクロは今回取り上げてる__warn_referencesと同じ機能を持つマクロで、こいつがld(1)に警告を出させるトリックです。

NetBSDの getsだと

__warn_references(gets, "warning: this program uses gets(), which is unsafe.")

です。

@ __warn_references() マクロの実装(現在)

objformatによって実装が異なります、ですのでsys/cdefs.hは以下のように分割されています。

もうnativeでa.outバイナリ作る必要もないしそもそも作れるか?問題もあるから消していいと思うんだよな、それともまだa.outなportってあるんだっけ?

FreeBSDではa.outサポートは 消されてますな。

ちなELFでの__warn_references()の実装は

#define __warn_references(sym,msg)                                      \
    __asm(".pushsection .gnu.warning." #sym "\n"                        \
          ".ascii \"" msg "\"\n"                                        \
          ".popsection");

gccはインラインアセンブラでgas(1)の疑似命令を使い、セクション .gnu.warning.<sym> に msgを文字列として埋め込んでます。objdumpで覗いてみると

$ objdump -s -j .gnu.warning.gets /lib/libc.so.12.181

/lib/libc.so.12.181:     file format elf64-x86-64

Contents of section .gnu.warning.gets:
 0000 7761726e 696e673a 20746869 73207072  warning: this pr
 0010 6f677261 6d207573 65732067 65747328  ogram uses gets(
 0020 292c2077 68696368 20697320 756e7361  ), which is unsa
 0030 66652e                               fe.

んでld(1)はコンパイルしたオブジェクトとlibcをリンクする際に、この警告を拾って表示するわけです。

@ __warn_references() マクロの実装(過去)

NetBSD1.1の時点ではobjformatはa.outだし、なぜかMIでなくMDと判定され ${MACHINEARCH}/include/cdefs.h行きになっとりますな、 .gnu.warningsでなく.stabs使って同じことをやっています。

a.out→ELFの話はまたいずれ。

@ __warn_references() の有効性

そもそもコンパイラやリンカがエラーメッセージ出しても一切気にしないのがCプログラマとして大手振ってま(以下略

ところによっては、この警告を見たくなけりゃ.gnu.warningセクション消せとかいう 猛者もいるし(白目)

@ 次回予告

微妙に飽きつつある、まだこんなどうでもいいネタ続き読みたい人いるのか。

次回「遡行」人は流れに逆らい、そして力尽きて流される。


*1:また一部のリビジョンはCVSから意図的に消されています。


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