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