Remove indirect function table patching
This commit is contained in:
parent
822d1efcff
commit
6298da7d34
2 changed files with 2 additions and 187 deletions
4
Makefile
4
Makefile
|
|
@ -178,14 +178,14 @@ build/v86.wasm: $(RUST_FILES) Cargo.toml
|
|||
mkdir -p build/
|
||||
-ls -lh build/v86.wasm
|
||||
cargo +nightly rustc --release $(CARGO_FLAGS)
|
||||
./tools/wasm-patch-indirect-function-table.js < build/wasm32-unknown-unknown/release/v86.wasm > build/v86.wasm
|
||||
mv build/wasm32-unknown-unknown/release/v86.wasm build/v86.wasm
|
||||
ls -lh build/v86.wasm
|
||||
|
||||
build/v86-debug.wasm: $(RUST_FILES) Cargo.toml
|
||||
mkdir -p build/
|
||||
-ls -lh build/v86-debug.wasm
|
||||
cargo +nightly rustc $(CARGO_FLAGS)
|
||||
./tools/wasm-patch-indirect-function-table.js < build/wasm32-unknown-unknown/debug/v86.wasm > build/v86-debug.wasm
|
||||
mv build/wasm32-unknown-unknown/debug/v86.wasm build/v86-debug.wasm
|
||||
ls -lh build/v86-debug.wasm
|
||||
|
||||
clean:
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
|
||||
// Read a wasm module in binary format from stdin, find table import entries, i.e.:
|
||||
//
|
||||
// (import "env" "table" (table (;0;) <initial> <maximum> anyfunc))
|
||||
//
|
||||
// Remove the <maximum> and write the patched wasm module to stdout.
|
||||
|
||||
process.on("unhandledRejection", exn => { throw exn; });
|
||||
|
||||
const assert = require("assert").strict;
|
||||
const fs = require("fs");
|
||||
|
||||
const SECTION_IMPORT = 2;
|
||||
|
||||
const IMPORT_KIND_FUNCTION = 0;
|
||||
const IMPORT_KIND_TABLE = 1;
|
||||
const IMPORT_KIND_MEMORY = 2;
|
||||
const IMPORT_KIND_GLOBAL = 3;
|
||||
|
||||
function main()
|
||||
{
|
||||
const wasm = fs.readFileSync("/dev/stdin");
|
||||
const view = new DataView(wasm.buffer);
|
||||
var ptr = 0;
|
||||
|
||||
// magic
|
||||
assert(view.getUint32(ptr, true) === 0x6d736100);
|
||||
ptr += 4;
|
||||
|
||||
// version
|
||||
assert(view.getUint32(ptr, true) === 1);
|
||||
ptr += 4;
|
||||
|
||||
while(ptr < view.byteLength)
|
||||
{
|
||||
const section_id = view.getUint8(ptr);
|
||||
ptr++;
|
||||
var { ptr, value: size } = read_leb_u32(ptr, view);
|
||||
const section_end = ptr + size;
|
||||
|
||||
if(section_id === SECTION_IMPORT)
|
||||
{
|
||||
patch_import_section(ptr, view);
|
||||
}
|
||||
|
||||
ptr = section_end;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
const module = new WebAssembly.Module(view.buffer);
|
||||
|
||||
process.stdout.write(wasm);
|
||||
}
|
||||
|
||||
function patch_import_section(ptr, view)
|
||||
{
|
||||
var { ptr, value: section_entry_count } = read_leb_u32(ptr, view);
|
||||
|
||||
for(let i = 0; i < section_entry_count; i++)
|
||||
{
|
||||
var { ptr, value: module_str_length } = read_leb_u32(ptr, view);
|
||||
ptr += module_str_length;
|
||||
var { ptr, value: field_str_length } = read_leb_u32(ptr, view);
|
||||
ptr += field_str_length;
|
||||
|
||||
const kind = view.getUint8(ptr);
|
||||
ptr++;
|
||||
|
||||
if(kind === IMPORT_KIND_FUNCTION)
|
||||
{
|
||||
var { ptr, value: function_signature_index } = read_leb_u32(ptr, view);
|
||||
}
|
||||
else if(kind === IMPORT_KIND_TABLE)
|
||||
{
|
||||
const table_offset = ptr;
|
||||
var { ptr, value: table_element_type } = read_leb_u32(ptr, view);
|
||||
assert(table_element_type === 0x70);
|
||||
|
||||
const maximum_present = new Uint8Array(view.buffer, ptr, 1);
|
||||
assert(maximum_present[0] === 0 || maximum_present[0] === 1);
|
||||
ptr++;
|
||||
|
||||
var { ptr, value: initial_table_size, leb_view: initial_table_size_view } = read_leb_u32(ptr, view);
|
||||
|
||||
if(maximum_present[0])
|
||||
{
|
||||
var { ptr, value: maximum_table_size, leb_view: maximum_table_size_view } = read_leb_u32(ptr, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
maximum_table_size = -1;
|
||||
}
|
||||
|
||||
console.error(`Found table import at offset` +
|
||||
` ${table_offset}` +
|
||||
` maximum_present=${maximum_present[0]}` +
|
||||
` initial=${initial_table_size}` +
|
||||
` maximum=${maximum_table_size}`);
|
||||
|
||||
if(maximum_present[0])
|
||||
{
|
||||
patch_maximum_limit(maximum_present, initial_table_size_view, maximum_table_size_view);
|
||||
console.error("Patched!");
|
||||
}
|
||||
else
|
||||
{
|
||||
console.error("No maximum present, skipped");
|
||||
}
|
||||
}
|
||||
else if(kind === IMPORT_KIND_MEMORY)
|
||||
{
|
||||
const maximum_present = view.getUint8(ptr);
|
||||
assert(maximum_present === 0 || maximum_present === 1);
|
||||
ptr++;
|
||||
|
||||
var { ptr, value: initial_memory_size } = read_leb_u32(ptr, view);
|
||||
|
||||
if(maximum_present)
|
||||
{
|
||||
var { ptr, value: maximum_memory_size } = read_leb_u32(ptr, view);
|
||||
}
|
||||
}
|
||||
else if(kind === IMPORT_KIND_GLOBAL)
|
||||
{
|
||||
const content_type = view.getUint8(ptr);
|
||||
ptr++;
|
||||
const mutability = view.getUint8(ptr);
|
||||
assert(mutability === 0 || mutability === 1);
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, `Unexpected import kind: 0x${kind.toString(16)} at offset ${ptr - 1}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function patch_maximum_limit(maximum_present, initial_size, maximum_size)
|
||||
{
|
||||
// clear the maximum present bit
|
||||
maximum_present[0] = 0;
|
||||
|
||||
// set the highest bit of the initial size, in order to use it to pad the existing maximum size bytes
|
||||
const last_byte_initial_size = initial_size[initial_size.length - 1];
|
||||
assert((last_byte_initial_size & 0x80) === 0);
|
||||
initial_size[initial_size.length - 1] = last_byte_initial_size | 0x80;
|
||||
|
||||
for(let i = 0; i < maximum_size.length - 1; i++)
|
||||
{
|
||||
// pad maximum value with 0x80 bytes
|
||||
maximum_size[i] = 0x80;
|
||||
}
|
||||
|
||||
// pad the last byte of the maximum value with 0x00
|
||||
maximum_size[maximum_size.length - 1] = 0x00;
|
||||
}
|
||||
|
||||
function read_leb_u32(ptr, view)
|
||||
{
|
||||
let value = 0;
|
||||
let byte_length = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
let byte = view.getUint8(ptr++);
|
||||
|
||||
value |= (byte & 0x7f) << (byte_length * 7);
|
||||
byte_length++;
|
||||
|
||||
if((byte & 0x80) === 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(byte_length <= 4);
|
||||
|
||||
const leb_view = new Uint8Array(view.buffer, ptr - byte_length, byte_length);
|
||||
|
||||
return { ptr, value, leb_view };
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue