1use super::error::ObjectError;
2use crate::{
3 serialize::MetadataHeader,
4 types::{
5 function::Compilation,
6 relocation::{RelocationKind as Reloc, RelocationTarget},
7 section::{CustomSectionProtection, SectionIndex},
8 symbols::{ModuleMetadata, Symbol, SymbolRegistry},
9 },
10};
11use object::{
12 elf, macho,
13 write::{
14 Object, Relocation, StandardSection, StandardSegment, Symbol as ObjSymbol, SymbolId,
15 SymbolSection,
16 },
17 FileFlags, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind,
18 SymbolScope,
19};
20use wasmer_types::entity::{EntityRef, PrimaryMap};
21use wasmer_types::target::{Architecture, BinaryFormat, Endianness, PointerWidth, Triple};
22use wasmer_types::LocalFunctionIndex;
23
24const DWARF_SECTION_NAME: &[u8] = b".eh_frame";
25
26pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
41 let obj_binary_format = match triple.binary_format {
42 BinaryFormat::Elf => object::BinaryFormat::Elf,
43 BinaryFormat::Macho => object::BinaryFormat::MachO,
44 BinaryFormat::Coff => object::BinaryFormat::Coff,
45 binary_format => {
46 return Err(ObjectError::UnsupportedBinaryFormat(format!(
47 "{binary_format}"
48 )));
49 }
50 };
51 let obj_architecture = match triple.architecture {
52 Architecture::X86_64 => object::Architecture::X86_64,
53 Architecture::Aarch64(_) => object::Architecture::Aarch64,
54 Architecture::Riscv64(_) => object::Architecture::Riscv64,
55 Architecture::LoongArch64 => object::Architecture::LoongArch64,
56 architecture => {
57 return Err(ObjectError::UnsupportedArchitecture(format!(
58 "{architecture}"
59 )));
60 }
61 };
62 let obj_endianness = match triple
63 .endianness()
64 .map_err(|_| ObjectError::UnknownEndianness)?
65 {
66 Endianness::Little => object::Endianness::Little,
67 Endianness::Big => object::Endianness::Big,
68 };
69
70 let mut object = Object::new(obj_binary_format, obj_architecture, obj_endianness);
71
72 if let Architecture::Riscv64(_) = triple.architecture {
73 object.flags = FileFlags::Elf {
74 e_flags: elf::EF_RISCV_FLOAT_ABI_DOUBLE,
75 os_abi: 2,
76 abi_version: 0,
77 };
78 }
79
80 Ok(object)
81}
82
83pub fn emit_data(
99 obj: &mut Object,
100 name: &[u8],
101 data: &[u8],
102 align: u64,
103) -> Result<u64, ObjectError> {
104 let symbol_id = obj.add_symbol(ObjSymbol {
105 name: name.to_vec(),
106 value: 0,
107 size: 0,
108 kind: SymbolKind::Data,
109 scope: SymbolScope::Dynamic,
110 weak: false,
111 section: SymbolSection::Undefined,
112 flags: SymbolFlags::None,
113 });
114 let section_id = obj.section_id(StandardSection::Data);
115 let offset = obj.add_symbol_data(symbol_id, section_id, data, align);
116
117 Ok(offset)
118}
119
120pub fn emit_compilation(
141 obj: &mut Object,
142 compilation: Compilation,
143 symbol_registry: &impl SymbolRegistry,
144 triple: &Triple,
145 relocs_builder: &ObjectMetadataBuilder,
146) -> Result<(), ObjectError> {
147 let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len());
148 let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len());
149 for (_, func) in compilation.functions.into_iter() {
150 function_bodies.push(func.body);
151 function_relocations.push(func.relocations);
152 }
153 let custom_section_relocations = compilation
154 .custom_sections
155 .iter()
156 .map(|(_, section)| section.relocations.clone())
157 .collect::<PrimaryMap<SectionIndex, _>>();
158
159 let debug_index = compilation.unwind_info.eh_frame;
160
161 let default_align = match triple.architecture {
162 target_lexicon::Architecture::Aarch64(_) => {
163 if matches!(
164 triple.operating_system,
165 target_lexicon::OperatingSystem::Darwin
166 ) {
167 8
168 } else {
169 4
170 }
171 }
172 _ => 1,
173 };
174
175 let custom_section_ids = compilation
177 .custom_sections
178 .into_iter()
179 .map(|(section_index, custom_section)| {
180 if debug_index.map_or(false, |d| d == section_index) {
181 let segment = obj.segment_name(StandardSegment::Debug).to_vec();
183 let section_id =
184 obj.add_section(segment, DWARF_SECTION_NAME.to_vec(), SectionKind::Debug);
185 obj.append_section_data(section_id, custom_section.bytes.as_slice(), default_align);
186 let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
187 let symbol_id = obj.add_symbol(ObjSymbol {
188 name: section_name.into_bytes(),
189 value: 0,
190 size: custom_section.bytes.len() as _,
191 kind: SymbolKind::Data,
192 scope: SymbolScope::Compilation,
193 weak: false,
194 section: SymbolSection::Section(section_id),
195 flags: SymbolFlags::None,
196 });
197 (section_id, symbol_id)
198 } else {
199 let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
200 let (section_kind, standard_section) = match custom_section.protection {
201 CustomSectionProtection::ReadExecute => {
202 (SymbolKind::Text, StandardSection::Text)
203 }
204 CustomSectionProtection::Read => (SymbolKind::Data, StandardSection::Data),
205 };
206 let section_id = obj.section_id(standard_section);
207 let symbol_id = obj.add_symbol(ObjSymbol {
208 name: section_name.into_bytes(),
209 value: 0,
210 size: custom_section.bytes.len() as _,
211 kind: section_kind,
212 scope: SymbolScope::Dynamic,
213 weak: false,
214 section: SymbolSection::Section(section_id),
215 flags: SymbolFlags::None,
216 });
217 obj.add_symbol_data(
218 symbol_id,
219 section_id,
220 custom_section.bytes.as_slice(),
221 custom_section.alignment.unwrap_or(default_align),
222 );
223 (section_id, symbol_id)
224 }
225 })
226 .collect::<PrimaryMap<SectionIndex, _>>();
227
228 let function_symbol_ids = function_bodies
230 .into_iter()
231 .map(|(function_local_index, function)| {
232 let function_name =
233 symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
234 let section_id = obj.section_id(StandardSection::Text);
235 let symbol_id = obj.add_symbol(ObjSymbol {
236 name: function_name.into_bytes(),
237 value: 0,
238 size: function.body.len() as _,
239 kind: SymbolKind::Text,
240 scope: SymbolScope::Dynamic,
241 weak: false,
242 section: SymbolSection::Section(section_id),
243 flags: SymbolFlags::None,
244 });
245 obj.add_symbol_data(symbol_id, section_id, &function.body, default_align);
246 (section_id, symbol_id)
247 })
248 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
249 for (i, (_, symbol_id)) in function_symbol_ids.iter() {
250 relocs_builder.setup_function_pointer(obj, i.index(), *symbol_id)?;
251 }
252
253 for (signature_index, function) in compilation.function_call_trampolines.into_iter() {
255 let function_name =
256 symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(signature_index));
257 let section_id = obj.section_id(StandardSection::Text);
258 let symbol_id = obj.add_symbol(ObjSymbol {
259 name: function_name.into_bytes(),
260 value: 0,
261 size: function.body.len() as _,
262 kind: SymbolKind::Text,
263 scope: SymbolScope::Dynamic,
264 weak: false,
265 section: SymbolSection::Section(section_id),
266 flags: SymbolFlags::None,
267 });
268 obj.add_symbol_data(symbol_id, section_id, &function.body, default_align);
269
270 relocs_builder.setup_trampoline(obj, signature_index.index(), symbol_id)?;
271 }
272
273 for (func_index, function) in compilation.dynamic_function_trampolines.into_iter() {
275 let function_name =
276 symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
277 let section_id = obj.section_id(StandardSection::Text);
278 let symbol_id = obj.add_symbol(ObjSymbol {
279 name: function_name.into_bytes(),
280 value: 0,
281 size: function.body.len() as _,
282 kind: SymbolKind::Text,
283 scope: SymbolScope::Dynamic,
284 weak: false,
285 section: SymbolSection::Section(section_id),
286 flags: SymbolFlags::None,
287 });
288 obj.add_symbol_data(symbol_id, section_id, &function.body, default_align);
289
290 relocs_builder.setup_dynamic_function_trampoline_pointer(
291 obj,
292 func_index.index(),
293 symbol_id,
294 )?;
295 }
296
297 let mut all_relocations = Vec::new();
298
299 for (function_local_index, relocations) in function_relocations.into_iter() {
300 let (section_id, symbol_id) = function_symbol_ids.get(function_local_index).unwrap();
301 all_relocations.push((*section_id, *symbol_id, relocations))
302 }
303
304 for (section_index, relocations) in custom_section_relocations.into_iter() {
305 if !debug_index.map_or(false, |d| d == section_index) {
306 let (section_id, symbol_id) = custom_section_ids.get(section_index).unwrap();
308 all_relocations.push((*section_id, *symbol_id, relocations));
309 }
310 }
311
312 for (section_id, symbol_id, relocations) in all_relocations.into_iter() {
313 let (_symbol_id, section_offset) = obj.symbol_section_and_offset(symbol_id).unwrap();
314
315 for r in relocations {
316 let relocation_address = section_offset + r.offset as u64;
317
318 let (relocation_kind, relocation_encoding, relocation_size) = match r.kind {
319 Reloc::Abs4 => (RelocationKind::Absolute, RelocationEncoding::Generic, 32),
320 Reloc::Abs8 => (RelocationKind::Absolute, RelocationEncoding::Generic, 64),
321 Reloc::X86PCRel4 => (RelocationKind::Relative, RelocationEncoding::Generic, 32),
322 Reloc::X86CallPCRel4 => {
323 (RelocationKind::Relative, RelocationEncoding::X86Branch, 32)
324 }
325 Reloc::X86CallPLTRel4 => (
326 RelocationKind::PltRelative,
327 RelocationEncoding::X86Branch,
328 32,
329 ),
330 Reloc::X86GOTPCRel4 => {
331 (RelocationKind::GotRelative, RelocationEncoding::Generic, 32)
332 }
333 Reloc::Arm64Call => (
334 match obj.format() {
335 object::BinaryFormat::Elf => RelocationKind::Elf(elf::R_AARCH64_CALL26),
336 object::BinaryFormat::MachO => RelocationKind::MachO {
337 value: macho::ARM64_RELOC_BRANCH26,
338 relative: true,
339 },
340 fmt => panic!("unsupported binary format {fmt:?}"),
341 },
342 RelocationEncoding::Generic,
343 32,
344 ),
345 Reloc::ElfX86_64TlsGd => (
346 RelocationKind::Elf(elf::R_X86_64_TLSGD),
347 RelocationEncoding::Generic,
348 32,
349 ),
350 Reloc::MachoArm64RelocBranch26 => (
351 RelocationKind::MachO {
352 value: macho::ARM64_RELOC_BRANCH26,
353 relative: true,
354 },
355 RelocationEncoding::Generic,
356 32,
357 ),
358 Reloc::MachoArm64RelocUnsigned => (
359 RelocationKind::MachO {
360 value: object::macho::ARM64_RELOC_UNSIGNED,
361 relative: true,
362 },
363 RelocationEncoding::Generic,
364 32,
365 ),
366 Reloc::MachoArm64RelocSubtractor => (
367 RelocationKind::MachO {
368 value: object::macho::ARM64_RELOC_SUBTRACTOR,
369 relative: false,
370 },
371 RelocationEncoding::Generic,
372 64,
373 ),
374 Reloc::MachoArm64RelocPage21 => (
375 RelocationKind::MachO {
376 value: object::macho::ARM64_RELOC_PAGE21,
377 relative: true,
378 },
379 RelocationEncoding::Generic,
380 32,
381 ),
382
383 Reloc::MachoArm64RelocPageoff12 => (
384 RelocationKind::MachO {
385 value: object::macho::ARM64_RELOC_PAGEOFF12,
386 relative: false,
387 },
388 RelocationEncoding::Generic,
389 32,
390 ),
391 Reloc::MachoArm64RelocGotLoadPage21 => (
392 RelocationKind::MachO {
393 value: object::macho::ARM64_RELOC_GOT_LOAD_PAGE21,
394 relative: true,
395 },
396 RelocationEncoding::Generic,
397 32,
398 ),
399 Reloc::MachoArm64RelocGotLoadPageoff12 => (
400 RelocationKind::MachO {
401 value: object::macho::ARM64_RELOC_GOT_LOAD_PAGEOFF12,
402 relative: true,
403 },
404 RelocationEncoding::Generic,
405 32,
406 ),
407 Reloc::MachoArm64RelocPointerToGot => (
408 RelocationKind::MachO {
409 value: object::macho::ARM64_RELOC_POINTER_TO_GOT,
410 relative: true,
411 },
412 RelocationEncoding::Generic,
413 32,
414 ),
415 Reloc::MachoArm64RelocTlvpLoadPage21 => (
416 RelocationKind::MachO {
417 value: object::macho::ARM64_RELOC_TLVP_LOAD_PAGE21,
418 relative: true,
419 },
420 RelocationEncoding::Generic,
421 32,
422 ),
423 Reloc::MachoArm64RelocTlvpLoadPageoff12 => (
424 RelocationKind::MachO {
425 value: object::macho::ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
426 relative: true,
427 },
428 RelocationEncoding::Generic,
429 32,
430 ),
431 Reloc::MachoArm64RelocAddend => (
432 RelocationKind::MachO {
433 value: object::macho::ARM64_RELOC_ADDEND,
434 relative: false,
435 },
436 RelocationEncoding::Generic,
437 32,
438 ),
439
440 other => {
441 return Err(ObjectError::UnsupportedArchitecture(format!(
442 "{} (relocation: {})",
443 triple.architecture, other
444 )))
445 }
446 };
447
448 match r.reloc_target {
449 RelocationTarget::LocalFunc(index) => {
450 let (_, target_symbol) = function_symbol_ids.get(index).unwrap();
451 obj.add_relocation(
452 section_id,
453 Relocation {
454 offset: relocation_address,
455 size: relocation_size,
456 kind: relocation_kind,
457 encoding: relocation_encoding,
458 symbol: *target_symbol,
459 addend: r.addend,
460 },
461 )
462 .map_err(ObjectError::Write)?;
463 }
464 RelocationTarget::LibCall(libcall) => {
465 let mut libcall_fn_name = libcall.to_function_name().to_string();
466 if matches!(triple.binary_format, BinaryFormat::Macho) {
467 libcall_fn_name = format!("_{libcall_fn_name}");
468 }
469
470 let libcall_fn_name = libcall_fn_name.as_bytes();
471
472 let target_symbol = obj.symbol_id(libcall_fn_name).unwrap_or_else(|| {
474 obj.add_symbol(ObjSymbol {
475 name: libcall_fn_name.to_vec(),
476 value: 0,
477 size: 0,
478 kind: SymbolKind::Unknown,
479 scope: SymbolScope::Unknown,
480 weak: false,
481 section: SymbolSection::Undefined,
482 flags: SymbolFlags::None,
483 })
484 });
485 obj.add_relocation(
486 section_id,
487 Relocation {
488 offset: relocation_address,
489 size: relocation_size,
490 kind: relocation_kind,
491 encoding: relocation_encoding,
492 symbol: target_symbol,
493 addend: r.addend,
494 },
495 )
496 .map_err(ObjectError::Write)?;
497 }
498 RelocationTarget::CustomSection(section_index) => {
499 let (_, target_symbol) = custom_section_ids.get(section_index).unwrap();
500 obj.add_relocation(
501 section_id,
502 Relocation {
503 offset: relocation_address,
504 size: relocation_size,
505 kind: relocation_kind,
506 encoding: relocation_encoding,
507 symbol: *target_symbol,
508 addend: r.addend,
509 },
510 )
511 .map_err(ObjectError::Write)?;
512 }
513 };
514 }
515 }
516
517 Ok(())
518}
519
520pub fn emit_serialized(
541 obj: &mut Object,
542 sercomp: &[u8],
543 triple: &Triple,
544 object_name: &str,
545) -> Result<(), ObjectError> {
546 obj.set_mangling(object::write::Mangling::None);
547 let len_name = format!("{object_name}_LENGTH");
549 let data_name = format!("{object_name}_DATA");
550 let align = match triple.architecture {
553 Architecture::X86_64 => 1,
554 Architecture::Aarch64(_) => 4,
556 _ => 1,
557 };
558
559 let len = sercomp.len();
560 let section_id = obj.section_id(StandardSection::Data);
561 let symbol_id = obj.add_symbol(ObjSymbol {
562 name: len_name.as_bytes().to_vec(),
563 value: 0,
564 size: len.to_le_bytes().len() as _,
565 kind: SymbolKind::Data,
566 scope: SymbolScope::Dynamic,
567 weak: false,
568 section: SymbolSection::Section(section_id),
569 flags: SymbolFlags::None,
570 });
571 obj.add_symbol_data(symbol_id, section_id, &len.to_le_bytes(), align);
572
573 let section_id = obj.section_id(StandardSection::Data);
574 let symbol_id = obj.add_symbol(ObjSymbol {
575 name: data_name.as_bytes().to_vec(),
576 value: 0,
577 size: sercomp.len() as _,
578 kind: SymbolKind::Data,
579 scope: SymbolScope::Dynamic,
580 weak: false,
581 section: SymbolSection::Section(section_id),
582 flags: SymbolFlags::None,
583 });
584 obj.add_symbol_data(symbol_id, section_id, sercomp, align);
585
586 Ok(())
587}
588
589pub struct ObjectMetadataBuilder {
597 placeholder_data: Vec<u8>,
598 metadata_length: u64,
599 section_offset: u64,
600 num_function_pointers: u64,
601 num_trampolines: u64,
602 num_dynamic_function_trampoline_pointers: u64,
603 endianness: Endianness,
604 pointer_width: PointerWidth,
605}
606
607impl ObjectMetadataBuilder {
608 pub fn new(metadata: &ModuleMetadata, triple: &Triple) -> Result<Self, ObjectError> {
610 let serialized_data = metadata.serialize()?;
611 let mut metadata_binary = vec![];
612 metadata_binary.extend(MetadataHeader::new(serialized_data.len()).into_bytes());
613 metadata_binary.extend(serialized_data);
614 let metadata_length = metadata_binary.len() as u64;
615
616 let pointer_width = triple.pointer_width().unwrap();
617 let endianness = triple
618 .endianness()
619 .map_err(|_| ObjectError::UnknownEndianness)?;
620
621 let module = &metadata.compile_info.module;
622 let num_function_pointers = module
623 .functions
624 .iter()
625 .filter(|(f_index, _)| module.local_func_index(*f_index).is_some())
626 .count() as u64;
627 let num_trampolines = module.signatures.len() as u64;
628 let num_dynamic_function_trampoline_pointers = module.num_imported_functions as u64;
629
630 let mut aself = Self {
631 placeholder_data: metadata_binary,
632 metadata_length,
633 section_offset: 0,
634 num_function_pointers,
635 num_trampolines,
636 num_dynamic_function_trampoline_pointers,
637 endianness,
638 pointer_width,
639 };
640
641 aself
642 .placeholder_data
643 .extend_from_slice(&aself.serialize_value(aself.num_function_pointers));
644 aself.placeholder_data.extend_from_slice(&vec![
645 0u8;
646 (aself.pointer_bytes() * aself.num_function_pointers)
647 as usize
648 ]);
649 aself
650 .placeholder_data
651 .extend_from_slice(&aself.serialize_value(aself.num_trampolines));
652 aself.placeholder_data.extend_from_slice(&vec![
653 0u8;
654 (aself.pointer_bytes() * aself.num_trampolines)
655 as usize
656 ]);
657 aself.placeholder_data.extend_from_slice(
658 &aself.serialize_value(aself.num_dynamic_function_trampoline_pointers),
659 );
660 aself.placeholder_data.extend_from_slice(&vec![
661 0u8;
662 (aself.pointer_bytes() * aself.num_dynamic_function_trampoline_pointers)
663 as usize
664 ]);
665
666 Ok(aself)
667 }
668
669 pub fn set_section_offset(&mut self, offset: u64) {
671 self.section_offset = offset;
672 }
673
674 pub fn placeholder_data(&self) -> &[u8] {
676 &self.placeholder_data
677 }
678
679 pub fn pointer_bytes(&self) -> u64 {
681 self.pointer_width.bytes() as u64
682 }
683
684 pub fn setup_function_pointer(
686 &self,
687 obj: &mut Object,
688 index: usize,
689 symbol_id: SymbolId,
690 ) -> Result<(), ObjectError> {
691 let section_id = obj.section_id(StandardSection::Data);
692 obj.add_relocation(
693 section_id,
694 Relocation {
695 offset: self.function_pointers_start_offset()
696 + self.pointer_bytes() * (index as u64),
697 size: self.pointer_width.bits(),
698 kind: RelocationKind::Absolute,
699 encoding: RelocationEncoding::Generic,
700 symbol: symbol_id,
701 addend: 0,
702 },
703 )
704 .map_err(ObjectError::Write)
705 }
706
707 pub fn setup_trampoline(
709 &self,
710 obj: &mut Object,
711 index: usize,
712 symbol_id: SymbolId,
713 ) -> Result<(), ObjectError> {
714 let section_id = obj.section_id(StandardSection::Data);
715 obj.add_relocation(
716 section_id,
717 Relocation {
718 offset: self.trampolines_start_offset() + self.pointer_bytes() * (index as u64),
719 size: self.pointer_width.bits(),
720 kind: RelocationKind::Absolute,
721 encoding: RelocationEncoding::Generic,
722 symbol: symbol_id,
723 addend: 0,
724 },
725 )
726 .map_err(ObjectError::Write)
727 }
728
729 pub fn setup_dynamic_function_trampoline_pointer(
731 &self,
732 obj: &mut Object,
733 index: usize,
734 symbol_id: SymbolId,
735 ) -> Result<(), ObjectError> {
736 let section_id = obj.section_id(StandardSection::Data);
737 obj.add_relocation(
738 section_id,
739 Relocation {
740 offset: self.dynamic_function_trampoline_pointers_start_offset()
741 + self.pointer_bytes() * (index as u64),
742 size: self.pointer_width.bits(),
743 kind: RelocationKind::Absolute,
744 encoding: RelocationEncoding::Generic,
745 symbol: symbol_id,
746 addend: 0,
747 },
748 )
749 .map_err(ObjectError::Write)
750 }
751
752 fn function_pointers_start_offset(&self) -> u64 {
753 self.section_offset + self.metadata_length + self.pointer_bytes()
754 }
755
756 fn trampolines_start_offset(&self) -> u64 {
757 self.function_pointers_start_offset()
758 + self.pointer_bytes() * self.num_function_pointers
759 + self.pointer_bytes()
760 }
761
762 fn dynamic_function_trampoline_pointers_start_offset(&self) -> u64 {
763 self.trampolines_start_offset()
764 + self.pointer_bytes() * self.num_trampolines
765 + self.pointer_bytes()
766 }
767
768 fn serialize_value(&self, value: u64) -> Vec<u8> {
769 match (self.endianness, self.pointer_width) {
770 (Endianness::Little, PointerWidth::U16) => (value as u16).to_le_bytes().to_vec(),
771 (Endianness::Big, PointerWidth::U16) => (value as u16).to_be_bytes().to_vec(),
772 (Endianness::Little, PointerWidth::U32) => (value as u32).to_le_bytes().to_vec(),
773 (Endianness::Big, PointerWidth::U32) => (value as u32).to_be_bytes().to_vec(),
774 (Endianness::Little, PointerWidth::U64) => value.to_le_bytes().to_vec(),
775 (Endianness::Big, PointerWidth::U64) => value.to_be_bytes().to_vec(),
776 }
777 }
778}