久しぶりに pepsi & coke を触っているので復習がてらつらつら書きます。特にリビジョン 556 の jolt2 について書きます。まず最初に、基礎知識を簡単にまとめます。
特に、jolt は実行時にプログラムを書き換え可能という動的な性質と、機械語に変換してから実行するという静的な性質を一つで持っている珍しい言語です。このなかで動的な性質を実現するために二つの基本機能があります。
jolt2 による Hello world プログラムと、C ライブラリ puts のアドレスを表示するプログラムです。
;; indirect.k (define puts (dlsym "puts")) (printf "Address of puts == 0x%x\n" puts) (puts "Hello, world!")
$ ./jolt.sh boot.k indirect.k ; loading: boot.k Address of puts == 0x96c60f33 Hello, world!
ここで、オプションを変更し、(puts "Hello, world!") がどのようにコンパイルされるのかを見ます。
(define puts (dlsym "puts")) (printf "Address of puts == 0x%x\n" puts) [(import "CompilerOptions") verboseExec: '1] (puts "Hello, world!")
$ ./jolt.sh boot.k indirect.k ; loading: boot.k Address of puts == 0x96c60f33 => 3 free 0x301f20 code size 33 bytes code start 0x301fa0 call 0x301fa0 Hello, world! => 10 free 0x301fa0
と、見にくいですが、0x301fa0 から 33 バイトが (puts "Hello, world!") に対応する機械語です。gdb を使ってここを逆アセンブルしてみます。
$ gdb (gdb) file ~/src/idst.556/function/jolt2/main (gdb) b puts (gdb) run boot.k indirect.k Starting program: /Users/takashi/src/idst.556/function/jolt2/main boot.k indirect.k Reading symbols for shared libraries +++.. done Breakpoint 1 at 0x96c60f39 ; loading: boot.k Address of puts == 0x96c60f33 => 3 free 0x301f20 code size 33 bytes code start 0x301fa0 call 0x301fa0 Breakpoint 1, 0x96c60f39 in puts () (gdb) disas 0x301fa0 (0x301fa0 + 33) Dump of assembler code from 0x301fa0 to 0x301fc1: 0x00301fa0: push %ebp 0x00301fa1: mov %esp,%ebp 0x00301fa3: push %ebx 0x00301fa4: sub $0x4,%esp 0x00301fa7: mov 0x443640,%ebx // シンボル puts 0x00301fad: mov $0x301090,%eax // "Hello, world!" 0x00301fb2: mov %eax,(%esp) 0x00301fb5: call *%ebx // puts("Hello, world!") 0x00301fb7: mov %eax,%eax 0x00301fb9: mov %eax,%eax 0x00301fbb: add $0x4,%esp 0x00301fbe: pop %ebx 0x00301fbf: pop %ebp 0x00301fc0: ret End of assembler dump. (gdb) p (char *) 0x301090 // 引数の内容を確認する $1 = 0x301090 "Hello, world!" (gdb) p puts // 関数 puts のアドレスを確認する $2 = {<text variable, no debug info>} 0x96c60f33 <puts> (gdb) p (void *) *0x443640 // シンボル puts の内容を確認する。 $3 = (void *) 0x96c60f33
また、マクロを使ってコンパイラにアクセス出来るので、シンボル puts の位置を確認する事が出来ます。
(define puts (dlsym "puts")) (syntax address ;;;; (address name) (lambda (form compiler) (let ((var [compiler lookupVariable: [form second]]) (result [var translateLvalue: compiler])) result))) (printf "Address of puts == 0x%x\n" puts) (printf "Address of table position of puts == 0x%x\n" (address puts)) (printf "Dereference == 0x%x\n" (long@ (address puts)))
$ ./jolt.sh boot.k indirect.k ; loading: boot.k Address of puts == 0x96c60f33 Address of table position of puts == 0x443640 Dereference == 0x96c60f33
というわけで、シンボル puts のメモリ上の位置が 0x443640 で、その内容 0x96c60f33 が関数 puts を指している事が分かるわけです。味気ない日記ですが、今日はこんな所で。
shortsleeved
2008/10/19 01:01
PowerPCなMacでやってみました。ニーモニックが笑えるくらい違っててびっくりでした。
propella
2008/10/19 14:29
へー。PowerPC でもちゃんと動くもんですね。どんな風になるのか見てみたいです。