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