以下のアセンブリ言語のコードをアセンブラしたものを実行するエミュレータ(アセンブリ言語のコードの更に下)を載せておきます
XOR AH, AH MOV AL, 0x03 INT 0x10 MOV SI, MESSAGE MOV AH, 0x0E mloop: MOV AL, [SI] OR AL, AL JE fin INT 0x10 ADD SI, 0x01 JMP mloop fin: JMP fin MESSAGE: DB "Hello World!", 0x0D, 0x0A, 0x00 TIMES 510 - ($ - $$) DB 0 DB 0x55, 0xAA
import java.io.FileInputStream; import java.io.BufferedInputStream; import java.io.IOException; public class Emulator{ private byte[] memory; //プログラムを格納するメモリ private int[] registers; //レジスタ郡 private int eip; //プログラムカウンタ private boolean zeroFlag; //ゼロフラグ private StringBuilder text; public static final int DEFAULT_MEMORY_SIZE = 1 * 1024 * 1024; public static final int AX = 0; public static final int CX = 1; public static final int DX = 2; public static final int BX = 3; public static final int SI = 6; public Emulator(int memorySize){ memory = new byte[memorySize]; //プログラムを格納する領域の確保 registers = new int[7]; //現在はレジスタ7つ目まで使う eip = 0; //プログラムカウンタ text = new StringBuilder(); } public void read(String fileName) throws IOException{ BufferedInputStream input = null; try{ input = new BufferedInputStream(new FileInputStream(fileName)); //プログラムを読み込む input.read(memory); input.close(); }catch(IOException e){ if(input != null){ try{ input.close(); }catch(IOException ioe){ throw ioe; } } throw e; } } public void execute(){ //オペコードの取得 int code = memory[eip] & 0xFF; //オペコードを表示する System.out.printf("code = %X\n", code); if(code == 0xB0){ movALImm8(); }else if(code == 0x04){ addALImm8(); }else if(code == 0xEB){ jmpShort(); }else if(code == 0x3C){ cmpALImm8(); }else if(code == 0x74){ jzShort(); }else if(code == 0x30){ xorRM8R8(); }else if(code == 0xCD){ interrupt(); }else if(code == 0xBE){ movSIImm16(); }else if(code == 0xB4){ movAHImm8(); }else if(code == 0x8A){ movR8RM8(); }else if(code == 0x08){ orRM8R8(); }else if(code == 0x83){ addRM16Imm8(); }else{ throw new RuntimeException("Not Implemented 0x" + Integer.toHexString(code)); } } private void movALImm8(){ //代入を行う int value = memory[eip + 1] & 0xFF; System.out.printf("MOV AL, 0x%X\n", value); setRegister8Low(Emulator.AX, value); eip += 2; } private void addALImm8(){ //足し算を行う int value = memory[eip + 1] & 0xFF; System.out.printf("ADD AL, 0x%X\n", value); int result = getRegister8Low(Emulator.AX)+ value; setRegister8Low(Emulator.AX, result); zeroFlag = result == 0 ? true : false; eip += 2; } private void jmpShort(){ //ジャンプ命令を実行する int value = memory[eip + 1]; System.out.printf("JMP 0x%X\n", value & 0xFF); eip += value; eip += 2; } private void cmpALImm8(){ //比較を行う int value = memory[eip + 1] & 0xFF; System.out.printf("CMP AL, 0x%X\n", value); int result = getRegister8Low(Emulator.AX) - value; zeroFlag = result == 0 ? true : false; eip += 2; } private void jzShort(){ //条件分岐 int value = memory[eip + 1]; System.out.printf("JZ 0x%X\n", value); if(zeroFlag){ eip += value; } eip += 2; } private void xorRM8R8(){ int modrm = memory[eip + 1] & 0xFF; if(modrm == 0xE4){ System.out.println("XOR AH, AH"); int ah = getRegister8High(Emulator.AX); int result = ah ^ ah; setRegister8High(Emulator.AX, result); zeroFlag = result == 0 ? true : false; }else{ throw new RuntimeException("xorRM8R8 Not Implemented modrm = " + Integer.toHexString(modrm)); } eip += 2; } private void interrupt(){ int index = memory[eip + 1] & 0xFF; int al = getRegister8Low(Emulator.AX); int ah = getRegister8High(Emulator.AX); if(index == 0x10){ System.out.println("INT 0x10"); if(ah == 0 && al == 0x03){ //このときは何もしない }else if(ah == 0x0E){ if(al == '\n'){ System.out.println(text); throw new RuntimeException(); }else{ System.out.println((char)al); text.append((char)al); } }else{ throw new RuntimeException("INT 0x10 実装されてない命令です"); } }else{ throw new RuntimeException("INT 0x" + Integer.toHexString(index) + " 実装されてない命令です"); } eip += 2; } private void movAHImm8(){ //代入を行う int value = memory[eip + 1] & 0xFF; System.out.printf("MOV AH, 0x%X\n", value); setRegister8High(Emulator.AX, value); eip += 2; } private void movSIImm16(){ //代入を行う int value = (memory[eip + 1] & 0xFF) | (memory[eip + 2] & 0xFF) << 8; System.out.printf("MOV SI, 0x%X\n", value); registers[Emulator.SI] = value; eip += 3; } private void movR8RM8(){ //代入を行う int modrm = memory[eip + 1] & 0xFF; if(modrm == 0x04){ System.out.println("MOV AL, [SI]"); setRegister8Low(Emulator.AX, memory[registers[Emulator.SI]] & 0xFF); }else{ throw new RuntimeException("movR8RM8 Not Implemented modrm = " + Integer.toHexString(modrm)); } eip += 2; } private void orRM8R8(){ int modrm = memory[eip + 1] & 0xFF; if(modrm == 0xC0){ System.out.println("OR AL, AL"); int al = getRegister8Low(Emulator.AX); int result = al | al; setRegister8Low(Emulator.AX, result); zeroFlag = result == 0 ? true : false; }else{ throw new RuntimeException("xorRM8R8 Not Implemented modrm = " + Integer.toHexString(modrm)); } eip += 2; } private void addRM16Imm8(){ int modrm = memory[eip + 1] & 0xFF; if(modrm == 0xC6){ int value = memory[eip + 2] & 0xFF; int result = registers[Emulator.SI] + value; registers[Emulator.SI] = result; zeroFlag = result == 0 ? true : false; } eip += 3; } //16bitレジスタの下位8bitを書き換える private void setRegister8Low(int index, int data){ registers[index] &= 0xFFFFFF00; registers[index] |= (data & 0xFF); } //16bitレジスタの上位8bitを書き換える private void setRegister8High(int index, int data){ registers[index] &= 0xFFFF00FF; registers[index] |= (data & 0xFF) << 8; } //16bitレジスタの下位8bitを返す private int getRegister8Low(int index){ return registers[index] & 0xFF; } //16bitレジスタの上位8bitを返す private int getRegister8High(int index){ return (registers[index] >> 8) & 0xFF; } public void dumpRegisters(){ //レジスタを全て出力する System.out.println(); System.out.println("Registers Value"); System.out.printf("AX = 0x%X\n", registers[Emulator.AX]); System.out.printf("CX = 0x%X\n", registers[Emulator.CX]); System.out.printf("DX = 0x%X\n", registers[Emulator.DX]); System.out.printf("BX = 0x%X\n", registers[Emulator.BX]); System.out.printf("EIP = 0x%X\n", eip); System.out.println("ZeroFlag = " + zeroFlag); } public static void main(String[] args){ if(args.length == 0){ System.out.println("引数で読み込むファイルを指定してください"); System.exit(0); } Emulator emulator = new Emulator(Emulator.DEFAULT_MEMORY_SIZE); try{ emulator.read(args[0]); while(true){ emulator.execute(); } }catch(IOException e){ System.out.println("ファイルの読み込みに失敗しました。"); e.printStackTrace(); }catch(RuntimeException e){ emulator.dumpRegisters(); e.printStackTrace(); } } }