Skip to content

Commit

Permalink
add remapstart
Browse files Browse the repository at this point in the history
  • Loading branch information
jwasinger committed Jun 6, 2019
1 parent d8bae4a commit 1e020e0
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 2 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ Wraps module into an ewasm-compatible constructor. It has two presets:

Re-serializes the module. It will drop any unknown (custom) sections.

### remapstart

If there is a start section, export it as `main` (replacing any pre-existing `main` export) and remove the start section

## CLI

`chisel` is available as a command line tool.
Expand Down
12 changes: 10 additions & 2 deletions chisel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use std::fs::{read, read_to_string};
use std::process;

use libchisel::{
checkstartfunc::*, deployer::*, remapimports::*, repack::*, trimexports::*, trimstartfunc::*,
verifyexports::*, verifyimports::*,
checkstartfunc::*, deployer::*, remapimports::*, remapstart::*, repack::*, trimexports::*,
trimstartfunc::*, verifyexports::*, verifyimports::*,
};

use clap::{App, Arg, ArgMatches, SubCommand};
Expand Down Expand Up @@ -241,6 +241,14 @@ fn execute_module(context: &ModuleContext, module: &mut Module) -> bool {
Err("remapimports: Invalid preset")
}
}
"remapstart" => {
is_translator = true;
if let Ok(chisel) = RemapStart::with_preset(&preset) {
translate_module(module, chisel)
} else {
Err("remapimports: Invalid preset")
}
}
"deployer" => {
is_translator = true;
let mut payload = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions libchisel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod imports;
pub mod checkstartfunc;
pub mod deployer;
pub mod remapimports;
pub mod remapstart;
pub mod repack;
pub mod trimexports;
pub mod trimstartfunc;
Expand Down
258 changes: 258 additions & 0 deletions libchisel/src/remapstart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
use parity_wasm::elements::*;
use std::collections::HashMap;

use super::{ModuleError, ModulePreset, ModuleTranslator};

pub struct RemapStart;

impl ModulePreset for RemapStart {
fn with_preset(preset: &str) -> Result<Self, ()> {
match preset {
// TODO refactor this later
"ewasm" => Ok(RemapStart {}),
_ => Err(()),
}
}
}

impl ModuleTranslator for RemapStart {
fn translate_inplace(&self, module: &mut Module) -> Result<bool, ModuleError> {
Ok(remap_start(module))
}

fn translate(&self, module: &Module) -> Result<Option<Module>, ModuleError> {
let mut ret = module.clone();
if remap_start(&mut ret) {
Ok(Some(ret))
} else {
Ok(None)
}
}
}

fn clear_names_section(module: &mut Module) {
let sections = module.sections_mut();
let mut rmidx = sections.len();
for (index, section) in sections.iter_mut().enumerate() {
if let Section::Name(_) = section {
rmidx = index;
break;
}
}
if rmidx < sections.len() {
sections.remove(rmidx);
}
}

// replace an exported function with another function
fn replace_export(module: &mut Module, export_name: &str, func_idx: u32) {

if let Some(mut export_section) = module.export_section_mut() {
for export_entry in export_section.entries_mut().iter_mut() {
if *export_entry.field() == export_name.to_string() {
*export_entry =
ExportEntry::new(export_name.to_string(), Internal::Function(func_idx));
}
}
} else {
module
.sections_mut()
.push(Section::Export(ExportSection::with_entries(vec![
ExportEntry::new(export_name.to_string(), Internal::Function(func_idx)),
])));
}
}

fn remap_start(module: &mut Module) -> bool {
let start_func_idx = match module.start_section() {
Some(idx) => idx,
None => {
return false;
}
};

if module.names_section().is_some() {
clear_names_section(module);
}

replace_export(module, "main", start_func_idx);

module.clear_start_section();

true
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{ModulePreset, ModuleTranslator, ModuleValidator};
use parity_wasm;
use rustc_hex::FromHex;
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::prelude::*;

#[test]
fn remapstart_mutation() {
//wat:
//(module
// (import "env" "ethereum_useGas" (func (param i64)))
// (memory 1)
// (export "main" (func $main))
// (export "memory" (memory 0))
// (func $main2)
// (func $main)
// (start $main2)
//)

let wasm: Vec<u8> = FromHex::from_hex(
"0061736d0100000001080260017e0060
000002170103656e760f657468657265756d5f75736547617300000303020101050301000107110
2046d61696e0001066d656d6f727902000801020a070202000b02000b0020046e616d65010e0201
046d61696e02056d61696e320209030001000001000200",
)
.unwrap();

let mut module: Module = parity_wasm::deserialize_buffer::<Module>(&wasm).unwrap();
module = module.parse_names().unwrap();
assert!(module.names_section().is_some());

let mut new = RemapStart::with_preset("ewasm")
.unwrap()
.translate(&module)
.expect("Module internal error")
.expect("new module not returned");

assert!(
new.start_section().is_none(),
"start section wasn't removed"
);
assert!(new.names_section().is_none(), "name section wasn't removed");
}

#[test]
fn remapstart_no_mutation() {
// (module
// (import "env" "ethereum_useGas" (func (param i64)))
// (memory 1)
// (export "main" (func $main))
// (export "memory" (memory 0))
// (func $main)
//)

let wasm: Vec<u8> = FromHex::from_hex(
"0061736d0100000001080260017e0060
000002170103656e760f657468657265756d5f757365476173000003020101050301000
1071102046d61696e0001066d656d6f727902000a040102000b",
)
.unwrap();

let mut module: Module = parity_wasm::deserialize_buffer::<Module>(&wasm).unwrap();

let mut new = RemapStart::with_preset("ewasm")
.unwrap()
.translate(&module)
.expect("Module internal error");

assert!(new.is_none());
}

#[test]
fn remapstart_inplace_mutation() {
//wat:
//(module
// (import "env" "ethereum_useGas" (func (param i64)))
// (memory 1)
// (export "main" (func $main))
// (export "memory" (memory 0))
// (func $main2)
// (func $main)
// (start $main2)
//)

let wasm: Vec<u8> = FromHex::from_hex(
"0061736d0100000001080260017e0060
000002170103656e760f657468657265756d5f75736547617300000303020101050301000107110
2046d61696e0001066d656d6f727902000801020a070202000b02000b0020046e616d65010e0201
046d61696e02056d61696e320209030001000001000200",
)
.unwrap();

let mut module: Module = parity_wasm::deserialize_buffer::<Module>(&wasm).unwrap();
module = module.parse_names().unwrap();
assert!(module.names_section().is_some());

let res = RemapStart::with_preset("ewasm")
.unwrap()
.translate_inplace(&mut module)
.unwrap();

assert!(res, "module was not modified");
assert!(
module.start_section().is_none(),
"start section wasn't removed"
);
assert!(
module.names_section().is_none(),
"name section wasn't removed"
);
}

#[test]
fn remapstart_inplace_no_mutation() {
// (module
// (import "env" "ethereum_useGas" (func (param i64)))
// (memory 1)
// (export "main" (func $main))
// (export "memory" (memory 0))
// (func $main)
//)

let wasm: Vec<u8> = FromHex::from_hex(
"0061736d0100000001080260017e0060
000002170103656e760f657468657265756d5f75736547617300000302010105030100010711020
46d61696e0001066d656d6f727902000a040102000b",
)
.unwrap();

let mut module: Module = parity_wasm::deserialize_buffer::<Module>(&wasm).unwrap();

let res = RemapStart::with_preset("ewasm")
.unwrap()
.translate_inplace(&mut module)
.unwrap();

assert!(!res, "module was modified");
}

#[test]
fn remapstart_mutation_no_exports() {
//wat:
//(module
// (import "env" "ethereum_useGas" (func (param i64)))
// (memory 1)
// (func $main2)
// (func $main)
// (start $main2)
//)

let wasm: Vec<u8> = FromHex::from_hex(
"0061736d0100000001080260017e0060000002170103656e760f657468657265756d5f7573654761730000030302010105030100010801010a070202000b02000b",
)
.unwrap();

let mut module: Module = parity_wasm::deserialize_buffer::<Module>(&wasm).unwrap();

let res = RemapStart::with_preset("ewasm")
.unwrap()
.translate_inplace(&mut module)
.unwrap();

assert!(res, "module was not modified");
assert!(
module.export_section().is_some(),
"export section does not exist"
);
}
}

0 comments on commit 1e020e0

Please sign in to comment.