1use crate::error::ObjectError;
2use object::write::{
3 Object, Relocation, StandardSection, StandardSegment, Symbol as ObjSymbol, SymbolSection,
4};
5use object::{
6 elf, macho, FileFlags, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags,
7 SymbolKind, SymbolScope,
8};
9use wasmer_types::entity::PrimaryMap;
10use wasmer_types::LocalFunctionIndex;
11use wasmer_types::{
12 Architecture, BinaryFormat, Compilation, CustomSectionProtection, Endianness,
13 RelocationKind as Reloc, RelocationTarget, SectionIndex, Triple,
14};
15use wasmer_types::{Symbol, SymbolRegistry};
16
17const DWARF_SECTION_NAME: &[u8] = b".eh_frame";
18
19pub fn get_object_for_target(triple: &Triple) -> Result<Object, ObjectError> {
35 let obj_binary_format = match triple.binary_format {
36 BinaryFormat::Elf => object::BinaryFormat::Elf,
37 BinaryFormat::Macho => object::BinaryFormat::MachO,
38 BinaryFormat::Coff => object::BinaryFormat::Coff,
39 binary_format => {
40 return Err(ObjectError::UnsupportedBinaryFormat(format!(
41 "{}",
42 binary_format
43 )));
44 }
45 };
46 let obj_architecture = match triple.architecture {
47 Architecture::X86_64 => object::Architecture::X86_64,
48 Architecture::Aarch64(_) => object::Architecture::Aarch64,
49 Architecture::Riscv64(_) => object::Architecture::Riscv64,
50 Architecture::LoongArch64 => object::Architecture::LoongArch64,
51 architecture => {
52 return Err(ObjectError::UnsupportedArchitecture(format!(
53 "{}",
54 architecture
55 )));
56 }
57 };
58 let obj_endianness = match triple
59 .endianness()
60 .map_err(|_| ObjectError::UnknownEndianness)?
61 {
62 Endianness::Little => object::Endianness::Little,
63 Endianness::Big => object::Endianness::Big,
64 };
65
66 let mut object = Object::new(obj_binary_format, obj_architecture, obj_endianness);
67
68 if let Architecture::Riscv64(_) = triple.architecture {
69 object.flags = FileFlags::Elf {
70 e_flags: elf::EF_RISCV_FLOAT_ABI_DOUBLE,
71 os_abi: 2,
72 abi_version: 0,
73 };
74 }
75
76 Ok(object)
77}
78
79pub fn emit_data(
96 obj: &mut Object,
97 name: &[u8],
98 data: &[u8],
99 align: u64,
100) -> Result<(), ObjectError> {
101 let symbol_id = obj.add_symbol(ObjSymbol {
102 name: name.to_vec(),
103 value: 0,
104 size: 0,
105 kind: SymbolKind::Data,
106 scope: SymbolScope::Dynamic,
107 weak: false,
108 section: SymbolSection::Undefined,
109 flags: SymbolFlags::None,
110 });
111 let section_id = obj.section_id(StandardSection::Data);
112 obj.add_symbol_data(symbol_id, section_id, data, align);
113
114 Ok(())
115}
116
117pub fn emit_compilation(
138 obj: &mut Object,
139 compilation: Compilation,
140 symbol_registry: &impl SymbolRegistry,
141 triple: &Triple,
142) -> Result<(), ObjectError> {
143 let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len());
144 let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len());
145 for (_, func) in compilation.functions.into_iter() {
146 function_bodies.push(func.body);
147 function_relocations.push(func.relocations);
148 }
149 let custom_section_relocations = compilation
150 .custom_sections
151 .iter()
152 .map(|(_, section)| section.relocations.clone())
153 .collect::<PrimaryMap<SectionIndex, _>>();
154
155 let debug_index = compilation.debug.map(|d| d.eh_frame);
156
157 let align = match triple.architecture {
158 Architecture::X86_64 => 1,
159 Architecture::Aarch64(_) => 4,
161 _ => 1,
162 };
163
164 let custom_section_ids = compilation
166 .custom_sections
167 .into_iter()
168 .map(|(section_index, custom_section)| {
169 if debug_index.map_or(false, |d| d == section_index) {
170 let segment = obj.segment_name(StandardSegment::Debug).to_vec();
172 let section_id =
173 obj.add_section(segment, DWARF_SECTION_NAME.to_vec(), SectionKind::Debug);
174 obj.append_section_data(section_id, custom_section.bytes.as_slice(), align);
175 let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
176 let symbol_id = obj.add_symbol(ObjSymbol {
177 name: section_name.into_bytes(),
178 value: 0,
179 size: custom_section.bytes.len() as _,
180 kind: SymbolKind::Data,
181 scope: SymbolScope::Compilation,
182 weak: false,
183 section: SymbolSection::Section(section_id),
184 flags: SymbolFlags::None,
185 });
186 (section_id, symbol_id)
187 } else {
188 let section_name = symbol_registry.symbol_to_name(Symbol::Section(section_index));
189 let (section_kind, standard_section) = match custom_section.protection {
190 CustomSectionProtection::ReadExecute => {
191 (SymbolKind::Text, StandardSection::Text)
192 }
193 CustomSectionProtection::Read => (SymbolKind::Data, StandardSection::Data),
194 };
195 let section_id = obj.section_id(standard_section);
196 let symbol_id = obj.add_symbol(ObjSymbol {
197 name: section_name.into_bytes(),
198 value: 0,
199 size: custom_section.bytes.len() as _,
200 kind: section_kind,
201 scope: SymbolScope::Dynamic,
202 weak: false,
203 section: SymbolSection::Section(section_id),
204 flags: SymbolFlags::None,
205 });
206 obj.add_symbol_data(
207 symbol_id,
208 section_id,
209 custom_section.bytes.as_slice(),
210 align,
211 );
212 (section_id, symbol_id)
213 }
214 })
215 .collect::<PrimaryMap<SectionIndex, _>>();
216
217 let function_symbol_ids = function_bodies
219 .into_iter()
220 .map(|(function_local_index, function)| {
221 let function_name =
222 symbol_registry.symbol_to_name(Symbol::LocalFunction(function_local_index));
223 let section_id = obj.section_id(StandardSection::Text);
224 let symbol_id = obj.add_symbol(ObjSymbol {
225 name: function_name.into_bytes(),
226 value: 0,
227 size: function.body.len() as _,
228 kind: SymbolKind::Text,
229 scope: SymbolScope::Dynamic,
230 weak: false,
231 section: SymbolSection::Section(section_id),
232 flags: SymbolFlags::None,
233 });
234 obj.add_symbol_data(symbol_id, section_id, &function.body, align);
235 (section_id, symbol_id)
236 })
237 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
238
239 for (signature_index, function) in compilation.function_call_trampolines.into_iter() {
241 let function_name =
242 symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(signature_index));
243 let section_id = obj.section_id(StandardSection::Text);
244 let symbol_id = obj.add_symbol(ObjSymbol {
245 name: function_name.into_bytes(),
246 value: 0,
247 size: function.body.len() as _,
248 kind: SymbolKind::Text,
249 scope: SymbolScope::Dynamic,
250 weak: false,
251 section: SymbolSection::Section(section_id),
252 flags: SymbolFlags::None,
253 });
254 obj.add_symbol_data(symbol_id, section_id, &function.body, align);
255 }
256
257 for (func_index, function) in compilation.dynamic_function_trampolines.into_iter() {
259 let function_name =
260 symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index));
261 let section_id = obj.section_id(StandardSection::Text);
262 let symbol_id = obj.add_symbol(ObjSymbol {
263 name: function_name.into_bytes(),
264 value: 0,
265 size: function.body.len() as _,
266 kind: SymbolKind::Text,
267 scope: SymbolScope::Dynamic,
268 weak: false,
269 section: SymbolSection::Section(section_id),
270 flags: SymbolFlags::None,
271 });
272 obj.add_symbol_data(symbol_id, section_id, &function.body, align);
273 }
274
275 let mut all_relocations = Vec::new();
276
277 for (function_local_index, relocations) in function_relocations.into_iter() {
278 let (section_id, symbol_id) = function_symbol_ids.get(function_local_index).unwrap();
279 all_relocations.push((*section_id, *symbol_id, relocations))
280 }
281
282 for (section_index, relocations) in custom_section_relocations.into_iter() {
283 if !debug_index.map_or(false, |d| d == section_index) {
284 let (section_id, symbol_id) = custom_section_ids.get(section_index).unwrap();
286 all_relocations.push((*section_id, *symbol_id, relocations));
287 }
288 }
289
290 for (section_id, symbol_id, relocations) in all_relocations.into_iter() {
291 let (_symbol_id, section_offset) = obj.symbol_section_and_offset(symbol_id).unwrap();
292
293 for r in relocations {
294 let relocation_address = section_offset + r.offset as u64;
295
296 let (relocation_kind, relocation_encoding, relocation_size) = match r.kind {
297 Reloc::Abs4 => (RelocationKind::Absolute, RelocationEncoding::Generic, 32),
298 Reloc::Abs8 => (RelocationKind::Absolute, RelocationEncoding::Generic, 64),
299 Reloc::X86PCRel4 => (RelocationKind::Relative, RelocationEncoding::Generic, 32),
300 Reloc::X86CallPCRel4 => {
301 (RelocationKind::Relative, RelocationEncoding::X86Branch, 32)
302 }
303 Reloc::X86CallPLTRel4 => (
304 RelocationKind::PltRelative,
305 RelocationEncoding::X86Branch,
306 32,
307 ),
308 Reloc::X86GOTPCRel4 => {
309 (RelocationKind::GotRelative, RelocationEncoding::Generic, 32)
310 }
311 Reloc::Arm64Call => (
312 match obj.format() {
313 object::BinaryFormat::Elf => RelocationKind::Elf(elf::R_AARCH64_CALL26),
314 object::BinaryFormat::MachO => RelocationKind::MachO {
315 value: macho::ARM64_RELOC_BRANCH26,
316 relative: true,
317 },
318 fmt => panic!("unsupported binary format {:?}", fmt),
319 },
320 RelocationEncoding::Generic,
321 32,
322 ),
323 Reloc::ElfX86_64TlsGd => (
324 RelocationKind::Elf(elf::R_X86_64_TLSGD),
325 RelocationEncoding::Generic,
326 32,
327 ),
328 other => {
329 return Err(ObjectError::UnsupportedArchitecture(format!(
330 "{} (relocation: {}",
331 triple.architecture, other
332 )))
333 }
334 };
335
336 match r.reloc_target {
337 RelocationTarget::LocalFunc(index) => {
338 let (_, target_symbol) = function_symbol_ids.get(index).unwrap();
339 obj.add_relocation(
340 section_id,
341 Relocation {
342 offset: relocation_address,
343 size: relocation_size,
344 kind: relocation_kind,
345 encoding: relocation_encoding,
346 symbol: *target_symbol,
347 addend: r.addend,
348 },
349 )
350 .map_err(ObjectError::Write)?;
351 }
352 RelocationTarget::LibCall(libcall) => {
353 let libcall_fn_name = libcall.to_function_name().as_bytes();
354 let target_symbol = obj.symbol_id(libcall_fn_name).unwrap_or_else(|| {
356 obj.add_symbol(ObjSymbol {
357 name: libcall_fn_name.to_vec(),
358 value: 0,
359 size: 0,
360 kind: SymbolKind::Unknown,
361 scope: SymbolScope::Unknown,
362 weak: false,
363 section: SymbolSection::Undefined,
364 flags: SymbolFlags::None,
365 })
366 });
367 obj.add_relocation(
368 section_id,
369 Relocation {
370 offset: relocation_address,
371 size: relocation_size,
372 kind: relocation_kind,
373 encoding: relocation_encoding,
374 symbol: target_symbol,
375 addend: r.addend,
376 },
377 )
378 .map_err(ObjectError::Write)?;
379 }
380 RelocationTarget::CustomSection(section_index) => {
381 let (_, target_symbol) = custom_section_ids.get(section_index).unwrap();
382 obj.add_relocation(
383 section_id,
384 Relocation {
385 offset: relocation_address,
386 size: relocation_size,
387 kind: relocation_kind,
388 encoding: relocation_encoding,
389 symbol: *target_symbol,
390 addend: r.addend,
391 },
392 )
393 .map_err(ObjectError::Write)?;
394 }
395 };
396 }
397 }
398
399 Ok(())
400}
401
402pub fn emit_serialized(
424 obj: &mut Object,
425 sercomp: &[u8],
426 triple: &Triple,
427 object_name: &str,
428) -> Result<(), ObjectError> {
429 obj.set_mangling(object::write::Mangling::None);
430 let len_name = format!("{}_LENGTH", object_name);
432 let data_name = format!("{}_DATA", object_name);
433 let align = match triple.architecture {
436 Architecture::X86_64 => 1,
437 Architecture::Aarch64(_) => 4,
439 _ => 1,
440 };
441
442 let len = sercomp.len();
443 let section_id = obj.section_id(StandardSection::Data);
444 let symbol_id = obj.add_symbol(ObjSymbol {
445 name: len_name.as_bytes().to_vec(),
446 value: 0,
447 size: len.to_le_bytes().len() as _,
448 kind: SymbolKind::Data,
449 scope: SymbolScope::Dynamic,
450 weak: false,
451 section: SymbolSection::Section(section_id),
452 flags: SymbolFlags::None,
453 });
454 obj.add_symbol_data(symbol_id, section_id, &len.to_le_bytes(), align);
455
456 let section_id = obj.section_id(StandardSection::Data);
457 let symbol_id = obj.add_symbol(ObjSymbol {
458 name: data_name.as_bytes().to_vec(),
459 value: 0,
460 size: sercomp.len() as _,
461 kind: SymbolKind::Data,
462 scope: SymbolScope::Dynamic,
463 weak: false,
464 section: SymbolSection::Section(section_id),
465 flags: SymbolFlags::None,
466 });
467 obj.add_symbol_data(symbol_id, section_id, sercomp, align);
468
469 Ok(())
470}