【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

文字列配列を作る (2)

前回、C言語のargc, argvをJITで表示しました。

これをそのままPythonに移植しました。jitモジュールは以下を使用しています。

mkstr1.py
import sys
from jit import *

# for (i = 0; i < argc; i++) {
#     printf(argv[i]);
#     putchar(' ');
# }
codes = [
    0x56,                    # push esi
    0x8b, 0x74, 0x24, 0x14,  # mov esi, dword ptr[esp+20]
    0xff, 0x36,              # 0:  push dword ptr[esi]
    0x83, 0xc6, 0x04,        #     add esi, 4
    0xff, 0x54, 0x24, 0x0c,  #     call [esp+12]
    0x83, 0xc4, 0x04,        #     add esp, 0x4
    0x6a, 0x20,              #     push 32
    0xff, 0x54, 0x24, 0x10,  #     call [esp+16]
    0x83, 0xc4, 0x04,        #     add esp, 0x4
    0xff, 0x4c, 0x24, 0x10,  #     dec dword ptr[esp+16]
    0x75, 0xe5,              #     jnz 0b
    0x5e,                    # pop esi
    0xc3,                    # ret
]

printf = CFUNCTYPE(None, c_char_p)(lambda s: sys.stdout.write(s))

p = VirtualAlloc(0, len(codes), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
p[:] = codes
f = CFUNCTYPE(
        None, c_void_p, c_void_p, c_int, POINTER(c_char_p)
    )(getaddr(p))

if __name__ == "__main__":
    argc = len(sys.argv)
    argv = (c_char_p * argc)()
    argv[:] = sys.argv
    f(printf, putchar, argc, argv)
    VirtualFree(p, 0, MEM_RELEASE)
実行結果
$ python mkstr1.py abc def
mkstr1.py abc def

リスト(sys.argv)を配列(argv)に変換しているのがポイントです。

printfの代替関数は可変長引数を考慮していませんが、今回はフォーマットせずに文字を表示するだけなので、特に問題はありません。

後でコードを使いまわす予定なので、モジュールとして使ったときはJIT実行と解放処理を呼ばないようにしています。