龙空技术网

用JS实现一个字节码运行器

JShaman 246

前言:

当前朋友们对“汇编js”大体比较注重,你们都想要分析一些“汇编js”的相关文章。那么小编在网摘上汇集了一些有关“汇编js””的相关文章,希望看官们能喜欢,兄弟们一起来学习一下吧!

JS运行字节码、JS实现一个bytecode运行系统、js虚拟机。

用JS实现一个简单的虚拟机、一个字节码运行系统。运行的代码原理类似下面的形式:

 var program = [11,0,10,42,6,255,30,0,11,0,0,11,1,1,11,3,1,60,1,10,2,0,20,2,1,60,2,10,0,1,10,1,2,11,2,1,20,3,2,31,2,30,2,41,3,2,19,31,0,50];run(program);function run(program){...}

以下给出例程,该例程实现斐波那契(Fibonacci)算法。

斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)

示例代码:

//示例代码:const Fn = (n) => {    if(n === 0) { return 0; }    if(n === 1) { return 1; }    return Fn(n - 1) + Fn(n - 2);}

用ASM汇编风格的JS代码实现:

var code = `// Loads value 10 in R0 // and calls Fibonacci routineMOVV R0, 10CALL 6HALT// This is the Fibonacci routing// Expects number of Fibonacci // numbers in register R0PUSH R0MOVV R0, 0MOVV R1, 1MOVV R3, 1PRINT R1MOVR R2, R0ADD R2, R1PRINT R2MOVR R0, R1MOVR R1, R2MOVV R2, 1ADD R3, R2POP R2PUSH R2JL R3, R2, 19POP R0RET`;

接下来是将ASM转为字节码:

function assemble(code){    var bytes = asm_assemble(code);    return bytes.toString();}console.log(assemble(code));var byte_code = assemble(code);//运行字节码function run(txtBytes, txtOutput){    var bytes = getBytes(txtBytes);    bytecode_init(bytes, txtOutput);    bytecode_run();}run(byte_code)function getBytes(txt){    var bytes = txt.split(",");    for(var i = 0; i < bytes.length; i++)    {        bytes[i] = parseInt(bytes[i]);    }    return bytes;}

ByteCode字节码运行相关部分:

// r0, r1, r2, r3var regs = [0, 0, 0, 0];var stack = [];var program = [];var pc = 0;var halted = false;var txtOutput = null;function bytecode_init(prg, txtOut){  program = prg;  txtOutput = txtOut;    pc = 0;  halted = false;  stack = [];}function bytecode_run(){  while(!halted)  {      runone();  }}function runone(){  if (halted)      return;  var instr = program[pc];  switch(instr)  {      // movr rdst, rsrc      case 10:          pc++;          var rdst = program[pc++];          var rsrc = program[pc++];          regs[rdst] = regs[rsrc];          break;      // movv rdst, val      case 11:          pc++;          var rdst = program[pc++];          var val = program[pc++];          regs[rdst] = val;          break;      // add rdst, rsrc      case 20:          pc++;          var rdst = program[pc++];          var rsrc = program[pc++];          regs[rdst] += regs[rsrc];          break;      // sub rdst, rsrc      case 21:          pc++;          var rdst = program[pc++];          var rsrc = program[pc++];          regs[rdst] -= regs[rsrc];          break;      // push rsrc      case 30:          pc++;          var rsrc = program[pc++];          stack.push(regs[rsrc]);          break;      // pop rdst      case 31:          pc++;          var rdst = program[pc++];          regs[rdst] = stack.pop();          break;      // jp addr      case 40:          pc++;          var addr = program[pc++];          pc = addr;          break;      // jl r1, r2, addr      case 41:          pc++;          var r1 = program[pc++];          var r2 = program[pc++];          var addr = program[pc++];          if (regs[r1] < regs[r2])              pc = addr          break;      // call addr      case 42:          pc++;          var addr = program[pc++];          stack.push(pc);          pc = addr;          break;      // ret      case 50:          pc++;          var addr = stack.pop();          pc = addr;          break;      // print reg      case 60:          pc++;          var reg = program[pc++];          println(regs[reg]);          break;      // halt      case 255:          pc++;          halted = true;          break;            default:          println("Error in bytecode");          halted = true;          break;  }    if (pc >= program.length)  {      halted = true;  }}function println(txt){  console.log(txt)  if (txtOutput)      txtOutput.text += txt + "\n";}

汇编语法风格处理部分:

//ASM语法处理var instructions = {    MOVR : 10,    MOVV : 11,    ADD  : 20,    SUB  : 21,    PUSH : 30,    POP  : 31,    JP   : 40,    JL   : 41,    CALL : 42,    RET  : 50,    PRINT: 60,    HALT : 255}var registers = {    R0 : 0,    R1 : 1,    R2 : 2,    R3 : 3}function asm_assemble(code){    var tokens = getTokens(code);    var bytes = getBytecode(tokens);    return bytes;}function getBytecode(tokens){    var bytes = [];        for(var line of tokens)    {        for(var i = 0; i < line.length; i++)         {            var token = line[i].trim().toUpperCase();                        // First token in a line is assumed to be an instruction            if(i == 0)            {                token = instructions[token];                bytes.push(token ? token : -1);            }            else            {                // If operand start with R is assumed to be a register                if (token.startsWith("R"))                    token = registers[token];                                    bytes.push(parseInt(token));            }        }    }        return bytes;}function getTokens(code){    var arLines = code.split(/\r?\n/);        // Remove comments and empty lines    for(var i = arLines.length - 1; i >= 0; i--){        var txt = arLines[i].trim();        if (!txt || txt.startsWith("//"))        {            arLines.splice(i, 1);            continue;        }                // Split each line by " " or ,        arLines[i] = txt.split(/[\s,]+/);    }        return arLines;}  

将以上代码合并到一起,即可运行。运行时,先转换ASM代码为字节码,然后再解释执行字节码。

JS虚拟机、JS字节码(ByteCode)运行器,可用于JavaScript混淆加密,保护JS代码。但由于字节码或虚拟机中对于外部交互并不好处理,如前端的Dom、Node.JS中的环境变量等。所以,通常只能用于处理算法。如要对产品或项目中的JS代码混淆加密,建议使用JShaman等专业JS代码保护工具。

标签: #汇编js