9月 26th, 2009
Java逆アセンブラを作っていたときの話。
バイナリファイルを読み込んで色々するプログラムを書くので、
「バイナリストリームからNバイト読み込んで…」
といった関数を沢山書いたんですが、これのテストがやりにくいです。
ファイルを実際に開く以外に、バイナリストリームを作る方法を知らないので、
ちょっとしたテストをする場合にも、実際にファイルを作らないといけない。
これでは非常に面倒です。
文字ストリームを扱う関数をテストする場合には、
with-input-from-stream, with-output-to-stream
を使えば、対話環境で楽に試せるので、
これのバイナリストリーム版を作ってみました。
Gray Streamを使っています。
SBCLでテスト済み。
(defclass binary-array-input-stream (fundamental-binary-input-stream)
((array :initarg :array :type (array t (*)))
(index :initarg :start :type fixnum)
(end :initarg :end :type fixnum)))
(defun make-binary-array-input-stream (array &optional (start 0) end)
(make-instance 'binary-array-input-stream
:array array :start start :end (or end (length array))))
(defmethod stream-read-byte ((stream binary-array-input-stream))
(with-slots (index end array) stream
(if (>= index end)
:eof
(prog1 (aref array index)
(incf index)))))
(defmacro with-input-from-binary-array((var array)
&body body)
`(let ((,var (make-binary-array-input-stream ,array)))
(multiple-value-prog1
(unwind-protect
(progn ,@body)
(close ,var)))))
配列の型は本当は (array (unsigned-byte 8) (*)) の方がいいんでしょうが、
そうすると、 #(1 2 3) の記法が使えなくなって面倒なので指定を緩くしました。
ここで、次のような関数を作ったとします。
(defun byte-list->number (byte-list &optional little-endian-p)
(reduce #'(lambda (high low) (+ (ash high 8) low))
(if little-endian-p
(reverse byte-list)
byte-list)))
(defun read-byte-list (n stream)
(let (byte-list)
(dotimes (_ n (nreverse byte-list))
(push (read-byte stream) byte-list))))
これらの関数を対話環境でテストしたければ、次のようにします。
(with-input-from-binary-array (s #(1 44))
(let ((byte-list (read-byte-list 2 s)))
(format t "big endian: ~A~%" (byte-list->number byte-list))
(format t "little endian: ~A~%" (byte-list->number byte-list t))))
big endianは300、little endianは11265となり、ちゃんと動きます。
Posted in プログラミング | No Comments »
9月 23rd, 2009
Javaのアセンブラと逆アセンブラをCommon Lispで作りました。
一部対応してない命令がありますが、大体動作します。
アセンブリはもちろんS式で記述します。読み込むときはreadするだけ。
オペランドのない命令はアトム、オペランド付きの命令はリストとなっています。
とりあえずhello world。
;; ljTest.lja
(class "ljTest" "java/lang/Object" (public super)
method
("<init>" "()V" (public)
aload_0
(invokespecial "java/lang/Object" "" "()V")
return)
method
("main" "([Ljava/lang/String;)V" (public static)
(meta max-stack 2)
(getstatic "java/lang/System" "out" "Ljava/io/PrintStream;")
(ldc "hello world")
(invokevirtual "java/io/PrintStream" "println" "(Ljava/lang/String;)V")
return))
hello worldだけなのに長いです。さすがJava。
<init>というのはコンストラクタです。
% clisp
> (load "ljasm.lisp")
> (assemble-file "ljTest.java")
> (exit)
% java ljTest
hello world
こんな感じに動作します。
次は逆アセンブル。
// le.java
public class le{
public static void main(String args[]) {
try {
for (int i=5; i>=0; i--) {
System.out.println(100 / i);
}
} catch (ArithmeticException e) {
System.out.println("Nice exception...");
}
}
}
ループと例外が使われています。
% javac le.java
% clisp
> (load "ljasm.lisp")
> (disassemble-file "le.class")
> (exit)
これで次のようなファイルが作られます。
(整形は私が手作業でやりました)
(CLASS "le" "java/lang/Object" (PUBLIC SUPER)
INTERFACE NIL
METHOD
("" "()V" (PUBLIC)
(META MAX-STACK 1)
(META MAX-LOCAL 1)
ALOAD_0
(INVOKESPECIAL "java/lang/Object" "" "()V")
RETURN)
METHOD
("main" "([Ljava/lang/String;)V" (PUBLIC STATIC)
(META MAX-STACK 3)
(META MAX-LOCAL 2)
:L0
ICONST_5 ISTORE_1
:L2
ILOAD_1 (IFLT :L22)
(GETSTATIC "java/lang/System" "out" "Ljava/io/PrintStream;")
(BIPUSH 100) ILOAD_1 IDIV
(INVOKEVIRTUAL "java/io/PrintStream" "println" "(I)V")
(IINC 1 255) (GOTO :L2)
:L22
(GOTO :L34)
:L25
ASTORE_1 ;store exception object
(GETSTATIC "java/lang/System" "out" "Ljava/io/PrintStream;")
(LDC "Nice exception...")
(INVOKEVIRTUAL "java/io/PrintStream" "println" "(Ljava/lang/String;)V")
:L34
RETURN
(META EXCEPTION :L0 :L22 :L25 "java/lang/ArithmeticException"))
キーワードはラベルと見なされます。
逆アセンブリするときはラベル名は自動生成されます。
例外の指定は非常に地味です。 (META EXCEPTION …) の
最初の:L0と:L22は例外を捕まえる範囲、:L25は例外ハンドラです。
という訳で、それっぽく動いています。
めでたしめでたし。
Posted in プログラミング | 2 Comments »
9月 22nd, 2009
CLISPのVMにはJUMPTAILなんて命令があったのか。
Posted in マンガ | 2 Comments »
9月 14th, 2009
先にその5を読み直した方がいいかも。
白クダーはミャーと鳴く。
Posted in マンガ | No Comments »
9月 7th, 2009
setqの正しい発音は「せっときゅー」とHyperSpecに書いてある。
それでも私は「せっとく」と発音したい。
Posted in マンガ | No Comments »
9月 1st, 2009
気がついたら9月になっていた。
気がつかなければ良かったのに…
Posted in マンガ | No Comments »
8月 27th, 2009
ワーオ!
実はこっそり目次ページを作ってました。
Posted in マンガ | No Comments »
8月 14th, 2009
_ – –‐- 、
r‐ ´ト、 ヽ ‘ ,
ヽ! /コュ l
| ) l!`!/ ̄ ̄` ‐-ァ ぜんぶ、した
| く,. / 、>
.!l iト、.! /} ノトノ 過去問も、やりとげた
i! l!./ ./ } ‐’ _ノ’,
.l l // !|ニ! l、 もうじゅうぶんなぐらい…
V从乂人ノ /ヽ lヽ
l / ‘, l ‘ , この夏に一生ぶんの勉強がつまってた
| ヾ l :!: ヘ
|, ‘ `-r、 ! :l: ‘, いろいろなことあったけど…
/ ソ lニ>、l ! l
./ /-‐、 | :! ! わたし…がんばって、よかった
/ ! _ -‘:::! ! :|!
./ | ! } :|! l つらかったり、苦しかったりしたけど…
/ | ヾシ/レ’
(”T ‐r ァ-‐ ‐-、 :! !レ’ でも…がんばって、よかった
ソ i ! フー、! l
/ !i /ーr´ :l ゴールは…幸せといっしょだったから
/ l / / | !
/ l / / .! l
という訳で院試受かった。
Posted in 雑記 | 1 Comment »
8月 9th, 2009
明日は院試だ。
どうでもいいことだけど「マルチバンクキャッシュ」って銀行の用語っぽい。
Posted in マンガ | 2 Comments »
8月 5th, 2009
院試に落ちる夢を見た。
しかし、去年の春に単位が足りなくて4年生になれない夢を見たが、
普通に4年生になれたことを考えると、むしろ受かる兆候なのかもしれない。
Posted in マンガ | No Comments »