Mozilla Layer for Unicode (MZLU) が Opencow に名称変更していたようだ。libunicows もバージョンアップして、Opencow に対応していた。
DirectX 9.0c をインストールしたら、PCastTV のチャンネル設定が狂ってしまった。http://pc5.2ch.net/test/read.cgi/hard/1087858949/ の No.700 でアップロードされていたレジストリファイルをインポートして、再起動したところ、無事復活した。一応 700氏のレジストリファイルのコピーを置いておく。(channel.reg) レジストリの数値は、http://www.microsoft.com/japan/msdn/library/ja/DirectX9_c/directx/htm/japan.asp に書かれているものを 16進表記に直したものになっているようだ。
へー、こんなものが。ちょっと欲しいかも。
setup.exe を cygwin.com からダウンロードする際に Irvine を使ったら、spambot detection mechanism というものに引っかかってダウンロードできなかった。User-Agent を変更すればよいのだろうが、面倒だったので、Ring サーバからダウンロードしておいた。
find コマンドに時間が掛かる問題は、4.2.10 から 4.2.11-CVS (findutils-20041227-1) にバージョンアップしたところ、解消された。
Java プログラムをコンパイルしようとして、jikes を実行しようとしたらコマンドが見つからないといわれてしまった。jikes.exe を %JAVA_HOME%\bin\ に入れておいたはずなのになくなっていた。JDK を 5.0 Update 1 にバージョンアップするときに、5.0 をアンインストールしてから 5.0 Update 1 を入れたのだが、そのときに %JAVA_HOME%\bin\ に入れておいたものも一緒に削除されてしまったようだ。以前の JDK では、このようなことはなかったのだが。
また diswin を改造。fcomi, fcomip, fucomi, fucomip にも対応させておいた。(diswin19.patch)
patch コマンドでパッチを当てると、ファイルのタイムスタンプがパッチを当てた時刻になってしまうのが、以前から非常に気になっていた。調べてみると -T というオプションがあるではないか。Cygwin に入れている man の日本語版は、古いためか -T オプションに関する記述がなく、今まで気付かなかった。
Unauthorized Windows 95 Update ← 「Windows 95 内部解析」のサンプルプログラムのアップデート。VxDCall() などの kernel32 の非公開 API に ordinal を使って動的にリンクする方法など。(def ファイルを使って静的にリンクしてしまう方が楽な気がするが。)
J2SE 5.0 Update 1 (1.5.0_01) が出ていたので、早速 DL してインストール。J2SE 5.0 では、動かなかったサンプルプログラムを試してみたところ、一応 HTML の表示はできている。しかし相変わらず内部でヌルポが発生しているようだ。そのせいか、少々動作が不安定だ。
perdr という逆アセンブラを試してみた。文字列への参照なども表示してくれるのは嬉しい。diswin などと同じように pushad, iretd, jecxz などの一部の 32bit 命令が 16bit 命令と同じ表示になっていたのが気になる。
unicows.dll がバージョンアップしていた。(1.0.4018.0 → 1.1.3790.0) 何が変わったのかは調べていないが、バグフィックスがメインらしい。
x86 にはいくつか非公開命令があるそうだ。(参照:Undocumented OpCodes: ICEBP ) ここに載っている命令のほとんどは、diswin は既に対応していた。FCMOVcc 命令は非公開命令ではないが、diswin では対応していなかった。とりあえず対応させておいた。(diswin19.patch)
VxD には、USE32 セグメントと USE16 セグメントが混在できるのだが、diswin はそのどちらも USE32 セグメントとして扱っていた。修正。
movzx, movsx のオペランドサイズがまだ間違っていたので、これも修正。
356byte以下でWIN起動テトリス作れや! ← WinNT PE 形式の 900bytes のテトリス、小さな PE ファイルを作る方法など。
「ジャンクションの罠」@水無月ばけらのえび日記 ← 何も考えずに、ディレクトリへのジャンクションを削除してはいけない。
Koders ← いろいろなソースコードを検索できるサイトだそうだ。試しに、LoadLibrary16, GetWin16DOSEnv などで検索してみると、E/OS LX(meos) というプロジェクトのソースが引っかかった。
また、diswin を改造。cmovz, cmovnz など、PentiumPro で追加された命令に対応していないことが判明。movzx, movsx, xadd, cmpxchg, cmpxchg8b のオペランドサイズもおかしい。dispe はこれらの命令には対応していたが、cmpxchg8b だけは正しく対応できていなかった。
浮動小数点命令のオペランドサイズにまだ間違っている部分が残っていた。
上記のバグの修正の他、clflush, lfence, rdpmc, sysenter, sysexit, monitor, mwait, fisttp の各命令に対応させておいた。(diswin19.patch)
ちなみに、sysenter, sysexit, monitor, mwait, fisttp は MASM 7.10 ではアセンブルできなかったのだが、対応していないのだろうか?
なんと、diswin 0.19 は GPL じゃないか。ARM 関連のソース (arm-dis.c, arm-opc.h, dis-asm.h) には GPL であることが明記されている。GPL とリンクしたソフトは GPL となるので、自動的に diswin も GPL ということになる。diswin 自体のドキュメントにはライセンスの説明が全くないので気が付かなかった。ちょっと問題ではなかろうか。
diswin 0.19 を元にした iPlus DisWin というシェアウェアがある。diswin 0.19 が GPL であるから、必然的にこれも GPL になるわけだ。そうなると、ソースの公開を要求できるわけかな。もっとも、iPlus DisWin には arm-dis.c は、リンクされていないようだが。
diswin を改造。序数だけエクスポートしている関数がある場合、関数名と関数のアドレスがずれてしまっていたのを修正した。ついでに、le.c のコンパイルでファイルの最後に改行がないという警告が出るのも修正した。
さらにいろいろ試していたら、diswin にまたバグ発見。例えば、下記のコードは、
00401000 e3fe jcxz 401000 00401002 67e3fb jcxz 401000
次のようになるのが正しい。
00401000 e3fe jecxz 401000 00401002 67e3fb jcxz 401000
diswin を元にしている dispe も同じで、jecxz に対応していなかった。他にもいろいろ試してみたところ、iretd, outsd, insd, out dx,eax, in eax,dx といった 32bit 命令に対応していないことが判明。dispe も同様だった。
浮動小数点命令関連のバグも詳しく調べてみた。qword ptr や tbyte ptr となるべき部分が、ことごとく dword ptr になっていることが判明。また、浮動小数点命令にはオペランドが word ptr となる命令(fldcw 等)もあるが、それも dword ptr となっていた。dispe では、word ptr となる命令は正しく扱えるようだが、それ以外の命令はダメであった。
さらに、32bit モードでの far-call, far-jump 命令(16:32 形式)も正しく扱えていなかった。
とりあえずこれらのバグは目に付く範囲で全て修正してみた。さらに、バグではないが、32bit 幅のメモリを扱うときには、必ず dword ptr が付くようになっていたのを、自明な場合には省略するように変更した。例えば、
mov eax, dword ptr [ebx]
という表示は、
mov eax, [ebx]
になる。
とりあえずパッチを公開。以前と同様、http://d.hatena.ne.jp/nonakap/20040116#p4 のパッチも含めてある。コンパイル方法も以前と同じ。(diswin19.patch)
「VisualStudio.NET 2003でリモートデバッグを」
最近どういうわけか Cygwin の起動が遅い。調べてみたところ、find コマンドの実行に妙に時間が掛かっている。find を 4.2.10 から 4.1.7 にバージョンダウンしたところ、普通の時間で起動するようになった。
見慣れないウィルスが来た。WORM_MABUTU.A だそうだ。
昨日はパスを相対パスで指定していたのだが、フルパスで指定してみたら、テストプログラムを短時間に連続して起動しても問題は発生しなくなった。また、GetCurrentDirectory() API でカレントディレクトリを取得し、VxDCall0() で INT 21h - Function 713Bh (Set Current Directory) を発行しておくと、相対パスでも問題なく動作するようになった。理由は不明だが、Win32 API レベルと、VxD レベルでカレントディレクトリに違いが生じていたようである。これで無事、Win32 app 単独で、Win9x でディレクトリのタイムスタンプを設定できるようになった。
久しぶりに、大熊猫のぺぇじへ行ってみると、PC-98 用の DISK-BIOS が増えている。SUPERCHANPON2X-PCI の BIOS もある。そのうち試してみよう。(← 一体いつになるのだろう。)
ソース表示で長い行を折り返し表示するには、
user_pref("view_source.wrap_long_lines", true);
としておけばよいそうだ。(参考: Caminoを使おう:prefs.jsの変更)
GlobalDosAlloc の実装を見てふと思った。もしかして QT_Thunk() を使わなくとも下位 1MB 領域のメモリは確保することができるのではないだろうか。GlobalDosAlloc() は、非公開フラグ 8000h を指定して GlobalAlloc() を呼び出すことで下位 1MB 領域のメモリを確保している。それならば、Win32 API の WOWGlobalAlloc16() でもフラグに 8000h を指定することで同じように下位 1MB 領域のメモリを確保できるのではないだろうか。V86 モードのセグメント値を取得するのに必要な、GetSelectorBase() に相当する Win32 API がないが、これは、DPMI Function 0006h - Get Segment Base Address を VxDCall0() 経由で呼び出すことで代用できそうである。早速試してみたところ、メモリ確保に成功した模様。って、よく考えたら、GetSelectorBase() に相当する Win32 API として WOWGetVDMPointer() が使えるのではなかろうか。WOWGetVDMPointer() の返値を 4bit 右シフトすればセグメント値として使えるはず。試してみたところ、これも問題なさそう。
あひゃ、さんざん回り道したあげく、下位 1MB 領域のメモリ確保は公開された Win32 API だけでできてしまったというわけか。(非公開のフラグを使っているのがポイントだが。) できあがった Win32 用の GlobalDosAlloc() のコードは以下の通り。Win16 の GlobalDosAlloc() とおなじように、上位 16bit にはリアルモード(V86 モード)のセグメント値、下位 16bit には、プロテクトモード (16bit) のセレクタ値が入っている。メモリを解放するには、WOWGlobalFree16() にセレクタ値を渡せばよい。
DWORD GlobalDosAlloc32(DWORD size) { WORD sel; DWORD ret = 0; sel = WOWGlobalAlloc16(0x8000, size); if (sel) { ret = (DWORD) WOWGetVDMPointer((DWORD) sel << 16, size, TRUE); if (ret == 0) { WOWGlobalFree16(sel); } else { ret = (ret << 12) | sel; } } return ret; }
先月の spam メールの集計結果。着信拒否になった spam が少なくとも 6045通。着信拒否にならなかった spam が 528通。そのうち Spam Mail Killer で削除できた spam は 507通(96.0%)。
Win9x の advapi32.dll は、非公開 API VxDCall0() を使用していることが分かった。RegOpenKey() などのレジストリ操作用の API は、内部で VxDCall0() を使って、_RegOpenKey() などのそれに対応する VxD 用のサービスを呼び出していた。レジストリの操作が VxD レベルで処理されていたとは知らなかった。
また Win9x では、wow32.dll の API や、user32.dll の文字列操作 API も、内部的には kernel32.dll の非公開 API を呼び出しているだけだというのも初めて知った。
Win32 app から VxDCall0() を使って、INT 21h - Function 7143h を呼び出してタイムスタンプの取得を試してみた。よく考えたら、INT 21h の場合は INT 1Ch の場合とは違って、VxDCall0() から、プロテクトモードの割り込みハンドラを呼び出すこともできるので、これを使えば、わざわざ GlobalDosAlloc() でメモリを確保したり、サンク API を呼び出したりする必要はない。プロテクトモードのハンドラでも正しくタイムスタンプの取得ができるかどうかが少し心配だったが、V86 モードのときと同じように動作した。
1回の実行に掛かる時間を計ってみたところ、DPMI 経由で V86 モードのハンドラを呼び出した場合には 数ms 掛かったが、プロテクトモードのハンドラを呼び出した場合にはそれより1桁ほど速かった。サンクを使って 16bit DLL を呼ぶという普通の方法だとどのくらいの速度が出るかも気になるところである。(あとで計り直したら、V86 モードとプロテクトモードではそれほど大きな差はなく、V86 の方が1割遅い程度だった。)
INT 21h - Function 7143h を呼び出してタイムスタンプの取得・設定するテストプログラムを短時間に連続して起動すると、2回目以降に起動したプログラムからはタイムスタンプの取得ができないという問題が発生した。パスが見つからない (AX=02h) というエラーコードが返ってきている。プロテクトモードハンドラを直接呼び出した場合も、DPMI 経由で V86 モードハンドラを呼び出した場合も同じ問題が発生している。全く同じ機能を持つ DOS プログラムを作って試してみた場合は、問題は発生しない。困った。