Diary?

2008-09-25
Thu

(22:03)

こういう黒魔術が(いやまあ魔術でも何でもないんだけど)通用するあたりが C 言語の長所であり短所なんだよなあ。ちなみに例示されているコードは俺の環境では gcc じゃきちんと動かず、 tcc なら普通にちゃんと動いた(tcc 0.9.23, gcc 4.1.2, Gentoo Linux, Celeron という環境)。

あと次のように書き換えたら gcc でも動いた。

void countdown(int *);
void mark(int);
 
main(int argc) {
    int c = 10;
    mark(0);
    printf(" %2d\n", c);
    countdown(&argc);
}
 
unsigned _mark;
 
void mark(int arg) {
    _mark = *((unsigned *)(&arg - 1));
}
 
void countdown(int *pargc) {
    unsigned *p = (unsigned *)(&pargc - 1);
    *p = _mark;
    int *pc = pargc - 9; //俺の環境ではこうなった。理由は不明
    if (*pc <= 0) {
        printf(" BANG!\n");
        exit(0);
    }
    (*pc)--;
}

多分絶対間違いなく他の環境じゃ動かない。ってか gcc -s の結果を眺めつつどこに何が積まれてるのかあたりを付けたらこうなった。何か tcc でコンパイルした結果を objdump してみると「おー、確かにここに値が詰まれてるぜー」とかいう風に納得できるんだけど、どうも gcc の方はアセンブリ/マシン語については大学で基礎レベルの講義を受けた程度の俺にはわけがわからん。もしもこういうマジで下位層部分の学習をするんなら、なんとなく tcc をお供にした方が良さそうな気がしてきた(そんな予定ないけど)。

追記: 「もっとえぐいトリック」は残念ながら思いつかなかった。

Creative Commons
この怪文書はクリエイティブ・コモンズ・ライセンスの元でライセンスされています。引用した文章など Kuwata Chikara に著作権のないものについては、それらの著作権保持者に帰属します。