codegen.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #!/usr/bin/env node
  2. "use strict";
  3. process.on("unhandledRejection", exn => { throw exn; });
  4. const fs = require("fs");
  5. global.v86util = {};
  6. // copied from const.js
  7. global.WASM_TABLE_SIZE = 0x10000;
  8. // The space we need for misc internal state before the beginning of mem8; see global_pointers.h
  9. global.GUEST_MEMORY_START = 0x10000 + 0x100000 * 6;
  10. global.WASM_PAGE_SIZE = 64 * 1024;
  11. global.dbg_assert = x => console.assert(x);
  12. require("../../src/browser/lib.js");
  13. const Codegen = require("../../src/codegen.js");
  14. const codegen_module_buffer = fs.readFileSync(__dirname + "/../../build/codegen-test.wasm");
  15. const vals = {
  16. imm8: 1,
  17. imm8s: 1,
  18. imm16: 2,
  19. imm32s: 3,
  20. asize_32: false,
  21. reg16: 4,
  22. reg32s: 4,
  23. instruction_pointer: 556,
  24. previous_ip: 560,
  25. prefixes: 0,
  26. timestamp_counter: 0,
  27. };
  28. const wasm_test_funcs = {
  29. env: {
  30. _read_imm8() { return vals.imm8; },
  31. _read_imm8s() { return vals.imm8s; },
  32. _read_imm16() { return vals.imm16; },
  33. _read_imm32s() { return vals.imm32s; },
  34. _is_asize_32() { return vals.asize_32; },
  35. _has_flat_segmentation() { return false; },
  36. _printf(...args) { console.log(...args); },
  37. ___assert_fail(...args) { console.error(...args); console.assert(false); },
  38. abort() { console.assert(false); },
  39. },
  40. };
  41. const memory_size = 256 * 1024 * 1024;
  42. v86util.load_wasm(
  43. "build/codegen-test.wasm",
  44. wasm_test_funcs,
  45. memory_size + GUEST_MEMORY_START,
  46. WASM_TABLE_SIZE,
  47. wm => {
  48. try {
  49. test(new Codegen(wm));
  50. } catch(er) {
  51. console.error(er);
  52. process.exit(1);
  53. }
  54. }
  55. );
  56. function test(gen)
  57. {
  58. gen.reset();
  59. gen.fn0("fn0");
  60. gen.fn0("fn0_test_eip_order");
  61. gen.fn1("fn1", 0);
  62. gen.fn2("fn2", 0, 1);
  63. gen.increment_instruction_pointer(10);
  64. gen.set_previous_eip();
  65. gen.commit_instruction_body_to_cs();
  66. gen.modrm_fn0("fn1r");
  67. gen.modrm_fn1("fn2r", 2);
  68. vals.asize_32 = !vals.asize_32;
  69. gen.modrm_fn0("fn1r");
  70. gen.modrm_fn1("fn2r", 2);
  71. gen.commit_instruction_body_to_cs();
  72. // Test instruction_body buffer separation by leaving the following uncomitted:
  73. gen.fn0("fn0");
  74. gen.finish();
  75. let buf = gen.get_module_code();
  76. fs.writeFileSync(__dirname + "/../../build/codegen-test-output.wasm", buf);
  77. const module = new WebAssembly.Module(buf);
  78. const expected = [
  79. ["fn0"],
  80. ["fn0_test_eip_order"],
  81. ["fn1", 0],
  82. ["fn2", 0, 1],
  83. ["fn1r", 0],
  84. ["fn2r", 0, 0],
  85. ["fn1r", 0],
  86. ["fn2r", 0, 0],
  87. ];
  88. const store = [];
  89. const imports = {
  90. e: {
  91. fn0() { store.push(["fn0"]); },
  92. fn1(arg0) { store.push(["fn1", arg0]); },
  93. fn2(arg0, arg1) { store.push(["fn2", arg0, arg1]); },
  94. fn1r(arg0) { store.push(["fn1r", arg0]); },
  95. fn2r(arg0, arg1) { store.push(["fn2r", arg0, arg1]); },
  96. get_seg() {},
  97. m: new WebAssembly.Memory({ initial: memory_size / 64 / 1024 }),
  98. },
  99. };
  100. const view = new Uint32Array(imports.e.m.buffer);
  101. imports.e.fn0_test_eip_order = function()
  102. {
  103. store.push(["fn0_test_eip_order"]);
  104. // Since fn0 was commited from the instruction_body buffer _after_ the instruction pointer updates
  105. console.assert(view[vals.instruction_pointer >> 2] === 10);
  106. console.assert(view[vals.previous_ip >> 2] === 10);
  107. };
  108. const o = new WebAssembly.Instance(module, imports);
  109. o.exports.f();
  110. console.log(store);
  111. console.assert(JSON.stringify(store) === JSON.stringify(expected));
  112. }