最初にJVM仕様を見つけます。 ご覧のとおり、Javaクラスファイルは以下で構成されています。
- マジックナンバー、常に0xCAFEBABE
- マイナーバージョンとメジャーバージョン。Java7の場合、それぞれ0と51です。
- 定数プール要素の数と要素自体については、以下で説明します。
- アクセスフラグ、現在のクラスを示す定数の数、親クラスを示す定数の数。
- 実装されたインターフェイスの数と、プール内の記述子の数の配列。
- フィールドの数、フィールド記述子の配列。
- メソッドの数、メソッド記述子の配列。
- 属性の数、属性の配列。
Javaでは、ビッグエンディアンの順序が受け入れられますが、FASMはx86のアセンブラーであり、リトルエンディアンが採用されているため、すぐに数値をある順序から別の順序に変換するマクロを作成します。
u1 equ db ; u1 - 1 , macro u2 [data] { ; u2 - 2 forward ; , u2 0x1234, 0x5678 ; u1 (((data) shr 8) and 0xFF) ; u1 ((data) and 0xFF) ; } macro u4 [data] { ; u4 - 4 , u2 forward u2 (((data) shr 16) and 0xFFFF) u2 ((data) and 0xFFFF) }
一般に、FASMマクロ言語は非常に強力であるため、一方向ではなく、別の言語を記述できます。
定数プールは非常に紛らわしく配置されており、1つの記述子が別の記述子を参照し、3番目の記述子を参照しますが、それを把握することができます。
一般的な場合の定数プールの要素は次のようになります。
cp_info { u1 tag; u1 info[]; }
タグの完全なリストはドキュメントに記載されていますが、詳細については説明しません。 プールのサイズ(およびメソッド、フィールドなど)を自動的に計算するために使用したトリックについて説明します。
const#nameという形式の構築-テキストconstと定数名の値を結び付けます。 設計は、Cマクロの設計に似ています。
const_count = 0 macro const name* { ; const_#name: const_count = const_count + 1 name = const_count ; (FASM ) }
FASMの用語では、定数は定数と呼ばれますが、実際には変数のように動作し、それらを使用して多くの操作を実行できます。
次に、開始および終了するマクロを宣言します。
macro ConstantPool { u2 const_count_end + 1 ; ; +1 0 , }
しかし、そのような変数は存在しません、とあなたは言います。 そして、あなたは正しいでしょう。 まだ存在しません。 FASMはマルチパスアセンブラーであり、最初のパスで見つからなかったものは、2番目以降のパスで記憶して接続します。
macro ConstantPoolEnd { UTF8 code_attr, 'Code' const_count_end = const_count ; . }
次のパスで、アセンブラはconst_count_endの代わりにできるだけ多くの定数を置き換えます。
メソッドとフィールドは同様の方法で編成されます。 メソッド定数を生成するマクロの例を挙げましょう
macro UTF8 name, text { const name u1 1 ; tag u2 .end - .start .start: u1 text .end: } macro Class name, className { UTF8 className_#name, className const name u1 7 ; tag u2 className_#name } macro NameAndType name, nameText, typeText { UTF8 name_#name, nameText UTF8 type_#name, typeText const name u1 12 ; tag u2 name_#name u2 type_#name } macro Method name, className, methodName, methodType { Class class_#name, className ; Class NameAndType nameAndType_#name, methodName, methodType ; NameAndType const name u1 10 ; tag u2 class_#name u2 nameAndType_#name }
ここで、リンクがどのように進むかを見ることができます-メソッドはクラスを参照し、クラスはUTF8を参照し、NameAndTypeも参照します。 引数は、
Method printlnInt, 'java/io/PrintStream', 'println', '(I)V'
などの文字列としてマクロに渡されます。
そして最後に、ソース自体:
format binary as 'class' include 'java.inc' ; --- FILE --- magic: u4 0xCAFEBABE version: u4 51 ConstantPool Class this, 'java' Class super, 'java/lang/Object' UTF8 main, 'main' UTF8 main_sig, '([Ljava/lang/String;)V' Field o, 'java/lang/System', 'out', 'Ljava/io/PrintStream;' Method println, 'java/io/PrintStream', 'println', '(Ljava/lang/String;)V' Method printlnInt, 'java/io/PrintStream', 'println', '(I)V' String hello, 'Hello World!' ConstantPoolEnd u2 PUBLIC, this, super, 0, 0 ; , , Methods MethodStart PUBLIC or STATIC, main, main_sig, 2, 1 getstatic o ldc hello ; , invokevirtual println getstatic o bipush 42 invokevirtual printlnInt return MethodEnd MethodsEnd u2 0 ;
»完全なコードはこちらにあります 。
ご清聴ありがとうございました!