FizzBuzzを書こう2
きっかけは「文字なし」・・・
本当はここの日記を書くためにとあるネタをやってました。
・・・が、うまいこといかず難航していてもやもやしてました
そこに、
http://d.hatena.ne.jp/ptr1024/20100612/1276368392
というのが舞い込んできました。
現在は修正がかかってますが最初に投稿されたときは「文字なし」でした。
数字なしではなく文字なしらしいです。
いや、ならやってやろうじゃないか、と。
さすがに完全文字なしは無理なので・・・
C言語で文字なしは無理があるのでなるべく少なくするという方針でいきます。
要はプログラムの大方を数字化してしまうということですね。
・・・
もう予想は付きますね・・・
ということで
完成したものがこれです。
http://codepad.org/R6zyIhNn
どう見ても手抜きですね。
ごめんなさい><;
だってだって夜中の遅い時間に半分ヤケで作ったものなんだよ><
お願い、許して〜
ε二二二ε二二二(。゚つД`)゚。ウワァァ-----ン!!!!
解説
本当はこんなことしてる場合じゃなかったりします・・・
ということで、前回のと合わせて時間がある時にやります><
#これの裏話もそのときに・・・
##覚えてたら、ですが・・・ ←
追記:書きました(10/06/20)
ソース
とりあえずソースをペタペタ。
#include <stdio.h> unsigned int a[] = { 1374456661, 33310151, 2415919104, 3910462352, 0, 2054842694, 2054504960, 1680146554, 3942648320, 4232416007, 4232415552, 1694268803, 1166768767, 57317884, 2247751513, 2332914898, 1788476485, 4193736965, 980800133, 2583446923, 4149805930, 1976731129, 59407, 2203582464, 3897576168, 4294967207, 2583446923, 4149806442, 1976731129, 59407, 2203582464, 3897582056, 4294967179, 1979650795, 59644, 2203582464, 3897585896, 4294967159, 232, 3900921856, 1760055420, 3925868543, 4294967161, 3284779059 }; int main( void ) { a[4] = (unsigned int)printf - (unsigned int)&a[5]; ((void(*)())a)(); return 0; }
どう見てもバイナリです、本当に(ry
大元のソース
で、バイナリが何やってるか、ですが元のソースを載せます。
#include <stdio.h> int main( void ) { int i = 1; __asm { nop nop jmp START PRINTF: jmp printf FIZZ: ;DB 'Fizz', 00h nop nop nop nop nop BUZZ: ;DB 'Buzz', 00h nop nop nop nop nop INTEGER: ;DB '%d', 00h nop nop nop RETURN: ;DB '\n', 00h nop nop } START: for( ; i <= 100 ; i++ ) { if( !( i % 3 ) || !( i % 5 ) ) { if( !( i % 3 ) ) { __asm { call FIZZ_PRINT FIZZ_PRINT: pop eax sub eax, 0x00 push eax call PRINTF } } if( !( i % 5 ) ) { __asm { call BUZZ_PRINT BUZZ_PRINT: pop eax sub eax, 0x00 push eax call PRINTF } } } else { __asm { push i call INT_PRINT INT_PRINT: pop eax sub eax, 0x00 push eax call PRINTF } } __asm { call RET_PRINT RET_PRINT: pop eax sub eax, 0x00 push eax call PRINTF } } return 0; }
基本的には前回のラムダ式で書いたものと同じです。
ただ、全てのコードをバイナリで済ますために各種データ(printf関数のポインタ、printfに渡すデータ)を埋め込めるように先頭にNOPを入れデータ領域を確保しています。
これをコンパイルし機械語を取り出します。
その後、データのために確保した領域(先頭のNOP)の部分を各種データに書き換えれば終了です。
ただし、printfの関数へのポインタは定数値ではないので実行時に書き換えることとします。
これが
a[4] = (unsigned int)printf - (unsigned int)&a[5];
の行です。
実際にはprintfの関数の位置はコンパイル(リンク)終了後には決まるはずなんだけど、コンパイル時には決まらないからどうしてもこの行を書かなくてはならなくなって残念なことに・・・
ちなみにjmp STARTの前に入っているNOPはunsigned intの境界(4バイト境界)に合わせるためにわざと入れてあります。
これ入れないと2バイトずれるためまた面倒なことに・・・
おわり
またバイナリなことをやってしまった・・・
ちょっとは高級言語的なことをしないと・・・><