Sat, 21 Dec 2002 20:13:07 JST / hina.di
powered by tds-1.3.0
<issei@issei.org>
タイトルの「或曰」ですが、漢文です。書き下すと「或(ある)いは曰(いわ) く」、現代語で「……と、ある人は言った」程度の意味です。
閉店まぎわの秋葉原の街で、Sony のインナーイヤー型ノイズキャンセリング・ へッドホン MDR-NC10を買おうとしたところ、寄った店には在庫なし。ぐぅ。
CVS本ですが、リファレンス的に使うにはイマイチですね。本文で長々と説明し ているので、パッと開いて必要な個所だけ拾い読みできません。
ひさしぶりに「素のC言語」を使ってプログラムを書いていて、エラー処理の面 倒さに疲れる。
こうなると、関数の戻り値をいちいちチェックしては上位の関数に渡すという C言語方式では面倒になってきて、Java や C++ で提供されている try - catch 式の例外処理スキームが欲しくなります。
以前、誰か *1の Web 日記で「Cプリプロセッサで try, catch 風のマクロを定義して使ってる」 というのを見かけた記憶があるのですが、ちょっと探してみたところ発見できな かったので、自分で書いてみます。
ヒープ上に確保したメモリを無視すれば、要は
だけで良いはず。C言語には、標準ライブラリでスタック環境と実行状態の待避・ 復元を行う setjmp (3), longjump (3) 関数が提供されていますから、そう苦労 せずに書けそうです。
……ということで、あっさり書けました *2。
C言語の文法に合わせるために、同名のローカル変数とグローバル変数を定義し て、現在実行中のコードが例外ハンドラ中にあるかどうかをチェックするなど、 いくつか小細工を弄していますが、本質的に難しいことは何もなく。
C++ で実現されているの例外処理と比べると、機能は圧倒的に低いですけど。
タイトル横にも書いてありますが、今回は日記システムとして TDS を使わせて頂いてます。今使ってるサーバ www.issei.org は、CGI, SSI の利用 に多少制限があるので、静的モードで HTML ファイルを作っておいて Web サーバ に転送してます。
Web 日記を書いたら、他からのリンク(Referer)をチェックするのが一つの楽 しみですが、この処理は CGI + JavaScript で行っています。CGI を IMG タグ に埋め込み、引数に JavaScript の document.referer を渡すというのは、SSI が使えない環境で独立したアクセス解析処理プログラムを作成するための常套手 段 *1ですね。
手元には、自作の Referer 解析 CGI プログラムもあるのですが、敢えてネット 上から拾ってきてみたり。あぁ、やっぱり排他制御の処理間違ってるよ、とか。
TDS の静的モードで作成した HTML ファイルを転送するには、今月の UNIX Magazine で取り上げられていた sitecopyを使っています。以前はローカルのディスクと Web サーバ上のファイルの同期 は rsync + ssh で行っていたのですが、今回のように ssh が使えない環境で Web ページ の更新を行うには、FTP 対応の sitecopy はなかなか便利ですね。
ちょっと驚いたことがひとつ。sitecopy は、最初に FTP サーバ上のファイルに 関する情報を ~/.sitecopy/ ディレクトリに保存しておいて、以降はローカルに 更新されたファイルのみ再転送します。この ~/.sitecopy/ 置いてあるファイル の形式が XML になってます。ソースファイルを眺めてみたところ、XML パーサに は expatを使ってるみたいですね。
「ホームドクターを探しておくべきではないでしょうか」という意見ですが、 私は、現状では患者が医師を選ぶためには、医師各人に関する情報が不足して いると思います。もう少し、医者個人の業績や、得手不得手、同業者内での評 価を気軽に調べられる環境が整わないと、選択の余地が広がらないのでは?
ちょっと調べてみたのですが、日本の「医師」はあくまで一般名詞の医師とし て振る舞うことを義務づけられており、個人を前面に押し出すことは徹底的に 禁止されているようですね *1。これだと、医師の側から情報を出すのも難しいのか。
法令の文面は分かっても、意図が分からず。法令は、改変履歴や審議過程とと もに CVSリポジトリにでも入れておいて欲しいものだ。
アイスキュロスの手になる、古代ギリシアの代表的な悲劇の第一幕。劇は全三幕 構成だが、第二幕、第三幕のテキストは、その大半が失われてしまっているとの こと。
ゼウスが父クロノスを打ち倒して神々の王の座に就き、その権勢を極めていた頃 の話。古き神ティタン一族の生き残りにして人類の庇護者を自認するプロメテウ スは、ゼウスに背いて人類に「火」を与え、その怒りを買う。ゼウスは、鍛冶と 技術を司る息子ヘパイストスを、権力・暴力を具象化した神とともに遣わし、プ ロメテウスを捕らえて世界の果ての岩山に磔りつける。
第一幕は、その非業の神プロメテウスと、ゼウスの寵愛を得たがために、その妻 ヘラに憎まれ、牛に姿を変えられて故国を追われて世界を流浪する王女イオの二 人を軸に展開する。
現存するものは劇の台本である以上、そこに小説風の情景描写は一切なく、登場 人物の台詞が全て。にもかかわらず、一読して、広大無辺にして荘厳なる神々の 世界が目に浮かぶよう。私が読んだのは邦訳されたテキスト *1ですが、その文章にして、これだけの力を感じさせるのですから、まさにギリシ ア文学おそるべし。
その後、アイスキュロスの時代から下ること数百年。やがて古代ギリシアは政治 的に没落し、国内抗争に諸外国を率いれて周辺地域の不安定化に多大な貢献をし た後に、紀元前二世紀に時の覇権国家ローマに征服されるわけですが、ローマは 国を征服しても、文化的にはギリシアに征服されたと言われるほど、ギリシア文 化が浸透しました。
現在の学問にしても、累を辿れば古代ギリシアに行き着くものが少なくないわけ ですが、「縛られたプロメテウス」のようなものを見せ付けられると、なるほど と納得せざるをえません。
「或曰」――或いは曰く。
なるほど、面白いものだな
「縛られたプロメテウス」では、永遠の寿命と強大な力を持つ神々と、死すべき 定めにあり、力も知恵も神には到底敵わぬ人間とが鋭く対比されている。
ギリシア神話における神の存在は、東洋思想の「道」(タオ)、現代風に自然法 則と言い換えても良いかもしれない。それは、いかに表象が移ろい変わろうとも、 変わらずに在り続ける永遠なるもの、そして人間を支配し、規定するものの象徴 だ *2。
死すべき定めにある人間は、いかに永遠に想いを馳せようとも、やがてその短い 一生に幕を下ろさねばならない。だからといって人間が無力で、永遠なる者に抗 し得ない存在かというと、そんなことはない。アイスキュロスの悲劇は、二千有 余年の時を越えて、今なおその輝きを放ち続け、ギリシア哲学は現代科学に至る 知の営みの中に、確かに引き継がれているのだから。
韜々と受け継がれる人類の営み。その流れを継承し、そこにわずかでも己が足跡 を残すことが、或いは、死すべき定めにある人間にとっての「永遠」を意味する のかもしれないな。
と、その或る人は言った。
良い医師というのは、どんなふうに探すのが良いんでしょう? 私は、あま り病院に行かない方なので、医師の診察を受ける機会も少ないのですが(最 後に病院に行ったのは何年前だ?)、健康診断なんかでたまに行ってみると 良いのかな。
或曰――或いは曰く。
私は病気や怪我は、しないことにしている。
と、その或る人は言った。
……参考にならない。
おや、活字本は文芸春秋社のものばかりだ。
医学・生物学において最近ホットな領域の一つ、再生医学をとりあつかった「人 体再生」という本 *1がありますが、物理学から生物・医学系に転向した知人T氏が「人体再生」で取 材を受けていた研究室にいることが判明。T氏帰省の折、研究テーマである体性 刺激への反応や微小循環に関して講義されてみたり。
専門的な話は、私の知識不足のためあまり踏み込めませんでしたが、マウスに噛 まれて大変だった話や、医学系と物理学系での研究対象に対する姿勢や気風の違 いなど、楽しませていただきました。また機会があったら、立ち寄ってください ね。>T氏
日銀のゼロ金利政策解除に関するレポートを読んでいたところ、ゼロ金利政策は 当事者が期待していた「貸し出し促進効果」は発揮しなかったものの、「資産代 替効果」という予期せぬ経路を通じて、経済底上げの役割を果たしたとの分析。
資産代替効果――経済学の書物を紐解くと「高い流動性を持ちリスクの少ない預 金に滞留していた資金が、金利低下に伴い、債権や株券などのリスクを伴う資産 に移動すること」とのこと。
そんなものかなと思っていた矢先、相次いで、両親が株式や株価に連動した金融 商品に投資していた *1との話を耳にする。なるほど、父母もこの流れに乗っていたのか。
Patrik Andersin という方からメールで知らせていただいたのですが、8月24 日に公開される ssh 2.3 からライセンスが変更になるとのこと。詳しくは Press Releaseにありますが、 特にフリーの UNIX 関係者に影響が大きい項目を抜粋しておき ます。
以下、私訳。
リリースされ次第、FreeBSD の ports/security/ssh2 もアップデートします。
*BSD のユーザが、わざわざ OpenSSH を ssh2 に入れ替える意味は「ない」と思 います。敢えていえば sftp?
ssh2 関係では、よく個人宛てに英語でメールがやってきます。私がメンテナンス している port の中でも、もっとも頻繁に質問を受けるのが ssh2 で、実は結構ユー ザがいるのかもしれません *1。
うーむ、こんな話だったのか。
コンパイラにハマり中。Pascal のサブセットを作れば良いということで、言語仕 様を決め、実装を始めてから二週間。やっと中間コード生成と、中間コード用イン タプリタの動作まで到達。
これで、プログラムを中間コードにコンパイルしてインタプリタ上で動作させら れるようになったので *1、スタックダンプを眺めつつ、中間コード生成ルーチンのバグ取りに勤しむ(目 が痛いぞ)。
参考文献……かな?
あと、Sybase 社が Watcom C/C++ コンパイラの ソースコードを公開する らしいので、これも出てきたら見てみたいですね。
ソースコードから、実際にプログラムが実行されるまでの過程を概略すると、 次のようになっている。
1, 4, 5 に関しては、具体的な処理内容を把握できる目処が立ったので、あとは 2, 3 を押さえたいところですが、GNU binutils のソースコードを眺めて5秒で メゲました。GNU binutils のコードは、ひどく読みにくい気がするんですけど、 私だけ?
友人に借りて以来、ずっと買おうと思っていた「恋愛的瞬間」をまとめ買い。
現代日本の不安を的確に掬い上げていると思うし、話としても面白い。にも関わ らず「だから、どうしたの?」という気がしてしまうのは、提示されている世界 観に私が馴染めないせいかな。
lcc 4.1/FreeBSD 4.1-RELEASE で putchar() を呼び出すコードを実行すると core dump してしまう問題の続き。
int
main(void)
{
printf("Hello, World");
putchar('\n');
return 0;
}
たとえば、上のコードを lcc 4.1 でコンパイルして実行すると、putchar を呼 び出した時点で異常終了する。
man page を読んでみると、概略
putchar(), putc() は、出力ストリームに文字を書き出す。同じ結果をもたらす 関数に fputc() があるが、fputc() が関数として実装されているのに対して、 putchar(), putc() はインライン展開されているマクロとして実装されている点 が異なる。
と書いてある。<stdio.h> を読んでみたところ、gcc を使っているかどうかでマ クロの実装が異なる *1ことが分かったので、試しに putchar() を使うのをやめて fputc() で書き換え てみると……やっぱり core dump。むむ?
アセンブラコードを書き出して調べてみる。
% lcc -S putchar.c -o putchar-lcc.s % gcc -S putchar.c -o putchar-gcc.s
putchar-lcc.s
main: pushl %ebp pushl %ebx pushl %esi pushl %edi movl %esp,%ebp pushl $.LC2 call printf addl $4,%esp pushl $__sF+84 ; ← pushl $10 call fputc addl $8,%esp movl $0,%eax .LC1: movl %ebp,%esp popl %edi popl %esi popl %ebx popl %ebp ret .Lf4:
putchar-gcc.s
main: pushl %ebp movl %esp,%ebp subl $8,%esp addl $-12,%esp pushl $.LC0 call printf addl $16,%esp addl $-8,%esp pushl $__sF+88 ; ← pushl $10 call fputc addl $16,%esp xorl %eax,%eax jmp .L6 .p2align 2,0x90 .L6: leave ret
気になるのは矢印で示した部分。fputc() を call する直前にスタックに積んで いるということは fputc() の引数。FreeBSD/i386 環境では、右側の引数から順 にスタックに積むので、この部分は stdout に相当するが、gcc と lcc とで値 が $__sF+88, $__sF+84 と異なっている。そもそも、$__sF って何者?
<stdio.h> から抜粋
extern FILE __sF[]; #define stdin (&__sF[0]) #define stdout (&__sF[1]) #define stderr (&__sF[2])
ふむ、stdin, stdout, stderr は FILE 構造体の配列として宣言されているのか。 で、stdout は配列 __sF の 1 番目ということで、そのアドレスが 「配列 __sF の先頭アドレス + FILE 型のサイズ」として計算されている。 どうも gcc と lcc で、FILE 構造体のサイズ計算が食い違っているらしい。
#include <stdio.h>
int
main(void)
{
printf("sizeof(long long) = %d\n", sizeof(long long));
return 0;
}
このコードをコンパイルして実行してみると、結果は gcc 2.95.2 では 8, lcc 4.1 では 4 となっている。gcc と lcc で long long 型のサイズが違うん だね。ビンゴ!
FILE 構造体のどこで long long が使われているのか見てみると、最後の _offset という要素が fpos_t 型で、fpos_t は最終的に long long 型の別名と して定義されている。 このために __sF[1] のアドレス計算が狂ってしまい、fputc() に stdout に対 応する FILE 構造体のアドレスの代わりに予期せぬデータがわたって、結果とし て core dump となったわけだ。
lcc でも long long 型を 64bit 型整数として扱わせれば良い。lcc では機種依 存のコード生成処理は src/*.md というファイルに記述されており、型と対応す るサイズなどの情報は src/c.h で定義された Interface, Metrics という構造 体を用いて記述されている。
typedef struct metrics {
unsigned char size, align, outofline;
} Metrics;
typedef struct interface {
Metrics charmetric;
Metrics shortmetric;
Metrics intmetric;
Metrics longmetric;
Metrics longlongmetric;
Metrics floatmetric;
Metrics doublemetric;
Metrics longdoublemetric;
Metrics ptrmetric;
Metrics structmetric;
.. (以下略)
今回のバイナリを生成するのに用いた x86linux.md を見てみると、次のように なっていた。
Interface x86linuxIR = {
1, 1, 0, /* char */
2, 2, 0, /* short */
4, 4, 0, /* int */
4, 4, 0, /* long */
4, 4, 0, /* long long */
4, 4, 1, /* float */
8, 4, 1, /* double */
8, 4, 1, /* long double */
4, 4, 0, /* T * */
0, 4, 0, /* struct; so that ARGB keeps stack aligned */
確かに long long 型が 4 バイトと宣言されているので、ここを 8 に書き直し て再コンパイル。できた lcc を使って putchar('\n'); を実行させると、今度 は core dump せずに完了。良し良し。
これで long long のサイズは gcc と一致したが、まだ long long 型の変数を 使うことはできない。たとえば、次のコードをコンパイルすると、コンパイラが assertion に引っかかって落ちる。
int
main(void)
{
long long n = 0;
return 0;
}
これは 64 bit 変数への代入を行うアセンブラルーチンが存在しないためで、こ れに対して正しいアセンブラコードを出力するには、x86linux.md に出力するア センブラコードを記述する必要がある。
1, 2, 4 バイトの代入処理がどうなっているか探してみると、x86linux.md の 520 行目付近に次のようなものを見つける。
stmt: ASGNI1(addr,rc) "movb %1,%0\n" 1 stmt: ASGNI2(addr,rc) "movw %1,%0\n" 1 stmt: ASGNI4(addr,rc) "movl %1,%0\n" 1
ということは、ここに次のような記述を追加すれば良いわけだ。
ASGNI8(addr,rc) "対応するアセンブラコードの雛形" 1
もう少しコンパイラの中身を調べないと書くのが難しそうなので、とりあえず棚 上げして、lcc のコード読み読み。
近所のショップでは、売りきれとのこと。予約しておくんだったかな。
send-pr 済。
OpenSSH は現在では SSH Protocol 1, 2 ともにサポートしていますが、どうも、SSH Communications Corp. の ssh2 と相互に通信できないことがあるようです。 詳しく調べてないので、原因は不明。
OpenSSH の ssh クライアントから SSH の sshd2 に接続したときのログ
% issei ssh -2 -v localhost debug: len 55 datafellows 0 debug: dsa_verify: signature correct debug: Wait SSH2_MSG_NEWKEYS. debug: GOT SSH2_MSG_NEWKEYS. debug: send SSH2_MSG_NEWKEYS. debug: done: send SSH2_MSG_NEWKEYS. debug: done: KEX2. debug: send SSH2_MSG_SERVICE_REQUEST Disconnecting: Corrupted HMAC on input. debug: Calling cleanup 0x80573f0(0x0)
再入荷の時刻を見切って購入成功。
昼夜を問わず。
動的リンクの計算方法が間違ってるというコンパイラのバグを潰したり、x86 の 命令セットリファレンスを読んだり。