Skip to content

Commit 3e1fb68

Browse files
alexcrichtondicej
andauthored
Add text format and printing support for dylink.0 (#1135)
* Add text format and printing support for `dylink.0` This is something I threw together which I think might be helpful in testing and working on #1133. In theory this should also make it easier to inspect this custom section in preexisting binaries. I've invented a text format of this out of nowhere as I don't believe there's a specification or anything else to follow. I've opted to use the `@dylink.0` annotation format to emphasize that it's a custom section, in the same manner that `@producers` uses that today. Note that this additionally copies some of the `wasmparser`-related parsing code from #1133. Co-authored-by: Joel Dice <[email protected]> * Add more bindings for symbol parsing --------- Co-authored-by: Joel Dice <[email protected]>
1 parent 9ed609d commit 3e1fb68

File tree

18 files changed

+569
-1
lines changed

18 files changed

+569
-1
lines changed

crates/wasmparser/src/readers/core.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod code;
22
mod coredumps;
33
mod custom;
44
mod data;
5+
mod dylink0;
56
mod elements;
67
mod exports;
78
mod functions;
@@ -20,6 +21,7 @@ pub use self::code::*;
2021
pub use self::coredumps::*;
2122
pub use self::custom::*;
2223
pub use self::data::*;
24+
pub use self::dylink0::*;
2325
pub use self::elements::*;
2426
pub use self::exports::*;
2527
pub use self::functions::*;
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use crate::{BinaryReader, Result, Subsection, Subsections};
2+
use std::ops::Range;
3+
4+
/// Parser for the dynamic linking `dylink.0` custom section.
5+
///
6+
/// This format is currently defined upstream at
7+
/// <https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md>.
8+
pub type Dylink0SectionReader<'a> = Subsections<'a, Dylink0Subsection<'a>>;
9+
10+
const WASM_DYLINK_MEM_INFO: u8 = 1;
11+
const WASM_DYLINK_NEEDED: u8 = 2;
12+
const WASM_DYLINK_EXPORT_INFO: u8 = 3;
13+
const WASM_DYLINK_IMPORT_INFO: u8 = 4;
14+
15+
#[allow(missing_docs)]
16+
pub const WASM_SYM_BINDING_WEAK: u32 = 1 << 0;
17+
#[allow(missing_docs)]
18+
pub const WASM_SYM_BINDING_LOCAL: u32 = 1 << 1;
19+
#[allow(missing_docs)]
20+
pub const WASM_SYM_VISIBILITY_HIDDEN: u32 = 1 << 2;
21+
#[allow(missing_docs)]
22+
pub const WASM_SYM_UNDEFINED: u32 = 1 << 4;
23+
#[allow(missing_docs)]
24+
pub const WASM_SYM_EXPORTED: u32 = 1 << 5;
25+
#[allow(missing_docs)]
26+
pub const WASM_SYM_EXPLICIT_NAME: u32 = 1 << 6;
27+
#[allow(missing_docs)]
28+
pub const WASM_SYM_NO_STRIP: u32 = 1 << 7;
29+
30+
/// Represents a `WASM_DYLINK_MEM_INFO` field
31+
#[derive(Debug, Copy, Clone)]
32+
pub struct MemInfo {
33+
/// Size of the memory area the loader should reserve for the module, which
34+
/// will begin at `env.__memory_base`.
35+
pub memory_size: u32,
36+
37+
/// The required alignment of the memory area, in bytes, encoded as a power
38+
/// of 2.
39+
pub memory_alignment: u32,
40+
41+
/// Size of the table area the loader should reserve for the module, which
42+
/// will begin at `env.__table_base`.
43+
pub table_size: u32,
44+
45+
/// The required alignment of the table area, in elements, encoded as a
46+
/// power of 2.
47+
pub table_alignment: u32,
48+
}
49+
50+
#[allow(missing_docs)]
51+
#[derive(Debug)]
52+
pub struct ExportInfo<'a> {
53+
pub name: &'a str,
54+
55+
/// Note that these flags correspond to those described in
56+
/// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>
57+
/// with the `WASM_SYM_*` prefix.
58+
pub flags: u32,
59+
}
60+
61+
#[allow(missing_docs)]
62+
#[derive(Debug)]
63+
pub struct ImportInfo<'a> {
64+
pub module: &'a str,
65+
pub field: &'a str,
66+
67+
/// Note that these flags correspond to those described in
68+
/// <https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md>
69+
/// with the `WASM_SYM_*` prefix.
70+
pub flags: u32,
71+
}
72+
73+
/// Possible subsections of the `dylink.0` custom section.
74+
#[derive(Debug)]
75+
#[allow(missing_docs)]
76+
pub enum Dylink0Subsection<'a> {
77+
MemInfo(MemInfo),
78+
Needed(Vec<&'a str>),
79+
ExportInfo(Vec<ExportInfo<'a>>),
80+
ImportInfo(Vec<ImportInfo<'a>>),
81+
Unknown {
82+
ty: u8,
83+
data: &'a [u8],
84+
range: Range<usize>,
85+
},
86+
}
87+
88+
impl<'a> Subsection<'a> for Dylink0Subsection<'a> {
89+
fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result<Self> {
90+
let data = reader.remaining_buffer();
91+
let offset = reader.original_position();
92+
Ok(match id {
93+
WASM_DYLINK_MEM_INFO => Self::MemInfo(MemInfo {
94+
memory_size: reader.read_var_u32()?,
95+
memory_alignment: reader.read_var_u32()?,
96+
table_size: reader.read_var_u32()?,
97+
table_alignment: reader.read_var_u32()?,
98+
}),
99+
WASM_DYLINK_NEEDED => Self::Needed(
100+
(0..reader.read_var_u32()?)
101+
.map(|_| reader.read_string())
102+
.collect::<Result<_, _>>()?,
103+
),
104+
WASM_DYLINK_EXPORT_INFO => Self::ExportInfo(
105+
(0..reader.read_var_u32()?)
106+
.map(|_| {
107+
Ok(ExportInfo {
108+
name: reader.read_string()?,
109+
flags: reader.read_var_u32()?,
110+
})
111+
})
112+
.collect::<Result<_, _>>()?,
113+
),
114+
WASM_DYLINK_IMPORT_INFO => Self::ImportInfo(
115+
(0..reader.read_var_u32()?)
116+
.map(|_| {
117+
Ok(ImportInfo {
118+
module: reader.read_string()?,
119+
field: reader.read_string()?,
120+
flags: reader.read_var_u32()?,
121+
})
122+
})
123+
.collect::<Result<_, _>>()?,
124+
),
125+
ty => Self::Unknown {
126+
ty,
127+
data,
128+
range: offset..offset + data.len(),
129+
},
130+
})
131+
}
132+
}

crates/wasmprinter/src/lib.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,6 +2555,13 @@ impl Printer {
25552555
section.data_offset(),
25562556
)?)
25572557
}
2558+
"dylink.0" => {
2559+
self.newline(section.range().start);
2560+
self.print_dylink0_section(Dylink0SectionReader::new(
2561+
section.data(),
2562+
section.data_offset(),
2563+
))
2564+
}
25582565
_ => Ok(()),
25592566
}
25602567
}
@@ -2577,6 +2584,97 @@ impl Printer {
25772584
self.end_group();
25782585
Ok(())
25792586
}
2587+
2588+
fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
2589+
self.start_group("@dylink.0");
2590+
loop {
2591+
let start = section.original_position();
2592+
let next = match section.next() {
2593+
Some(Ok(next)) => next,
2594+
Some(Err(e)) => return Err(e.into()),
2595+
None => break,
2596+
};
2597+
match next {
2598+
Dylink0Subsection::MemInfo(info) => {
2599+
self.newline(start);
2600+
self.start_group("mem-info");
2601+
if info.memory_size > 0 || info.memory_alignment > 0 {
2602+
write!(
2603+
self.result,
2604+
" (memory {} {})",
2605+
info.memory_size, info.memory_alignment
2606+
)?;
2607+
}
2608+
if info.table_size > 0 || info.table_alignment > 0 {
2609+
write!(
2610+
self.result,
2611+
" (table {} {})",
2612+
info.table_size, info.table_alignment
2613+
)?;
2614+
}
2615+
self.end_group();
2616+
}
2617+
Dylink0Subsection::Needed(needed) => {
2618+
self.newline(start);
2619+
self.start_group("needed");
2620+
for s in needed {
2621+
self.result.push_str(" ");
2622+
self.print_str(s)?;
2623+
}
2624+
self.end_group();
2625+
}
2626+
Dylink0Subsection::ExportInfo(info) => {
2627+
for info in info {
2628+
self.newline(start);
2629+
self.start_group("export-info ");
2630+
self.print_str(info.name)?;
2631+
self.print_dylink0_flags(info.flags)?;
2632+
self.end_group();
2633+
}
2634+
}
2635+
Dylink0Subsection::ImportInfo(info) => {
2636+
for info in info {
2637+
self.newline(start);
2638+
self.start_group("import-info ");
2639+
self.print_str(info.module)?;
2640+
self.result.push_str(" ");
2641+
self.print_str(info.field)?;
2642+
self.print_dylink0_flags(info.flags)?;
2643+
self.end_group();
2644+
}
2645+
}
2646+
Dylink0Subsection::Unknown { ty, .. } => {
2647+
bail!("don't know how to print dylink.0 subsection id {ty}");
2648+
}
2649+
}
2650+
}
2651+
self.end_group();
2652+
Ok(())
2653+
}
2654+
2655+
fn print_dylink0_flags(&mut self, mut flags: u32) -> Result<()> {
2656+
macro_rules! print_flag {
2657+
($($name:ident = $text:tt)*) => ({$(
2658+
if flags & wasmparser::$name != 0 {
2659+
flags &= !wasmparser::$name;
2660+
self.result.push_str(concat!(" ", $text));
2661+
}
2662+
)*})
2663+
}
2664+
print_flag! {
2665+
WASM_SYM_BINDING_WEAK = "binding-weak"
2666+
WASM_SYM_BINDING_LOCAL = "binding-local"
2667+
WASM_SYM_VISIBILITY_HIDDEN = "visibility-hidden"
2668+
WASM_SYM_UNDEFINED = "undefined"
2669+
WASM_SYM_EXPORTED = "exported"
2670+
WASM_SYM_EXPLICIT_NAME = "explicit-name"
2671+
WASM_SYM_NO_STRIP = "no-strip"
2672+
}
2673+
if flags != 0 {
2674+
write!(self.result, " {:#x}", flags)?;
2675+
}
2676+
Ok(())
2677+
}
25802678
}
25812679

25822680
struct NamedLocalPrinter {

crates/wast/src/core/binary.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ impl Encode for Custom<'_> {
10621062
match self {
10631063
Custom::Raw(r) => r.encode(e),
10641064
Custom::Producers(p) => p.encode(e),
1065+
Custom::Dylink0(p) => p.encode(e),
10651066
}
10661067
}
10671068
}
@@ -1080,6 +1081,38 @@ impl Encode for Producers<'_> {
10801081
}
10811082
}
10821083

1084+
impl Encode for Dylink0<'_> {
1085+
fn encode(&self, e: &mut Vec<u8>) {
1086+
for section in self.subsections.iter() {
1087+
e.push(section.id());
1088+
let mut tmp = Vec::new();
1089+
section.encode(&mut tmp);
1090+
tmp.encode(e);
1091+
}
1092+
}
1093+
}
1094+
1095+
impl Encode for Dylink0Subsection<'_> {
1096+
fn encode(&self, e: &mut Vec<u8>) {
1097+
match self {
1098+
Dylink0Subsection::MemInfo {
1099+
memory_size,
1100+
memory_align,
1101+
table_size,
1102+
table_align,
1103+
} => {
1104+
memory_size.encode(e);
1105+
memory_align.encode(e);
1106+
table_size.encode(e);
1107+
table_align.encode(e);
1108+
}
1109+
Dylink0Subsection::Needed(libs) => libs.encode(e),
1110+
Dylink0Subsection::ExportInfo(list) => list.encode(e),
1111+
Dylink0Subsection::ImportInfo(list) => list.encode(e),
1112+
}
1113+
}
1114+
}
1115+
10831116
impl Encode for Tag<'_> {
10841117
fn encode(&self, e: &mut Vec<u8>) {
10851118
self.ty.encode(e);

0 commit comments

Comments
 (0)