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