bitflags::bitflags! { /// Flags for WebAssembly symbols. /// /// These flags correspond to those described in /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md> /// with the `WASM_SYM_*` prefix. #[repr(transparent)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pubstruct SymbolFlags: u32 { /* N.B.: Newlyaddedflagsshouldbekeepinsyncwith`print_dylink0_flags` in`crates/wasmprinter/src/lib.rs`.
*/ /// This is a weak symbol. const BINDING_WEAK = 1 << 0; /// This is a local symbol (this is exclusive with [BINDING_WEAK]). const BINDING_LOCAL = 1 << 1; /// This is a hidden symbol. const VISIBILITY_HIDDEN = 1 << 2; /// This symbol is not defined. const UNDEFINED = 1 << 4; /// This symbol is intended to be exported from the wasm module to the host environment. const EXPORTED = 1 << 5; /// This symbol uses an explicit symbol name, rather than reusing the name from a wasm import. const EXPLICIT_NAME = 1 << 6; /// This symbol is intended to be included in the linker output, regardless of whether it is used by the program. const NO_STRIP = 1 << 7; /// This symbol resides in thread local storage. const TLS = 1 << 8; /// This symbol represents an absolute address. const ABSOLUTE = 1 << 9;
}
/// Flags for WebAssembly segments. /// /// These flags are defined by implementation at the time of writing: /// <https://github.com/llvm/llvm-project/blob/llvmorg-17.0.6/llvm/include/llvm/BinaryFormat/Wasm.h#L391-L394> #[repr(transparent)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] pubstruct SegmentFlags: u32 { /// The segment contains only null-terminated strings, which allows the linker to perform merging. const STRINGS = 0x1; /// The segment contains thread-local data. const TLS = 0x2;
}
}
/// A reader for the `linking` custom section of a WebAssembly module. /// /// This format is currently defined upstream at /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>. #[derive(Debug, Clone)] pubstruct LinkingSectionReader<'a> { /// The version of linking metadata contained in this section.
version: u32, /// The subsections in this section.
subsections: Subsections<'a, Linking<'a>>, /// The range of the entire section, including the version.
range: Range<usize>,
}
/// Represents a reader for segments from the linking custom section. pubtype SegmentMap<'a> = SectionLimited<'a, Segment<'a>>;
/// Represents extra metadata about the data segments. #[derive(Debug, Copy, Clone)] pubstruct Segment<'a> { /// The name for the segment. pub name: &'a str, /// The required alignment of the segment, encoded as a power of 2. pub alignment: u32, /// The flags for the segment. pub flags: SegmentFlags,
}
impl<'a> FromReader<'a> for Segment<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let name = reader.read_string()?; let alignment = reader.read_var_u32()?; let flags = reader.read()?;
Ok(Self {
name,
alignment,
flags,
})
}
}
/// Represents a reader for init functions from the linking custom section. pubtype InitFuncMap<'a> = SectionLimited<'a, InitFunc>;
/// Represents an init function in the linking custom section. #[derive(Debug, Copy, Clone)] pubstruct InitFunc { /// The priority of the init function. pub priority: u32, /// The symbol index of init function (*not* the function index). pub symbol_index: u32,
}
impl<'a> FromReader<'a> for InitFunc { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let priority = reader.read_var_u32()?; let symbol_index = reader.read_var_u32()?;
Ok(Self {
priority,
symbol_index,
})
}
}
/// Represents a reader for COMDAT data from the linking custom section. pubtype ComdatMap<'a> = SectionLimited<'a, Comdat<'a>>;
/// Represents [COMDAT](https://llvm.org/docs/LangRef.html#comdats) data in the linking custom section. #[derive(Debug, Clone)] pubstruct Comdat<'a> { /// The name of this comdat. pub name: &'a str, /// The flags. pub flags: u32, /// The member symbols of this comdat. pub symbols: SectionLimited<'a, ComdatSymbol>,
}
impl<'a> FromReader<'a> for Comdat<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let name = reader.read_string()?; let flags = reader.read_var_u32()?; // FIXME(#188) ideally shouldn't need to skip here let symbols = reader.skip(|reader| { let count = reader.read_var_u32()?; for _ in0..count {
reader.read::<ComdatSymbol>()?;
}
Ok(())
})?;
Ok(Self {
name,
flags,
symbols: SectionLimited::new(symbols)?,
})
}
}
/// Represents a symbol that is part of a comdat. #[derive(Debug, Copy, Clone)] pubstruct ComdatSymbol { /// The kind of the symbol. pub kind: ComdatSymbolKind, /// The index of the symbol. Must not be an import. pub index: u32,
}
impl<'a> FromReader<'a> for ComdatSymbol { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let kind = reader.read()?; let index = reader.read_var_u32()?;
Ok(Self { kind, index })
}
}
/// Represents a symbol kind. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pubenum ComdatSymbolKind { /// The symbol is a data segment.
Data, /// The symbol is a function.
Func, /// The symbol is a global.
Global, /// The symbol is an event.
Event, /// The symbol is a table.
Table, /// The symbol is a section.
Section,
}
impl<'a> FromReader<'a> for ComdatSymbolKind { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let offset = reader.original_position(); match reader.read_u8()? { 0 => Ok(Self::Data), 1 => Ok(Self::Func), 2 => Ok(Self::Global), 3 => Ok(Self::Event), 4 => Ok(Self::Table), 5 => Ok(Self::Section),
k => Err(BinaryReader::invalid_leading_byte_error(
k, "comdat symbol kind",
offset,
)),
}
}
}
/// Represents a reader for symbol info from the linking custom section. pubtype SymbolInfoMap<'a> = SectionLimited<'a, SymbolInfo<'a>>;
/// Represents extra information about symbols in the linking custom section. /// /// The symbol flags correspond to those described in /// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md> /// with the `WASM_SYM_*` prefix. #[derive(Debug, Copy, Clone)] pubenum SymbolInfo<'a> { /// The symbol is a function.
Func { /// The flags for the symbol.
flags: SymbolFlags, /// The index of the function corresponding to this symbol.
index: u32, /// The name for the function, if it is defined or uses an explicit name.
name: Option<&'a str>,
}, /// The symbol is a data symbol.
Data { /// The flags for the symbol.
flags: SymbolFlags, /// The name for the symbol.
name: &'a str, /// The definition of the data symbol, if it is defined.
symbol: Option<DefinedDataSymbol>,
}, /// The symbol is a global.
Global { /// The flags for the symbol.
flags: SymbolFlags, /// The index of the global corresponding to this symbol.
index: u32, /// The name for the global, if it is defined or uses an explicit name.
name: Option<&'a str>,
}, /// The symbol is a section.
Section { /// The flags for the symbol.
flags: SymbolFlags, /// The index of the function corresponding to this symbol.
section: u32,
}, /// The symbol is an event.
Event { /// The flags for the symbol.
flags: SymbolFlags, /// The index of the event corresponding to this symbol.
index: u32, /// The name for the event, if it is defined or uses an explicit name.
name: Option<&'a str>,
}, /// The symbol is a table.
Table { /// The flags for the symbol.
flags: SymbolFlags, /// The index of the table corresponding to this symbol.
index: u32, /// The name for the table, if it is defined or uses an explicit name.
name: Option<&'a str>,
},
}
impl<'a> FromReader<'a> for SymbolInfo<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let offset = reader.original_position(); let kind = reader.read_u8()?; let flags: SymbolFlags = reader.read()?;
let defined = !flags.contains(SymbolFlags::UNDEFINED); let explicit_name = flags.contains(SymbolFlags::EXPLICIT_NAME);
// https://github.com/WebAssembly/wabt/blob/1.0.34/src/binary-writer.cc#L1226 match kind {
SYMTAB_FUNCTION | SYMTAB_GLOBAL | SYMTAB_EVENT | SYMTAB_TABLE => { let index = reader.read_var_u32()?; let name = match defined || explicit_name { true => Some(reader.read_string()?), false => None,
};
Ok(match kind {
SYMTAB_FUNCTION => Self::Func { flags, index, name },
SYMTAB_GLOBAL => Self::Global { flags, index, name },
SYMTAB_EVENT => Self::Event { flags, index, name },
SYMTAB_TABLE => Self::Table { flags, index, name },
_ => unreachable!(),
})
}
SYMTAB_DATA => { let name = reader.read_string()?; let data = match defined { true => Some(reader.read()?), false => None,
};
Ok(Self::Data {
flags,
name,
symbol: data,
})
}
SYMTAB_SECTION => { let section = reader.read_var_u32()?;
Ok(Self::Section { flags, section })
}
k => Err(BinaryReader::invalid_leading_byte_error(
k, "symbol kind",
offset,
)),
}
}
}
/// Represents the metadata about a data symbol defined in the wasm file. #[derive(Debug, Copy, Clone)] pubstruct DefinedDataSymbol { /// The index of the data segment. pub index: u32, /// The offset within the segment. Must be <= the segment's size. pub offset: u32, /// The size of the data, which can be zero. `offset + size` must be <= the segment's size. pub size: u32,
}
impl<'a> FromReader<'a> for DefinedDataSymbol { fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { let index = reader.read_var_u32()?; let offset = reader.read_var_u32()?; let size = reader.read_var_u32()?;
Ok(Self {
index,
offset,
size,
})
}
}
/// Represents a subsection read from the linking custom section. #[derive(Debug, Clone)] pubenum Linking<'a> { /// Extra metadata about the data segments.
SegmentInfo(SegmentMap<'a>), /// A list of constructor functions to be called at startup.
InitFuncs(InitFuncMap<'a>), /// The [COMDAT](https://llvm.org/docs/LangRef.html#comdats) groups of associated linking objects.
ComdatInfo(ComdatMap<'a>), /// Extra information about the symbols present in the module.
SymbolTable(SymbolInfoMap<'a>), /// An unknown [linking subsection](https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md#linking-metadata-section).
Unknown { /// The identifier for this subsection.
ty: u8, /// The contents of this subsection.
data: &'a [u8], /// The range of bytes, relative to the start of the original data /// stream, that the contents of this subsection reside in.
range: Range<usize>,
},
}
impl<'a> Subsection<'a> for Linking<'a> { fn from_reader(id: u8, reader: BinaryReader<'a>) -> Result<Self> { let data = reader.remaining_buffer(); let offset = reader.original_position();
Ok(match id { 5 => Self::SegmentInfo(SegmentMap::new(reader)?), 6 => Self::InitFuncs(InitFuncMap::new(reader)?), 7 => Self::ComdatInfo(ComdatMap::new(reader)?), 8 => Self::SymbolTable(SymbolInfoMap::new(reader)?),
ty => Self::Unknown {
ty,
data,
range: offset..offset + data.len(),
},
})
}
}
impl<'a> LinkingSectionReader<'a> { /// Creates a new reader for the linking section contents starting at /// `offset` within the original wasm file. pubfn new(mut reader: BinaryReader<'a>) -> Result<Self> { let range = reader.range(); let offset = reader.original_position();
let version = reader.read_var_u32()?; if version != 2 { return Err(BinaryReaderError::new(
format!("unsupported linking section version: {}", version),
offset,
));
}
/// Returns the version of linking metadata contained in this section. pubfn version(&self) -> u32 { self.version
}
/// Returns the original byte offset of this section. pubfn original_position(&self) -> usize { self.subsections.original_position()
}
/// Returns the range, as byte offsets, of this section within the original /// wasm binary. pubfn range(&self) -> Range<usize> { self.range.clone()
}
/// Returns the iterator for advancing through the subsections. /// /// You can also use [`IntoIterator::into_iter`] directly on this type. pubfn subsections(&self) -> Subsections<'a, Linking<'a>> { self.subsections.clone()
}
}
impl<'a> IntoIterator for LinkingSectionReader<'a> { type Item = Result<Linking<'a>>; type IntoIter = Subsections<'a, Linking<'a>>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.