mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-27 21:52:03 +00:00
Merge remote-tracking branch 'origin/master' into fix-leb-i64
# Conflicts: # Cargo.toml
This commit is contained in:
@ -12,6 +12,7 @@ fn main() {
|
|||||||
let module = match parity_wasm::deserialize_file(&args[1])
|
let module = match parity_wasm::deserialize_file(&args[1])
|
||||||
.expect("Failed to load module")
|
.expect("Failed to load module")
|
||||||
.parse_names()
|
.parse_names()
|
||||||
|
.and_then(|module| module.parse_reloc())
|
||||||
{
|
{
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err((errors, m)) => {
|
Err((errors, m)) => {
|
||||||
|
BIN
res/cases/v1/relocatable.wasm
Normal file
BIN
res/cases/v1/relocatable.wasm
Normal file
Binary file not shown.
@ -33,6 +33,7 @@ mod func;
|
|||||||
mod segment;
|
mod segment;
|
||||||
mod index_map;
|
mod index_map;
|
||||||
mod name_section;
|
mod name_section;
|
||||||
|
mod reloc_section;
|
||||||
|
|
||||||
pub use self::module::{Module, peek_size, ImportCountType};
|
pub use self::module::{Module, peek_size, ImportCountType};
|
||||||
pub use self::section::{
|
pub use self::section::{
|
||||||
@ -56,6 +57,9 @@ pub use self::name_section::{
|
|||||||
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
||||||
LocalNameSection,
|
LocalNameSection,
|
||||||
};
|
};
|
||||||
|
pub use self::reloc_section::{
|
||||||
|
RelocSection, RelocationEntry,
|
||||||
|
};
|
||||||
|
|
||||||
/// Deserialization from serial i/o
|
/// Deserialization from serial i/o
|
||||||
pub trait Deserialize : Sized {
|
pub trait Deserialize : Sized {
|
||||||
|
@ -7,6 +7,7 @@ use super::section::{
|
|||||||
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
||||||
};
|
};
|
||||||
use super::name_section::NameSection;
|
use super::name_section::NameSection;
|
||||||
|
use super::reloc_section::RelocSection;
|
||||||
|
|
||||||
const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
|
const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
|
||||||
|
|
||||||
@ -191,6 +192,47 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to parse reloc section in place
|
||||||
|
/// Corresponding custom section with proper header will convert to reloc sections
|
||||||
|
/// If some of them will fail to be decoded, Err variant is returned with the list of
|
||||||
|
/// (index, Error) tuples of failed sections.
|
||||||
|
pub fn parse_reloc(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
|
||||||
|
let mut parse_errors = Vec::new();
|
||||||
|
|
||||||
|
for (i, section) in self.sections.iter_mut().enumerate() {
|
||||||
|
if let Some(relocation_section) = {
|
||||||
|
if let Section::Custom(ref custom) = *section {
|
||||||
|
if custom.name().starts_with("reloc.") {
|
||||||
|
let mut rdr = io::Cursor::new(custom.payload());
|
||||||
|
let reloc_section = match RelocSection::deserialize(custom.name().to_owned(), &mut rdr) {
|
||||||
|
Ok(reloc_section) => reloc_section,
|
||||||
|
Err(e) => { parse_errors.push((i, e)); continue; }
|
||||||
|
};
|
||||||
|
if rdr.position() != custom.payload().len() as u64 {
|
||||||
|
parse_errors.push((i, io::Error::from(io::ErrorKind::InvalidData).into()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(Section::Reloc(reloc_section))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
*section = relocation_section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parse_errors.len() > 0 {
|
||||||
|
Err((parse_errors, self))
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Count imports by provided type
|
/// Count imports by provided type
|
||||||
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
||||||
self.import_section()
|
self.import_section()
|
||||||
|
346
src/elements/reloc_section.rs
Normal file
346
src/elements/reloc_section.rs
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
|
use super::{CountedList, CountedListWriter, CountedWriter, Deserialize, Error, Serialize, VarInt32, VarUint32, VarUint7};
|
||||||
|
|
||||||
|
const FUNCTION_INDEX_LEB: u8 = 0;
|
||||||
|
const TABLE_INDEX_SLEB: u8 = 1;
|
||||||
|
const TABLE_INDEX_I32: u8 = 2;
|
||||||
|
const MEMORY_ADDR_LEB: u8 = 3;
|
||||||
|
const MEMORY_ADDR_SLEB: u8 = 4;
|
||||||
|
const MEMORY_ADDR_I32: u8 = 5;
|
||||||
|
const TYPE_INDEX_LEB: u8 = 6;
|
||||||
|
const GLOBAL_INDEX_LEB: u8 = 7;
|
||||||
|
|
||||||
|
/// Relocation information.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct RelocSection {
|
||||||
|
/// Name of this section.
|
||||||
|
name: String,
|
||||||
|
|
||||||
|
/// ID of the section containing the relocations described in this section.
|
||||||
|
section_id: u32,
|
||||||
|
|
||||||
|
/// Name of the section containing the relocations described in this section. Only set if section_id is 0.
|
||||||
|
relocation_section_name: Option<String>,
|
||||||
|
|
||||||
|
/// Relocation entries.
|
||||||
|
entries: Vec<RelocationEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelocSection {
|
||||||
|
/// Name of this section.
|
||||||
|
pub fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name of this section (mutable).
|
||||||
|
pub fn name_mut(&mut self) -> &mut String {
|
||||||
|
&mut self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ID of the section containing the relocations described in this section.
|
||||||
|
pub fn section_id(&self) -> u32 {
|
||||||
|
self.section_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ID of the section containing the relocations described in this section (mutable).
|
||||||
|
pub fn section_id_mut(&mut self) -> &mut u32 {
|
||||||
|
&mut self.section_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name of the section containing the relocations described in this section.
|
||||||
|
pub fn relocation_section_name(&self) -> Option<&str> {
|
||||||
|
self.relocation_section_name.as_ref().map(String::as_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Name of the section containing the relocations described in this section (mutable).
|
||||||
|
pub fn relocation_section_name_mut(&mut self) -> &mut Option<String> {
|
||||||
|
&mut self.relocation_section_name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of relocation entries.
|
||||||
|
pub fn entries(&self) -> &[RelocationEntry] {
|
||||||
|
&self.entries
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of relocation entries (mutable).
|
||||||
|
pub fn entries_mut(&mut self) -> &mut Vec<RelocationEntry> {
|
||||||
|
&mut self.entries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelocSection {
|
||||||
|
/// Deserialize a reloc section.
|
||||||
|
pub fn deserialize<R: Read>(
|
||||||
|
name: String,
|
||||||
|
rdr: &mut R,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let section_id = VarUint32::deserialize(rdr)?.into();
|
||||||
|
|
||||||
|
let relocation_section_name =
|
||||||
|
if section_id == 0 {
|
||||||
|
Some(String::deserialize(rdr)?)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let entries = CountedList::deserialize(rdr)?.into_inner();
|
||||||
|
|
||||||
|
Ok(RelocSection {
|
||||||
|
name,
|
||||||
|
section_id,
|
||||||
|
relocation_section_name,
|
||||||
|
entries,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for RelocSection {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
|
let mut counted_writer = CountedWriter::new(wtr);
|
||||||
|
|
||||||
|
self.name.serialize(&mut counted_writer)?;
|
||||||
|
|
||||||
|
VarUint32::from(self.section_id).serialize(&mut counted_writer)?;
|
||||||
|
|
||||||
|
if let Some(relocation_section_name) = self.relocation_section_name {
|
||||||
|
relocation_section_name.serialize(&mut counted_writer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let counted_list = CountedListWriter(self.entries.len(), self.entries.into_iter());
|
||||||
|
counted_list.serialize(&mut counted_writer)?;
|
||||||
|
|
||||||
|
counted_writer.done()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Relocation entry.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum RelocationEntry {
|
||||||
|
/// Function index.
|
||||||
|
FunctionIndexLeb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the function symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Function table index.
|
||||||
|
TableIndexSleb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the function symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Function table index.
|
||||||
|
TableIndexI32 {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the function symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Linear memory index.
|
||||||
|
MemoryAddressLeb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the data symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
|
||||||
|
/// Addend to add to the address.
|
||||||
|
addend: i32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Linear memory index.
|
||||||
|
MemoryAddressSleb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the data symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
|
||||||
|
/// Addend to add to the address.
|
||||||
|
addend: i32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Linear memory index.
|
||||||
|
MemoryAddressI32 {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the data symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
|
||||||
|
/// Addend to add to the address.
|
||||||
|
addend: i32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Type table index.
|
||||||
|
TypeIndexLeb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the type used.
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Global index.
|
||||||
|
GlobalIndexLeb {
|
||||||
|
/// Offset of the value to rewrite.
|
||||||
|
offset: u32,
|
||||||
|
|
||||||
|
/// Index of the global symbol in the symbol table.
|
||||||
|
index: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deserialize for RelocationEntry {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Self::Error> {
|
||||||
|
match VarUint7::deserialize(rdr)?.into() {
|
||||||
|
FUNCTION_INDEX_LEB => Ok(RelocationEntry::FunctionIndexLeb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
TABLE_INDEX_SLEB => Ok(RelocationEntry::TableIndexSleb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
TABLE_INDEX_I32 => Ok(RelocationEntry::TableIndexI32 {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
MEMORY_ADDR_LEB => Ok(RelocationEntry::MemoryAddressLeb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
addend: VarInt32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
MEMORY_ADDR_SLEB => Ok(RelocationEntry::MemoryAddressSleb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
addend: VarInt32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
MEMORY_ADDR_I32 => Ok(RelocationEntry::MemoryAddressI32 {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
addend: VarInt32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
TYPE_INDEX_LEB => Ok(RelocationEntry::TypeIndexLeb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
GLOBAL_INDEX_LEB => Ok(RelocationEntry::GlobalIndexLeb {
|
||||||
|
offset: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
index: VarUint32::deserialize(rdr)?.into(),
|
||||||
|
}),
|
||||||
|
|
||||||
|
entry_type => Err(Error::UnknownValueType(entry_type as i8)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for RelocationEntry {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
|
match self {
|
||||||
|
RelocationEntry::FunctionIndexLeb { offset, index } => {
|
||||||
|
VarUint7::from(FUNCTION_INDEX_LEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::TableIndexSleb { offset, index } => {
|
||||||
|
VarUint7::from(TABLE_INDEX_SLEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::TableIndexI32 { offset, index } => {
|
||||||
|
VarUint7::from(TABLE_INDEX_I32).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::MemoryAddressLeb { offset, index, addend } => {
|
||||||
|
VarUint7::from(MEMORY_ADDR_LEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
VarInt32::from(addend).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::MemoryAddressSleb { offset, index, addend } => {
|
||||||
|
VarUint7::from(MEMORY_ADDR_SLEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
VarInt32::from(addend).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::MemoryAddressI32 { offset, index, addend } => {
|
||||||
|
VarUint7::from(MEMORY_ADDR_I32).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
VarInt32::from(addend).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::TypeIndexLeb { offset, index } => {
|
||||||
|
VarUint7::from(TYPE_INDEX_LEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
|
||||||
|
RelocationEntry::GlobalIndexLeb { offset, index } => {
|
||||||
|
VarUint7::from(GLOBAL_INDEX_LEB).serialize(wtr)?;
|
||||||
|
VarUint32::from(offset).serialize(wtr)?;
|
||||||
|
VarUint32::from(index).serialize(wtr)?;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::super::{Section, deserialize_file};
|
||||||
|
use super::RelocationEntry;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reloc_section() {
|
||||||
|
let module =
|
||||||
|
deserialize_file("./res/cases/v1/relocatable.wasm").expect("Module should be deserialized")
|
||||||
|
.parse_reloc().expect("Reloc section should be deserialized");
|
||||||
|
let mut found = false;
|
||||||
|
for section in module.sections() {
|
||||||
|
match *section {
|
||||||
|
Section::Reloc(ref reloc_section) => {
|
||||||
|
assert_eq!(vec![
|
||||||
|
RelocationEntry::MemoryAddressSleb { offset: 4, index: 0, addend: 0 },
|
||||||
|
RelocationEntry::FunctionIndexLeb { offset: 12, index: 0 },
|
||||||
|
], reloc_section.entries());
|
||||||
|
found = true
|
||||||
|
},
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(found, "There should be a reloc section in relocatable.wasm");
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ use super::{
|
|||||||
|
|
||||||
use super::types::Type;
|
use super::types::Type;
|
||||||
use super::name_section::NameSection;
|
use super::name_section::NameSection;
|
||||||
|
use super::reloc_section::RelocSection;
|
||||||
|
|
||||||
const ENTRIES_BUFFER_LENGTH: usize = 16384;
|
const ENTRIES_BUFFER_LENGTH: usize = 16384;
|
||||||
|
|
||||||
@ -64,6 +65,13 @@ pub enum Section {
|
|||||||
///
|
///
|
||||||
/// Note that initially it is not parsed until `parse_names` is called explicitly.
|
/// Note that initially it is not parsed until `parse_names` is called explicitly.
|
||||||
Name(NameSection),
|
Name(NameSection),
|
||||||
|
/// Relocation section.
|
||||||
|
///
|
||||||
|
/// Note that initially it is not parsed until `parse_reloc` is called explicitly.
|
||||||
|
/// Also note that currently there are serialization (but not de-serialization)
|
||||||
|
/// issues with this section
|
||||||
|
/// (see https://github.com/paritytech/parity-wasm/issues/198)
|
||||||
|
Reloc(RelocSection),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Section {
|
impl Deserialize for Section {
|
||||||
@ -191,7 +199,11 @@ impl Serialize for Section {
|
|||||||
payload: serialize(name_section)?,
|
payload: serialize(name_section)?,
|
||||||
};
|
};
|
||||||
custom.serialize(writer)?;
|
custom.serialize(writer)?;
|
||||||
}
|
},
|
||||||
|
Section::Reloc(reloc_section) => {
|
||||||
|
VarUint7::from(0x00).serialize(writer)?;
|
||||||
|
reloc_section.serialize(writer)?;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -214,6 +226,7 @@ impl Section {
|
|||||||
Section::Code(_) => 0x0a,
|
Section::Code(_) => 0x0a,
|
||||||
Section::Data(_) => 0x0b,
|
Section::Data(_) => 0x0b,
|
||||||
Section::Name(_) => 0x00,
|
Section::Name(_) => 0x00,
|
||||||
|
Section::Reloc(_) => 0x00,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user