憂鬱な午後のひととき


10月31日_
rdtsc
=Aが64bitではrdx:eaxではなくraxになるというのは言われてみればなるほど. たまたま自分が使っていた範囲ではedxは関係が無いので気が付かなかった.
・ハロウィン
興味が無いので毎度毎度, 何を祝ってるのか調べてもすぐ忘れる. カトリックの諸聖人の日(11/1)の前夜祭. プロテスタントが多いアメリカでは前夜祭だけ盛大にやってるらしい. やはりすぐ忘れそうだ.
10月30日_
ProgramDataフォルダの取得ではまる
SHGetFolderPath + CSIDL_COMMON_APPDATAを使ってProgramDataを取得しようとしたのだが, 2008 serverで取れないときがあった. 原因は権限の問題ではなく環境変数の問題だった. 2008 serverではSYSTEMDRIVE環境変数が定義されていないと動作しない(Vista以降推奨のSHGetKnownFolderPathを使っても同じ). プログラムをCreateProcessで起動するときに環境ブロックにNULLを指定しているならよいが, そうでない場合はSYSTEMDRIVEを渡さないと動かない. fastcgiなんかで注意が必要. プログラムが/MDでコンパイルされている場合, DLLの読み込みのためにSystemRoot環境変数も必要(こちらはXpのみ).
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "User32.lib")

#include <stdio.h>
#include <string>

int main()
{
    _putenv("SYSTEMDRIVE="); // 環境変数を消す
    char buf[MAX_PATH];
    if (SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf) == S_OK) {
        // Xp, 2003はOK
        printf("programdata=%s\n", buf);
    } else {
        // Vista, 2008 server, Windows 7だと動かない
        int err = GetLastError();
        printf("err=%d\n", err);
        return 1;
    }
}
10月29日_
ハイブリッド車等の静音性に関する対策検討委員会
一通り読んでみた. とりあえず現状では「ハイブリッド車の静音性に起因する自己の発生は確認できていない」し事故率も変わらない(<資料2>). 今のところ自動車のエンジンっぽい音をだすのがいいんじゃないって感じだが, せっかく静かなのにわざわざ音を出すというのがやだなあ(パブリックコメントにも多い---もちろん反論も多い). 対策が必要な場面を見ても大半は現状でも十分注意すべきところで, 人が気が付かないなら一時停止して窓開けて通りますよと言えばよいのでは. 「エコ」キャンペーンに使う力の一部でも「歩行者を気づかう運転」キャンペーンに回したらと思う.
10月26日_
VC2010 beta2入れてみた. beta1の全く使い物にならない遅さのGUIから, 使い物にならない程度の遅さに改善された感じ. 残念ながらタブ型ドキュメントをoffにすることはbeta2でもできなかった. 製品版には入ってくれるんだよなあ. std::minの酷いバグは直ってた(注:あれ, 勘違いか. 直ってない?).
beta1からbeta2への移行が不十分だった模様. 再インストールしてそのバグが直ってることを確認した.
10月25日_
首藤さんの日記を見て, 科学未来館のデジタルコンテンツEXPO2009に行ってみる. かなり昔にメールのやりとりが少しあった福地さんに会えるかなと思ったけど分からんかった. 残念.
3Dテレビがもう実用間近という雰囲気でびっくり. 裸眼でも立体に見えた. リアルタイムで自分を立体視できたのも面白かった. ただ私には30分程度で頭痛くなりそうな感じではあった.
HRP-4Cのデモを期待したけど酷かった. 人だかりが凄くて全く見えない. 大きなスクリーンがあるんだからそこに表示したらいいだろう(表示されたいたのはタイトルだけ! 画面が変わらないのでいつ始まるのかと思ってたら既に始まっていた). 初日の不手際じゃなくて最終日でそれはないだろうと思った. あと帰る間際になってEXPO2009だけなら無料というのに気が付いた. 幸い払い戻しをしてもらえたけど, 入り口でここで券を買ってくださいと言われたら普通買う. EXPO2009のみの人は無料と大きく掲示すべきだと思う. なんか未来館って毎度毎度, 展示のやり方や運営方法に不満が募る.
10月24日_
あるクラスがvoid func() constメンバ関数を持っているときのみ実行させるtemplate. クラスがある基底クラスを継承していないといけないなどの制約が無くてもよい. もちろんboost使えという話だけど, 無しでもやりたいとき用にメモ.
#include <stdio.h>

template<typename T>
class X {
    T t_;
    struct DummyClass;
    template<typename S, void (S::*)() const>
    struct HasMemFunc { };
    template<typename S>
    void dispatch(int, HasMemFunc<S, &S::func>* p = 0)
    {
        t_.func();
    }

    template<typename S>
    void dispatch(DummyClass*)
    {
        puts("no func");
    }
public:
    void run()
    {
        dispatch<T>(0);
    }
};

struct A {
};

struct B {
    void func() const { puts("run func"); }
};

int main()
{
    X<A> a;
    a.run(); // "run func"
    X<B> b;
    b.run(); // "no func"
}
多少意味が変わるがVC専用でよければ__if_existsを使って
template<typename T>
struct Y {
    void run()
    {
        __if_exists(T::func) {
            T().func();
        }
        __if_not_exists(T::func) {
            puts("no func");
        }
    }
};
10月23日_
結局流れ星は見られんかった. この夏に行った和歌山の南の端っこの方だったらよう見えただろうなあ. あそこの空の暗さは凄かった. 地デジテレビでもアナログしか映らんかったし.
10月22日_
今動いてるマシンがVMware上かどうかを判別するckvm.cpp. VMware バックドア I/O ポートを見ながらなんとなく作る. 32/64-bit Win/Linux両対応.
class BackDoor : public Xbyak::CodeGenerator {
public:
    BackDoor(int cmd, int param)
    {
#ifdef XBYAK32
        push(ebx);
        push(esi);
        const Xbyak::Reg32& retp = esi;
        mov(retp, ptr [esp + 8 + 4]);
#else
        push(rbx);
        const Xbyak::Reg64& retp = r8;
    #ifdef XBYAK64_WIN
        mov(retp, rcx);
    #else
        mov(retp, rdi);
    #endif
#endif
        mov(eax, 0x564d5868);
        mov(ebx, param);
        mov(ecx, cmd);
        mov(edx, 0x5658);

        db(0xed); // in eax, dx
        mov(ptr [retp + 0], eax);
        mov(ptr [retp + 4], ebx);
        mov(ptr [retp + 8], ecx);
        mov(ptr [retp + 12], ecx);
#ifdef XBYAK32
        pop(esi);
        pop(ebx);
#else
        pop(rbx);
#endif
        ret();
    }
10月21日_
・オリオン座流星群
夜中2時に起きて, 不審者に間違われてもしかたないよなあとびくびくしつつ, 街灯の少ない近所の公園を求めてさまよった. 30分ほどねばったけど微妙に雲がかかっていたせいか, 普段の眼鏡じゃなかったせいか見えなかった. 残念. にしてもやはりこっちの空は明るいなあ.
4時半過ぎにもう一度起きて見たが, 今度は移動している間にみるみる空の色が変わってきた. 後30分ぐらい早く起きないといかんかったのか. またもや残念.
・眼鏡
サーバルームのすみに落ちてた. そういや昨日は一度入ったのだった. 見つかってよかった.
10月20日_
会社で眼鏡無くした. 別に資料が山積みでどこに何あるか分からない机じゃなくてきれいさっぱりとしてるのに, あちこちうろつき回ってるわけでも無いのに, 不思議だ. 明日もう一度探すが結構高かった(6万ぐらい?)ので見つからないと新PC購入計画が….
10月18日_
boostなんてコンパイル遅くなるし, むやみやたらと複雑でコンパイルエラー分からないし, クラス名爆発して, gasが死ぬし, コードおっかけるの大変だし, 時々バグってるしで実はあんまし好きく無いのに, みんな好きだなあ.
こっち行くので酸っぱい葡萄.
10月17日_
サーバのps auxが変な現象は, /proc/1/statやlinux/fs/proc/array.cのdo_task_statなんかを見て原因を探そうとしたけど, 結局psのバージョンを新しくしたら直ったという恥ずかしい落ちだった.
10月16日_
VC10で
#include <stdio.h>
#include <algorithm>

int main()
{
    printf("min(3, 1)=%u\n", std::min<size_t>(3, 1));
    printf("max(1, 3)=%u\n", std::max<size_t>(1, 3));
}
//
min(3, 1)=3
max(1, 3)=1
minとmaxが逆になってるのではなく常に第1引数の値が返る. いくらβとは言え, こんな酷いバグがあったとは.
template<class _Ty,
    class _Pr> inline
    const _Ty& (min)(const _Ty& _Left, _Pr)
    {    // return _Left as smallest
    return (_Left);
    }
よくわからんところにマッチしてるなあ.
10月15日_
#if 1
#elif
#endif
がVC9やgcc 4.3.4でコンパイルできるけどgcc 4.4でエラーになる. #if 1が真となった時点で#elifの後ろの評価をしないのが正しいならgcc 4.4が間違ってるということかな. mcppのチェックでもエラーにはならなかった. 本当に殆ど何もチェックしないのでたとえば
#if 1
#elif <html>&{this}|(what)!??
#endif
もgcc 4.4以外ではエラーにならなかった.
10月14日_
うちのサーバのps auxが少し前から変.
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
root         1  0.2 99.9   328 589505315 ?   S    06:29   0:02 init [3]
% uname -a
Linux mie 2.6.31.3 #1 Sun Oct 11 01:29:43 JST 2009 i686 GNU/Linux
リブートしても変わらない. 何度やっても同じ. 589505315 = 0x23232323だから何か未初期化メモリを参照したのかなあ.
% free
             total       used       free     shared    buffers     cached
Mem:       1519612     246140    1273472          0     161652      47088
-/+ buffers/cache:      37400    1482212
Swap:            0          0          0
だし, 触ってて特に実害はなさそうなんだけど気持ち悪い.
10月13日_
もう1カ月近く喉の痛みが治らない. 何度かお医者さん行って薬も飲んでるのになあ. 咽頭炎らしいがどうしたもんか.
10月12日_
やっぱり「C で再帰」だと、そう思う人は多いかなあ。
「思う」とかの問題じゃないと思う. スタックサイズなんて普通1MBかせいぜい8MBで, 一つの再帰に16byte食うなら要素数6万~50万程度で死亡. 「Cで考える」ときにそういう「当たり前のこと」をスルーしたのはアウトだと思う. ちなみにVCでも末尾再帰版はスタックを食わない形に変換される.
10月11日_
『北村薫の捜索表現講義』(北村薫)
大学で講義をした一部をまとめたものらしい. 著者の語り口は群馬で聞いたときで残っているのでなんとなく想像しながら読んだ. 何を選ぶか, 何を読むか, どう解釈するかで自分を表現するという考え方が面白い. 朗読を聞くというのはしたことがないので一度探してみる.
10月10日_
__sync_bool_compare_and_swap_4 とは何か?~ glibc をビルドする場合は、 gcc の --with-arch=i686 configure オプションを使ってはいけない
これ以前はまりました. CASの命令で未定義になって--with-arch=i686でgccをリコンパイルしたのも同じなら, その後glibcのbuildではまったのも同じ. 私はCCをgcc -U__i686 -D__i686=__i686にするというかなり無理やりな方法で対処しました. でも#define __i686 1のせいでasmソースが壊れると気づくのにおっそろしく時間を食ってしまった. 自分の環境がかなり特殊なので発現したと思っていたがそうでも無かったのか. ついでに書いとくと自分の環境ではglibc-*/nscd/Makefileの終わりのリンクで-lsspを追加しないとうまくいかんかった. 理由は調べてない.
10月8日_
クレタ人のパラドックス
クレタ族が絶滅寸前で一人しかいなかったら矛盾かな.
10月6日_
64bitの場合はVC, gccともに32bit gccのメンバ関数と同様に第一引数にthisが入った形. これは一貫してるのでやっぱり32bit VCだけ変. とりあえず32bit/64bit gcc/VC用の
int func(int a, int b, int c, int d, int e) const
{
    return x_ + y_ + a + b + c + d + e;
}
相当のJIT的メンバ関数はこんな感じ(memfunc.cpp). 無理に一つのソースにまとめたからやや見にくいけど
    const struct {
        const Reg32e& self;
        const Operand& a;
        const Operand& b;
        const Operand& c;
        const Operand& d;
    } para = {
#if defined(XBYAK64_WIN)
        rcx,
        edx,
        r8d,
        r9d,
        ptr [rsp + 8 * 5],
        ptr [rsp + 8 * 6],
#elif defined(XBYAK64_GCC)
        rdi,
        esi,
        edx,
        ecx,
        r8d,
        r9d,
#else
        ecx,
        ptr [esp + 4 + PARA_ADJ],
        ptr [esp + 8 + PARA_ADJ],
        ptr [esp + 12 + PARA_ADJ],
        ptr [esp + 16 + PARA_ADJ],
        ptr [esp + 20 + PARA_ADJ],
#endif
    };
    mov(eax, ptr [para.self]);
    add(eax, ptr [para.self + 4]);
    add(eax, para.a);
    add(eax, para.b);
    ...
このあたりの部分はたいしたことないんだけど一見トリッキーな記述っぽくて面白い.
10月5日_
なんとなくC++のメンバ関数の呼び出し規約を調べてみた. また詳細をきちんと書くとして, VCとgccとでだいぶ違う. VCは呼び出された先でスタックを戻すというのは若干違和感(可変数引数だと呼び出し元). ポータビリティが落ちてしまうので今まで常にC系関数でしかasmを使わなかったけど, やはり特別な理由が無い限り, それは正しいと思う. 素直にthisを第一引数とするstaticメンバ関数(これはgccのメンバ関数相当)を追加してそれを経由するべきだよなあ. ちなみに, 今回やってみるまで知らなかったのだけどVC, gccともに通常の関数ポインタ(もしくはvoid*)から直接メンバ関数ポインタにキャストできない. 下記で
int (A::*p)(int, int) const
    = (int (A::*)(int, int) const)code.getCode();
みたいにやってないのはそれが理由. class Bのメンバ関数をAのメンバ関数にキャストすることはできるのだからちょっと不思議だ.
#include <stdio.h>
#include <stdlib.h>
#include <xbyak/xbyak.h>

struct A {
    int x_;
    int y_;
    A() : x_(3), y_(5) {}
    int func(int a, int b) const { return x_ + y_ + a + b; }
};

struct Code : public Xbyak::CodeGenerator {
    Code()
    {
#ifdef _WIN32
        const int PARA_ADJ = 0;
        const int RET_ADJ = 8;
#else
        mov(ecx, ptr [esp + 4]);
        const int PARA_ADJ = 4;
        const int RET_ADJ = 0;
#endif
        mov(eax, ptr [ecx]);
        add(eax, ptr [ecx + 4]);
        add(eax, ptr [esp + 4 + PARA_ADJ]);
        add(eax, ptr [esp + 8 + PARA_ADJ]);
        ret(RET_ADJ);
    }
};

int main()
{
    Code code;
    int (A::*p)(int, int) const = 0;
    *(void**)&p = (void*)code.getCode();

    for (int i = 0; i < 10; i++) {
        A a;
        int t1, t2, x, y;
        a.x_ = rand();
        a.y_ = rand();
        t1 = rand();
        t2 = rand();
        x = a.func(t1, t2);
        y = (a.*p)(t1, t2);
        printf("%d, %d\n", x, y);
    }
}

御意見は光成滋生<herumi@nifty.com>までお願いします