コンパイラ実装会(3)に参加してきた。その3

前回に引き続き、今回は、brainfuckのコード から アセンブラのコード を生成して出力する node.jsのコードを作成しました。
想定している環境は、Linuxx86_64です。

ネット上のアセンブラの情報がNASMとGASとIntel記法とAT&T記法でごちゃってて、ちょっと一苦労。。。
アセンブラにもNASMとGAS等があり、今回は、GASを。
記法はIntel記法とAT&T記法がありますが、Intel記法です。

bf2asm.js

var fs = require('fs');

var cmds = "";
var indent = 0;
var code = fs.readFileSync('data','utf-8');

var trans = function(code) {
  var arr = code.split('');
  while(arr.length != 0){
    var c = arr.shift();
    switch (c) {
    case '+' : 
      cmds += 'inc byte ptr[esi]\n';
      break;
    case '-' :
      cmds += 'dec byte ptr[esi]\n';
      break;
    case '>' :
      cmds += 'inc esi\n';
      break;
    case '<' :
      cmds += 'dec esi\n';
      break;
    case '.' :
      cmds += 'mov edx, 0x1\n';
      cmds += 'mov ecx, esi\n';
      cmds += 'mov ebx, 0x1\n';
      cmds += 'mov eax, 0x4\n';
      cmds += 'int 0x80\n';
      break;
    //case ',' :
      //cmds += 'ptr = getchar();\n';  
      //break;
    case '[' :
      cmds += indent*2 + ':\n';
      cmds += 'cmp byte ptr [esi],0\n';
      cmds += 'jz ' + (indent*2+1) + 'f\n';
      indent += 1;
      break;
    case ']' :
      indent -= 1;
      cmds += 'jmp ' + indent*2 + "b\n";
      cmds += (indent*2+1) + ':\n';
      break;
    default:
    }
  }
  return cmds;
}

var out = '';
out += '.intel_syntax noprefix\n';
out += '.comm mem, 30000\n';
out += '.code64\n';
out += '.globl _start\n';
out += '_start:\n';
out += 'lea esi, mem\n';
out += trans(code);
out += 'xor ebx,ebx\n';
out += 'mov eax,0x1\n';
out += 'int 0x80\n';

fs.writeFileSync('./bf.s',out,'utf-8');

data (brainfuckのHelloコード)

>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++
++>-]<.>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>
++++++++[<++++>-]<+.[-]++++++++++.

実行方法

$ node bf2asm.js
$ as bf.s -o bf.o
$ ld bf.o
$ ./a.out 
Hello World!