1use std::fmt;
31
32const MAGIC: [u8; 8] = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];
34
35const LINKING_VERSION: u32 = 2;
37
38pub const PADDED: usize = 5;
40
41const PAGE: u64 = 65_536;
43
44pub const WEAK: u32 = 0x1;
46pub const LOCAL: u32 = 0x2;
48pub const HIDDEN: u32 = 0x4;
50const UNDEFINED: u32 = 0x10;
52pub const EXPORTED: u32 = 0x20;
54const EXPLICIT_NAME: u32 = 0x40;
56pub const NO_STRIP: u32 = 0x80;
58
59pub const STRINGS: u32 = 0x1;
61pub const RETAIN: u32 = 0x4;
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub enum ValType {
67 I32,
68 I64,
69 F32,
70 F64,
71}
72
73impl ValType {
74 #[must_use]
76 pub fn byte(self) -> u8 {
77 match self {
78 ValType::I32 => 0x7f,
79 ValType::I64 => 0x7e,
80 ValType::F32 => 0x7d,
81 ValType::F64 => 0x7c,
82 }
83 }
84}
85
86impl fmt::Display for ValType {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 f.write_str(match self {
89 ValType::I32 => "i32",
90 ValType::I64 => "i64",
91 ValType::F32 => "f32",
92 ValType::F64 => "f64",
93 })
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
99pub struct FuncType {
100 pub params: Vec<ValType>,
101 pub results: Vec<ValType>,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
106pub enum SymbolKind {
107 Function { ty: u32, import: Option<Import> },
109 Data { place: Option<Place> },
111 Global { ty: ValType, mutable: bool, import: Option<Import> },
113 Table { import: Option<Import> },
115 Tag { ty: u32, import: Option<Import> },
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct Import {
123 pub module: String,
124 pub field: String,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub struct Place {
130 pub segment: u32,
131 pub offset: u32,
132 pub size: u32,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Symbol {
138 pub name: String,
139 pub kind: SymbolKind,
140 pub flags: u32,
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
146pub enum RelocKind {
147 FunctionIndexLeb,
149 TableIndexSleb,
151 TableIndexI32,
153 MemoryAddrLeb,
155 MemoryAddrSleb,
157 MemoryAddrI32,
159 TypeIndexLeb,
161 GlobalIndexLeb,
163 TagIndexLeb,
165 TableNumberLeb,
167}
168
169impl RelocKind {
170 #[must_use]
172 pub fn number(self) -> u8 {
173 match self {
174 RelocKind::FunctionIndexLeb => 0,
175 RelocKind::TableIndexSleb => 1,
176 RelocKind::TableIndexI32 => 2,
177 RelocKind::MemoryAddrLeb => 3,
178 RelocKind::MemoryAddrSleb => 4,
179 RelocKind::MemoryAddrI32 => 5,
180 RelocKind::TypeIndexLeb => 6,
181 RelocKind::GlobalIndexLeb => 7,
182 RelocKind::TagIndexLeb => 10,
183 RelocKind::TableNumberLeb => 20,
184 }
185 }
186
187 #[must_use]
189 pub fn width(self) -> usize {
190 match self {
191 RelocKind::TableIndexI32 | RelocKind::MemoryAddrI32 => 4,
192 _ => PADDED,
193 }
194 }
195
196 fn has_addend(self) -> bool {
198 matches!(
199 self,
200 RelocKind::MemoryAddrLeb | RelocKind::MemoryAddrSleb | RelocKind::MemoryAddrI32
201 )
202 }
203
204 fn names_type(self) -> bool {
206 self == RelocKind::TypeIndexLeb
207 }
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212pub struct Fixup {
213 pub at: u32,
216 pub kind: RelocKind,
217 pub target: u32,
219 pub addend: i32,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Default)]
225pub struct Function {
226 pub symbol: u32,
228 pub locals: Vec<(u32, ValType)>,
230 pub code: Vec<u8>,
232 pub fixups: Vec<Fixup>,
233 pub export: Option<String>,
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Default)]
239pub struct Segment {
240 pub name: String,
242 pub align: u32,
244 pub flags: u32,
246 pub bytes: Vec<u8>,
247 pub fixups: Vec<Fixup>,
248}
249
250#[derive(Debug, Clone, PartialEq, Eq, Default)]
252pub struct Producers {
253 pub language: Option<String>,
255 pub processed_by: Vec<(String, String)>,
257}
258
259#[derive(Debug, Clone, PartialEq, Eq, Default)]
261pub struct Module {
262 pub types: Vec<FuncType>,
263 pub symbols: Vec<Symbol>,
264 pub functions: Vec<Function>,
265 pub aliases: Vec<(u32, u32)>,
271 pub segments: Vec<Segment>,
272 pub inits: Vec<(u32, u32)>,
275 pub features: Vec<String>,
277 pub disallowed: Vec<String>,
279 pub producers: Producers,
280}
281
282impl Module {
283 pub fn intern(&mut self, ty: FuncType) -> u32 {
289 let index = match self.types.iter().position(|t| *t == ty) {
290 Some(index) => index,
291 None => {
292 self.types.push(ty);
293 self.types.len() - 1
294 }
295 };
296 u32::try_from(index).expect("fewer than 2^32 types")
297 }
298
299 pub fn symbol(&mut self, name: impl Into<String>, kind: SymbolKind, flags: u32) -> u32 {
305 self.symbols.push(Symbol { name: name.into(), kind, flags });
306 u32::try_from(self.symbols.len() - 1).expect("fewer than 2^32 symbols")
307 }
308}
309
310#[derive(Debug, Clone, PartialEq, Eq)]
312pub enum Error {
313 Target { fixup: Fixup, why: &'static str },
315 Outside { fixup: Fixup },
317 Definition { symbol: u32 },
319 Place { symbol: u32 },
321 Alias { symbol: u32 },
324}
325
326impl fmt::Display for Error {
327 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328 match self {
329 Error::Target { fixup, why } => write!(
330 f,
331 "the fixup at {} names {} {}, which {why}",
332 fixup.at,
333 if fixup.kind.names_type() { "type" } else { "symbol" },
334 fixup.target
335 ),
336 Error::Outside { fixup } => {
337 write!(f, "the fixup at {} is outside the bytes it patches", fixup.at)
338 }
339 Error::Definition { symbol } => {
340 write!(f, "symbol {symbol} is not a function that one definition names")
341 }
342 Error::Place { symbol } => write!(f, "symbol {symbol} is outside its segment"),
343 Error::Alias { symbol } => {
344 write!(f, "symbol {symbol} is not a second name of a function that is defined here")
345 }
346 }
347 }
348}
349
350impl std::error::Error for Error {}
351
352#[derive(Debug, Clone, PartialEq, Eq)]
354pub struct Written {
355 pub bytes: Vec<u8>,
356 pub defines: Vec<String>,
359}
360
361pub fn uleb(out: &mut Vec<u8>, mut value: u64) {
363 loop {
364 let byte = (value & 0x7f) as u8;
365 value >>= 7;
366 if value == 0 {
367 out.push(byte);
368 return;
369 }
370 out.push(byte | 0x80);
371 }
372}
373
374pub fn sleb(out: &mut Vec<u8>, mut value: i64) {
376 loop {
377 let byte = (value & 0x7f) as u8;
378 value >>= 7;
379 let done = (value == 0 && byte & 0x40 == 0) || (value == -1 && byte & 0x40 != 0);
380 if done {
381 out.push(byte);
382 return;
383 }
384 out.push(byte | 0x80);
385 }
386}
387
388#[must_use]
390pub fn uleb_padded(value: u32) -> [u8; PADDED] {
391 let mut out = [0; PADDED];
392 let mut rest = value;
393 for (n, byte) in out.iter_mut().enumerate() {
394 *byte = (rest & 0x7f) as u8;
395 rest >>= 7;
396 if n + 1 < PADDED {
397 *byte |= 0x80;
398 }
399 }
400 out
401}
402
403#[must_use]
405pub fn sleb_padded(value: i32) -> [u8; PADDED] {
406 let mut out = [0; PADDED];
407 let mut rest = value;
408 for (n, byte) in out.iter_mut().enumerate() {
409 *byte = (rest & 0x7f) as u8;
410 rest >>= 7;
411 if n + 1 < PADDED {
412 *byte |= 0x80;
413 }
414 }
415 out
416}
417
418pub fn name(out: &mut Vec<u8>, text: &str) {
420 uleb(out, text.len() as u64);
421 out.extend_from_slice(text.as_bytes());
422}
423
424struct Layout {
426 function: Vec<Option<u32>>,
428 other: Vec<Option<u32>>,
430 segment: Vec<u32>,
432 slot: Vec<Option<u32>>,
435 defined: Vec<bool>,
437}
438
439impl Layout {
440 fn of(module: &Module) -> Result<Layout, Error> {
441 let count = module.symbols.len();
442 let mut defined = vec![false; count];
443 for function in &module.functions {
444 let index = function.symbol as usize;
445 let is_function = matches!(
446 module.symbols.get(index).map(|s| &s.kind),
447 Some(SymbolKind::Function { .. })
448 );
449 if !is_function || defined[index] {
450 return Err(Error::Definition { symbol: function.symbol });
451 }
452 defined[index] = true;
453 }
454 for &(alias, target) in &module.aliases {
457 let is_function = matches!(
458 module.symbols.get(alias as usize).map(|s| &s.kind),
459 Some(SymbolKind::Function { .. })
460 );
461 let named = defined.get(target as usize) == Some(&true);
462 if !is_function || defined[alias as usize] || !named {
463 return Err(Error::Alias { symbol: alias });
464 }
465 defined[alias as usize] = true;
466 }
467
468 let mut function = vec![None; count];
471 let mut next = 0u32;
472 for (index, symbol) in module.symbols.iter().enumerate() {
473 if matches!(symbol.kind, SymbolKind::Function { .. }) && !defined[index] {
474 function[index] = Some(next);
475 next += 1;
476 }
477 }
478 for f in &module.functions {
479 function[f.symbol as usize] = Some(next);
480 next += 1;
481 }
482 for &(alias, target) in &module.aliases {
483 function[alias as usize] = function[target as usize];
484 }
485
486 let mut other = vec![None; count];
488 let (mut globals, mut tables, mut tags) = (0u32, 0u32, 0u32);
489 for (index, symbol) in module.symbols.iter().enumerate() {
490 let counter = match symbol.kind {
491 SymbolKind::Global { .. } => &mut globals,
492 SymbolKind::Table { .. } => &mut tables,
493 SymbolKind::Tag { .. } => &mut tags,
494 _ => continue,
495 };
496 other[index] = Some(*counter);
497 *counter += 1;
498 }
499
500 let mut segment = Vec::with_capacity(module.segments.len());
501 let mut address = 0u64;
502 for s in &module.segments {
503 let align = 1u64 << s.align.min(31);
504 address = address.div_ceil(align) * align;
505 segment.push(u32::try_from(address).unwrap_or(u32::MAX));
506 address += s.bytes.len() as u64;
507 }
508 for (index, symbol) in module.symbols.iter().enumerate() {
509 if let SymbolKind::Data { place: Some(place) } = symbol.kind {
510 let fits = module.segments.get(place.segment as usize).is_some_and(|s| {
511 u64::from(place.offset) + u64::from(place.size) <= s.bytes.len() as u64
512 });
513 if !fits {
514 return Err(Error::Place { symbol: u32::try_from(index).unwrap_or(u32::MAX) });
515 }
516 }
517 }
518
519 let mut slot = vec![None; count];
520 let mut slots = 1u32;
521 let fixups = module
522 .functions
523 .iter()
524 .flat_map(|f| &f.fixups)
525 .chain(module.segments.iter().flat_map(|s| &s.fixups));
526 for fixup in fixups {
527 if !matches!(fixup.kind, RelocKind::TableIndexSleb | RelocKind::TableIndexI32) {
528 continue;
529 }
530 if let Some(entry @ None) = slot.get_mut(fixup.target as usize) {
531 *entry = Some(slots);
532 slots += 1;
533 }
534 }
535
536 Ok(Layout { function, other, segment, slot, defined })
537 }
538
539 fn is_defined(&self, module: &Module, index: usize) -> bool {
541 match module.symbols[index].kind {
542 SymbolKind::Function { .. } => self.defined[index],
543 SymbolKind::Data { place } => place.is_some(),
544 SymbolKind::Global { .. } | SymbolKind::Table { .. } | SymbolKind::Tag { .. } => false,
545 }
546 }
547
548 fn value(&self, module: &Module, fixup: Fixup) -> Result<i64, Error> {
550 let fail = |why| Err(Error::Target { fixup, why });
551 if fixup.kind.names_type() {
552 return if (fixup.target as usize) < module.types.len() {
553 Ok(i64::from(fixup.target))
554 } else {
555 fail("is not in the type list")
556 };
557 }
558 let index = fixup.target as usize;
559 let Some(symbol) = module.symbols.get(index) else {
560 return fail("is not in the symbol table");
561 };
562 match (fixup.kind, &symbol.kind) {
563 (RelocKind::FunctionIndexLeb, SymbolKind::Function { .. }) => {
564 Ok(i64::from(self.function[index].unwrap_or(0)))
565 }
566 (RelocKind::TableIndexSleb | RelocKind::TableIndexI32, SymbolKind::Function { .. }) => {
567 Ok(i64::from(self.slot[index].unwrap_or(0)))
568 }
569 (
570 RelocKind::MemoryAddrLeb | RelocKind::MemoryAddrSleb | RelocKind::MemoryAddrI32,
571 SymbolKind::Data { place },
572 ) => {
573 let base = place.map_or(0, |p| {
574 i64::from(self.segment[p.segment as usize]) + i64::from(p.offset)
575 });
576 Ok(base + i64::from(fixup.addend))
577 }
578 (RelocKind::GlobalIndexLeb, SymbolKind::Global { .. })
579 | (RelocKind::TableNumberLeb, SymbolKind::Table { .. })
580 | (RelocKind::TagIndexLeb, SymbolKind::Tag { .. }) => {
581 Ok(i64::from(self.other[index].unwrap_or(0)))
582 }
583 _ => fail("is not of the kind the relocation wants"),
584 }
585 }
586}
587
588fn patch(bytes: &mut [u8], fixup: Fixup, value: i64) -> Result<(), Error> {
591 let at = fixup.at as usize;
592 let Some(field) = bytes.get_mut(at..at + fixup.kind.width()) else {
593 return Err(Error::Outside { fixup });
594 };
595 let value32 = value as i32;
598 match fixup.kind {
599 RelocKind::TableIndexI32 | RelocKind::MemoryAddrI32 => {
600 field.copy_from_slice(&value32.to_le_bytes());
601 }
602 RelocKind::TableIndexSleb | RelocKind::MemoryAddrSleb => {
603 field.copy_from_slice(&sleb_padded(value32));
604 }
605 _ => field.copy_from_slice(&uleb_padded(value as u32)),
606 }
607 Ok(())
608}
609
610struct Entry {
612 offset: u32,
613 fixup: Fixup,
614}
615
616fn section(out: &mut Vec<u8>, id: u8, payload: &[u8]) {
618 out.push(id);
619 uleb(out, payload.len() as u64);
620 out.extend_from_slice(payload);
621}
622
623fn custom(out: &mut Vec<u8>, label: &str, payload: &[u8]) {
625 let mut body = Vec::with_capacity(label.len() + 1 + payload.len());
626 name(&mut body, label);
627 body.extend_from_slice(payload);
628 section(out, 0, &body);
629}
630
631fn import_of(symbol: &Symbol) -> (String, String) {
633 let import = match &symbol.kind {
634 SymbolKind::Function { import, .. }
635 | SymbolKind::Global { import, .. }
636 | SymbolKind::Table { import }
637 | SymbolKind::Tag { import, .. } => import.as_ref(),
638 SymbolKind::Data { .. } => None,
639 };
640 match import {
641 Some(i) => (i.module.clone(), i.field.clone()),
642 None => ("env".to_owned(), symbol.name.clone()),
643 }
644}
645
646fn len32(n: usize) -> u64 {
648 n as u64
649}
650
651pub fn write(module: &Module) -> Result<Written, Error> {
657 let layout = Layout::of(module)?;
658 let mut out = Vec::from(MAGIC);
659 let mut sections = 0u32;
661
662 if !module.types.is_empty() {
663 let mut payload = Vec::new();
664 uleb(&mut payload, len32(module.types.len()));
665 for ty in &module.types {
666 payload.push(0x60);
667 uleb(&mut payload, len32(ty.params.len()));
668 payload.extend(ty.params.iter().map(|t| t.byte()));
669 uleb(&mut payload, len32(ty.results.len()));
670 payload.extend(ty.results.iter().map(|t| t.byte()));
671 }
672 section(&mut out, 1, &payload);
673 sections += 1;
674 }
675
676 {
680 let data: u64 = layout.segment.last().map_or(0, |start| {
681 u64::from(*start) + module.segments.last().map_or(0, |s| s.bytes.len() as u64)
682 });
683 let mut entries: Vec<Vec<u8>> = Vec::new();
684 let mut memory = Vec::new();
685 name(&mut memory, "env");
686 name(&mut memory, "__linear_memory");
687 memory.push(0x02);
688 memory.push(0x00);
689 uleb(&mut memory, data.div_ceil(PAGE));
690 entries.push(memory);
691 let kinds: [fn(&SymbolKind) -> bool; 4] = [
692 |k| matches!(k, SymbolKind::Global { .. }),
693 |k| matches!(k, SymbolKind::Table { .. }),
694 |k| matches!(k, SymbolKind::Tag { .. }),
695 |k| matches!(k, SymbolKind::Function { .. }),
696 ];
697 for wanted in kinds {
698 for (index, symbol) in module.symbols.iter().enumerate() {
699 if !wanted(&symbol.kind) || layout.is_defined(module, index) {
700 continue;
701 }
702 let (from, field) = import_of(symbol);
703 let mut entry = Vec::new();
704 name(&mut entry, &from);
705 name(&mut entry, &field);
706 match symbol.kind {
707 SymbolKind::Function { ty, .. } => {
708 entry.push(0x00);
709 uleb(&mut entry, u64::from(ty));
710 }
711 SymbolKind::Table { .. } => {
712 entry.extend_from_slice(&[0x01, 0x70, 0x00]);
713 uleb(&mut entry, len32(layout.slot.iter().flatten().count()));
714 }
715 SymbolKind::Global { ty, mutable, .. } => {
716 entry.extend_from_slice(&[0x03, ty.byte(), u8::from(mutable)]);
717 }
718 SymbolKind::Tag { ty, .. } => {
719 entry.extend_from_slice(&[0x04, 0x00]);
720 uleb(&mut entry, u64::from(ty));
721 }
722 SymbolKind::Data { .. } => unreachable!("data is never imported"),
723 }
724 entries.push(entry);
725 }
726 }
727 let mut payload = Vec::new();
728 uleb(&mut payload, len32(entries.len()));
729 for entry in entries {
730 payload.extend_from_slice(&entry);
731 }
732 section(&mut out, 2, &payload);
733 sections += 1;
734 }
735
736 if !module.functions.is_empty() {
737 let mut payload = Vec::new();
738 uleb(&mut payload, len32(module.functions.len()));
739 for f in &module.functions {
740 let SymbolKind::Function { ty, .. } = module.symbols[f.symbol as usize].kind else {
741 unreachable!("the layout checked that a definition names a function symbol");
742 };
743 uleb(&mut payload, u64::from(ty));
744 }
745 section(&mut out, 3, &payload);
746 sections += 1;
747 }
748
749 let exports: Vec<&Function> = module.functions.iter().filter(|f| f.export.is_some()).collect();
750 if !exports.is_empty() {
751 let mut payload = Vec::new();
752 uleb(&mut payload, len32(exports.len()));
753 for f in exports {
754 name(&mut payload, f.export.as_deref().unwrap_or_default());
755 payload.push(0x00);
756 uleb(&mut payload, u64::from(layout.function[f.symbol as usize].unwrap_or(0)));
757 }
758 section(&mut out, 7, &payload);
759 sections += 1;
760 }
761
762 let mut code_relocs = Vec::new();
765 let mut code_section = None;
766 if !module.functions.is_empty() {
767 let mut payload = Vec::new();
768 uleb(&mut payload, len32(module.functions.len()));
769 for f in &module.functions {
770 let mut body = Vec::new();
771 uleb(&mut body, len32(f.locals.len()));
772 for (count, ty) in &f.locals {
773 uleb(&mut body, u64::from(*count));
774 body.push(ty.byte());
775 }
776 let start = body.len();
777 body.extend_from_slice(&f.code);
778 for fixup in &f.fixups {
779 let value = layout.value(module, *fixup)?;
780 patch(&mut body[start..], *fixup, value)?;
781 }
782 uleb(&mut payload, len32(body.len()));
783 let base = payload.len() + start;
784 for fixup in &f.fixups {
785 let offset = u32::try_from(base + fixup.at as usize).unwrap_or(u32::MAX);
786 code_relocs.push(Entry { offset, fixup: *fixup });
787 }
788 payload.extend_from_slice(&body);
789 }
790 section(&mut out, 10, &payload);
791 code_section = Some(sections);
792 sections += 1;
793 }
794
795 let mut data_relocs = Vec::new();
798 let mut data_section = None;
799 if !module.segments.is_empty() {
800 let mut payload = Vec::new();
801 uleb(&mut payload, len32(module.segments.len()));
802 for (s, start) in module.segments.iter().zip(&layout.segment) {
803 payload.extend_from_slice(&[0x00, 0x41]);
804 sleb(&mut payload, i64::from(*start as i32));
805 payload.push(0x0b);
806 uleb(&mut payload, len32(s.bytes.len()));
807 let base = payload.len();
808 let mut bytes = s.bytes.clone();
809 for fixup in &s.fixups {
810 let value = layout.value(module, *fixup)?;
811 patch(&mut bytes, *fixup, value)?;
812 let offset = u32::try_from(base + fixup.at as usize).unwrap_or(u32::MAX);
813 data_relocs.push(Entry { offset, fixup: *fixup });
814 }
815 payload.extend_from_slice(&bytes);
816 }
817 section(&mut out, 11, &payload);
818 data_section = Some(sections);
819 }
820
821 custom(&mut out, "linking", &linking(module, &layout));
822 for (label, target, mut entries) in
823 [("reloc.CODE", code_section, code_relocs), ("reloc.DATA", data_section, data_relocs)]
824 {
825 let Some(target) = target else { continue };
826 if entries.is_empty() {
827 continue;
828 }
829 entries.sort_by_key(|e| e.offset);
830 let mut payload = Vec::new();
831 uleb(&mut payload, u64::from(target));
832 uleb(&mut payload, len32(entries.len()));
833 for entry in &entries {
834 payload.push(entry.fixup.kind.number());
835 uleb(&mut payload, u64::from(entry.offset));
836 uleb(&mut payload, u64::from(entry.fixup.target));
837 if entry.fixup.kind.has_addend() {
838 sleb(&mut payload, i64::from(entry.fixup.addend));
839 }
840 }
841 custom(&mut out, label, &payload);
842 }
843
844 if let Some(payload) = producers(&module.producers) {
845 custom(&mut out, "producers", &payload);
846 }
847 if let Some(payload) = target_features(module) {
848 custom(&mut out, "target_features", &payload);
849 }
850
851 let defines = module
852 .symbols
853 .iter()
854 .enumerate()
855 .filter(|(index, s)| layout.is_defined(module, *index) && s.flags & LOCAL == 0)
856 .map(|(_, s)| s.name.clone())
857 .collect();
858 Ok(Written { bytes: out, defines })
859}
860
861#[must_use]
864pub fn producers(producers: &Producers) -> Option<Vec<u8>> {
865 let fields: Vec<(&str, Vec<(&str, &str)>)> = [
866 ("language", producers.language.iter().map(|l| (l.as_str(), "")).collect::<Vec<_>>()),
867 (
868 "processed-by",
869 producers.processed_by.iter().map(|(n, v)| (n.as_str(), v.as_str())).collect(),
870 ),
871 ]
872 .into_iter()
873 .filter(|(_, values)| !values.is_empty())
874 .collect();
875 if fields.is_empty() {
876 return None;
877 }
878 let mut payload = Vec::new();
879 uleb(&mut payload, len32(fields.len()));
880 for (field, values) in fields {
881 name(&mut payload, field);
882 uleb(&mut payload, len32(values.len()));
883 for (value, version) in values {
884 name(&mut payload, value);
885 name(&mut payload, version);
886 }
887 }
888 Some(payload)
889}
890
891#[must_use]
894pub fn target_features(module: &Module) -> Option<Vec<u8>> {
895 if module.features.is_empty() && module.disallowed.is_empty() {
896 return None;
897 }
898 let mut payload = Vec::new();
899 uleb(&mut payload, len32(module.features.len() + module.disallowed.len()));
900 for (prefix, list) in [(b'+', &module.features), (b'-', &module.disallowed)] {
901 for feature in list {
902 payload.push(prefix);
903 name(&mut payload, feature);
904 }
905 }
906 Some(payload)
907}
908
909fn linking(module: &Module, layout: &Layout) -> Vec<u8> {
912 let mut payload = Vec::new();
913 uleb(&mut payload, u64::from(LINKING_VERSION));
914
915 let mut table = Vec::new();
916 uleb(&mut table, len32(module.symbols.len()));
917 for (index, symbol) in module.symbols.iter().enumerate() {
918 let defined = layout.is_defined(module, index);
919 let mut flags = symbol.flags & !(UNDEFINED | EXPLICIT_NAME);
920 if !defined {
921 flags |= UNDEFINED;
922 }
923 let explicit = !defined
924 && !matches!(symbol.kind, SymbolKind::Data { .. })
925 && import_of(symbol).1 != symbol.name;
926 if explicit {
927 flags |= EXPLICIT_NAME;
928 }
929 let kind = match symbol.kind {
930 SymbolKind::Function { .. } => 0,
931 SymbolKind::Data { .. } => 1,
932 SymbolKind::Global { .. } => 2,
933 SymbolKind::Tag { .. } => 4,
934 SymbolKind::Table { .. } => 5,
935 };
936 table.push(kind);
937 uleb(&mut table, u64::from(flags));
938 match symbol.kind {
939 SymbolKind::Data { place } => {
940 name(&mut table, &symbol.name);
941 if let Some(place) = place {
942 uleb(&mut table, u64::from(place.segment));
943 uleb(&mut table, u64::from(place.offset));
944 uleb(&mut table, u64::from(place.size));
945 }
946 }
947 _ => {
948 let number = match symbol.kind {
949 SymbolKind::Function { .. } => layout.function[index],
950 _ => layout.other[index],
951 };
952 uleb(&mut table, u64::from(number.unwrap_or(0)));
953 if defined || explicit {
954 name(&mut table, &symbol.name);
955 }
956 }
957 }
958 }
959 subsection(&mut payload, 8, &table);
960
961 if !module.segments.is_empty() {
962 let mut info = Vec::new();
963 uleb(&mut info, len32(module.segments.len()));
964 for s in &module.segments {
965 name(&mut info, &s.name);
966 uleb(&mut info, u64::from(s.align));
967 uleb(&mut info, u64::from(s.flags));
968 }
969 subsection(&mut payload, 5, &info);
970 }
971
972 if !module.inits.is_empty() {
973 let mut inits = Vec::new();
974 uleb(&mut inits, len32(module.inits.len()));
975 for (priority, symbol) in &module.inits {
976 uleb(&mut inits, u64::from(*priority));
977 uleb(&mut inits, u64::from(*symbol));
978 }
979 subsection(&mut payload, 6, &inits);
980 }
981 payload
982}
983
984fn subsection(out: &mut Vec<u8>, id: u8, payload: &[u8]) {
985 out.push(id);
986 uleb(out, len32(payload.len()));
987 out.extend_from_slice(payload);
988}