1 | use alloc::vec::Vec; |
2 | |
3 | use crate::write::elf::writer::*; |
4 | use crate::write::string::StringId; |
5 | use crate::write::*; |
6 | use crate::AddressSize; |
7 | use crate::{elf, pod}; |
8 | |
9 | #[derive (Clone, Copy)] |
10 | struct ComdatOffsets { |
11 | offset: usize, |
12 | str_id: StringId, |
13 | } |
14 | |
15 | #[derive (Clone, Copy)] |
16 | struct SectionOffsets { |
17 | index: SectionIndex, |
18 | offset: usize, |
19 | str_id: StringId, |
20 | reloc_offset: usize, |
21 | reloc_str_id: Option<StringId>, |
22 | } |
23 | |
24 | #[derive (Default, Clone, Copy)] |
25 | struct SymbolOffsets { |
26 | index: SymbolIndex, |
27 | str_id: Option<StringId>, |
28 | } |
29 | |
30 | // Public methods. |
31 | impl<'a> Object<'a> { |
32 | /// Add a property with a u32 value to the ELF ".note.gnu.property" section. |
33 | /// |
34 | /// Requires `feature = "elf"`. |
35 | pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) { |
36 | if self.format != BinaryFormat::Elf { |
37 | return; |
38 | } |
39 | |
40 | let align = if self.elf_is_64() { 8 } else { 4 }; |
41 | let mut data = Vec::with_capacity(32); |
42 | let n_name = b"GNU \0" ; |
43 | data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 { |
44 | n_namesz: U32::new(self.endian, n_name.len() as u32), |
45 | n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32), |
46 | n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0), |
47 | })); |
48 | data.extend_from_slice(n_name); |
49 | // This happens to already be aligned correctly. |
50 | debug_assert_eq!(util::align(data.len(), align), data.len()); |
51 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property))); |
52 | // Value size |
53 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4))); |
54 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value))); |
55 | util::write_align(&mut data, align); |
56 | |
57 | let section = self.section_id(StandardSection::GnuProperty); |
58 | self.append_section_data(section, &data, align as u64); |
59 | } |
60 | } |
61 | |
62 | // Private methods. |
63 | impl<'a> Object<'a> { |
64 | pub(crate) fn elf_section_info( |
65 | &self, |
66 | section: StandardSection, |
67 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
68 | match section { |
69 | StandardSection::Text => (&[], &b".text" [..], SectionKind::Text, SectionFlags::None), |
70 | StandardSection::Data => (&[], &b".data" [..], SectionKind::Data, SectionFlags::None), |
71 | StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => ( |
72 | &[], |
73 | &b".rodata" [..], |
74 | SectionKind::ReadOnlyData, |
75 | SectionFlags::None, |
76 | ), |
77 | StandardSection::ReadOnlyDataWithRel => ( |
78 | &[], |
79 | b".data.rel.ro" , |
80 | SectionKind::ReadOnlyDataWithRel, |
81 | SectionFlags::None, |
82 | ), |
83 | StandardSection::UninitializedData => ( |
84 | &[], |
85 | &b".bss" [..], |
86 | SectionKind::UninitializedData, |
87 | SectionFlags::None, |
88 | ), |
89 | StandardSection::Tls => (&[], &b".tdata" [..], SectionKind::Tls, SectionFlags::None), |
90 | StandardSection::UninitializedTls => ( |
91 | &[], |
92 | &b".tbss" [..], |
93 | SectionKind::UninitializedTls, |
94 | SectionFlags::None, |
95 | ), |
96 | StandardSection::TlsVariables => { |
97 | // Unsupported section. |
98 | (&[], &[], SectionKind::TlsVariables, SectionFlags::None) |
99 | } |
100 | StandardSection::Common => { |
101 | // Unsupported section. |
102 | (&[], &[], SectionKind::Common, SectionFlags::None) |
103 | } |
104 | StandardSection::GnuProperty => ( |
105 | &[], |
106 | &b".note.gnu.property" [..], |
107 | SectionKind::Note, |
108 | SectionFlags::Elf { |
109 | sh_flags: u64::from(elf::SHF_ALLOC), |
110 | }, |
111 | ), |
112 | } |
113 | } |
114 | |
115 | pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { |
116 | let mut name = section.to_vec(); |
117 | name.push(b'.' ); |
118 | name.extend_from_slice(value); |
119 | name |
120 | } |
121 | |
122 | fn elf_has_relocation_addend(&self) -> Result<bool> { |
123 | Ok(match self.architecture { |
124 | Architecture::Aarch64 => true, |
125 | Architecture::Aarch64_Ilp32 => true, |
126 | Architecture::Arm => false, |
127 | Architecture::Avr => true, |
128 | Architecture::Bpf => false, |
129 | Architecture::Csky => true, |
130 | Architecture::I386 => false, |
131 | Architecture::X86_64 => true, |
132 | Architecture::X86_64_X32 => true, |
133 | Architecture::Hexagon => true, |
134 | Architecture::LoongArch64 => true, |
135 | Architecture::Mips => false, |
136 | Architecture::Mips64 => true, |
137 | Architecture::Msp430 => true, |
138 | Architecture::PowerPc => true, |
139 | Architecture::PowerPc64 => true, |
140 | Architecture::Riscv64 => true, |
141 | Architecture::Riscv32 => true, |
142 | Architecture::S390x => true, |
143 | Architecture::Sbf => false, |
144 | Architecture::Sharc => true, |
145 | Architecture::Sparc64 => true, |
146 | Architecture::Xtensa => true, |
147 | _ => { |
148 | return Err(Error(format!( |
149 | "unimplemented architecture {:?}" , |
150 | self.architecture |
151 | ))); |
152 | } |
153 | }) |
154 | } |
155 | |
156 | pub(crate) fn elf_fixup_relocation(&mut self, relocation: &mut Relocation) -> Result<i64> { |
157 | // Determine whether the addend is stored in the relocation or the data. |
158 | if self.elf_has_relocation_addend()? { |
159 | Ok(0) |
160 | } else { |
161 | let constant = relocation.addend; |
162 | relocation.addend = 0; |
163 | Ok(constant) |
164 | } |
165 | } |
166 | |
167 | pub(crate) fn elf_is_64(&self) -> bool { |
168 | match self.architecture.address_size().unwrap() { |
169 | AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, |
170 | AddressSize::U64 => true, |
171 | } |
172 | } |
173 | |
174 | pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
175 | // Create reloc section header names so we can reference them. |
176 | let is_rela = self.elf_has_relocation_addend()?; |
177 | let reloc_names: Vec<_> = self |
178 | .sections |
179 | .iter() |
180 | .map(|section| { |
181 | let mut reloc_name = Vec::with_capacity( |
182 | if is_rela { ".rela" .len() } else { ".rel" .len() } + section.name.len(), |
183 | ); |
184 | if !section.relocations.is_empty() { |
185 | reloc_name.extend_from_slice(if is_rela { |
186 | &b".rela" [..] |
187 | } else { |
188 | &b".rel" [..] |
189 | }); |
190 | reloc_name.extend_from_slice(§ion.name); |
191 | } |
192 | reloc_name |
193 | }) |
194 | .collect(); |
195 | |
196 | // Start calculating offsets of everything. |
197 | let mut writer = Writer::new(self.endian, self.elf_is_64(), buffer); |
198 | writer.reserve_file_header(); |
199 | |
200 | // Calculate size of section data. |
201 | let mut comdat_offsets = Vec::with_capacity(self.comdats.len()); |
202 | for comdat in &self.comdats { |
203 | if comdat.kind != ComdatKind::Any { |
204 | return Err(Error(format!( |
205 | "unsupported COMDAT symbol ` {}` kind {:?}" , |
206 | self.symbols[comdat.symbol.0].name().unwrap_or("" ), |
207 | comdat.kind |
208 | ))); |
209 | } |
210 | |
211 | writer.reserve_section_index(); |
212 | let offset = writer.reserve_comdat(comdat.sections.len()); |
213 | let str_id = writer.add_section_name(b".group" ); |
214 | comdat_offsets.push(ComdatOffsets { offset, str_id }); |
215 | } |
216 | let mut section_offsets = Vec::with_capacity(self.sections.len()); |
217 | for (section, reloc_name) in self.sections.iter().zip(reloc_names.iter()) { |
218 | let index = writer.reserve_section_index(); |
219 | let offset = writer.reserve(section.data.len(), section.align as usize); |
220 | let str_id = writer.add_section_name(§ion.name); |
221 | let mut reloc_str_id = None; |
222 | if !section.relocations.is_empty() { |
223 | writer.reserve_section_index(); |
224 | reloc_str_id = Some(writer.add_section_name(reloc_name)); |
225 | } |
226 | section_offsets.push(SectionOffsets { |
227 | index, |
228 | offset, |
229 | str_id, |
230 | // Relocation data is reserved later. |
231 | reloc_offset: 0, |
232 | reloc_str_id, |
233 | }); |
234 | } |
235 | |
236 | // Calculate index of symbols and add symbol strings to strtab. |
237 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
238 | writer.reserve_null_symbol_index(); |
239 | // Local symbols must come before global. |
240 | for (index, symbol) in self.symbols.iter().enumerate() { |
241 | if symbol.is_local() { |
242 | let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); |
243 | symbol_offsets[index].index = writer.reserve_symbol_index(section_index); |
244 | } |
245 | } |
246 | let symtab_num_local = writer.symbol_count(); |
247 | for (index, symbol) in self.symbols.iter().enumerate() { |
248 | if !symbol.is_local() { |
249 | let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); |
250 | symbol_offsets[index].index = writer.reserve_symbol_index(section_index); |
251 | } |
252 | } |
253 | for (index, symbol) in self.symbols.iter().enumerate() { |
254 | if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() { |
255 | symbol_offsets[index].str_id = Some(writer.add_string(&symbol.name)); |
256 | } |
257 | } |
258 | |
259 | // Calculate size of symbols. |
260 | writer.reserve_symtab_section_index(); |
261 | writer.reserve_symtab(); |
262 | if writer.symtab_shndx_needed() { |
263 | writer.reserve_symtab_shndx_section_index(); |
264 | } |
265 | writer.reserve_symtab_shndx(); |
266 | writer.reserve_strtab_section_index(); |
267 | writer.reserve_strtab(); |
268 | |
269 | // Calculate size of relocations. |
270 | for (index, section) in self.sections.iter().enumerate() { |
271 | let count = section.relocations.len(); |
272 | if count != 0 { |
273 | section_offsets[index].reloc_offset = writer.reserve_relocations(count, is_rela); |
274 | } |
275 | } |
276 | |
277 | // Calculate size of section headers. |
278 | writer.reserve_shstrtab_section_index(); |
279 | writer.reserve_shstrtab(); |
280 | writer.reserve_section_headers(); |
281 | |
282 | // Start writing. |
283 | let e_type = elf::ET_REL; |
284 | let e_machine = match (self.architecture, self.sub_architecture) { |
285 | (Architecture::Aarch64, None) => elf::EM_AARCH64, |
286 | (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, |
287 | (Architecture::Arm, None) => elf::EM_ARM, |
288 | (Architecture::Avr, None) => elf::EM_AVR, |
289 | (Architecture::Bpf, None) => elf::EM_BPF, |
290 | (Architecture::Csky, None) => elf::EM_CSKY, |
291 | (Architecture::I386, None) => elf::EM_386, |
292 | (Architecture::X86_64, None) => elf::EM_X86_64, |
293 | (Architecture::X86_64_X32, None) => elf::EM_X86_64, |
294 | (Architecture::Hexagon, None) => elf::EM_HEXAGON, |
295 | (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, |
296 | (Architecture::Mips, None) => elf::EM_MIPS, |
297 | (Architecture::Mips64, None) => elf::EM_MIPS, |
298 | (Architecture::Msp430, None) => elf::EM_MSP430, |
299 | (Architecture::PowerPc, None) => elf::EM_PPC, |
300 | (Architecture::PowerPc64, None) => elf::EM_PPC64, |
301 | (Architecture::Riscv32, None) => elf::EM_RISCV, |
302 | (Architecture::Riscv64, None) => elf::EM_RISCV, |
303 | (Architecture::S390x, None) => elf::EM_S390, |
304 | (Architecture::Sbf, None) => elf::EM_SBF, |
305 | (Architecture::Sharc, None) => elf::EM_SHARC, |
306 | (Architecture::Sparc64, None) => elf::EM_SPARCV9, |
307 | (Architecture::Xtensa, None) => elf::EM_XTENSA, |
308 | _ => { |
309 | return Err(Error(format!( |
310 | "unimplemented architecture {:?} with sub-architecture {:?}" , |
311 | self.architecture, self.sub_architecture |
312 | ))); |
313 | } |
314 | }; |
315 | let (os_abi, abi_version, e_flags) = if let FileFlags::Elf { |
316 | os_abi, |
317 | abi_version, |
318 | e_flags, |
319 | } = self.flags |
320 | { |
321 | (os_abi, abi_version, e_flags) |
322 | } else { |
323 | (elf::ELFOSABI_NONE, 0, 0) |
324 | }; |
325 | writer.write_file_header(&FileHeader { |
326 | os_abi, |
327 | abi_version, |
328 | e_type, |
329 | e_machine, |
330 | e_entry: 0, |
331 | e_flags, |
332 | })?; |
333 | |
334 | // Write section data. |
335 | for comdat in &self.comdats { |
336 | writer.write_comdat_header(); |
337 | for section in &comdat.sections { |
338 | writer.write_comdat_entry(section_offsets[section.0].index); |
339 | } |
340 | } |
341 | for (index, section) in self.sections.iter().enumerate() { |
342 | writer.write_align(section.align as usize); |
343 | debug_assert_eq!(section_offsets[index].offset, writer.len()); |
344 | writer.write(§ion.data); |
345 | } |
346 | |
347 | // Write symbols. |
348 | writer.write_null_symbol(); |
349 | let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> { |
350 | let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags { |
351 | st_info |
352 | } else { |
353 | let st_type = match symbol.kind { |
354 | SymbolKind::Null => elf::STT_NOTYPE, |
355 | SymbolKind::Text => { |
356 | if symbol.is_undefined() { |
357 | elf::STT_NOTYPE |
358 | } else { |
359 | elf::STT_FUNC |
360 | } |
361 | } |
362 | SymbolKind::Data => { |
363 | if symbol.is_undefined() { |
364 | elf::STT_NOTYPE |
365 | } else if symbol.is_common() { |
366 | elf::STT_COMMON |
367 | } else { |
368 | elf::STT_OBJECT |
369 | } |
370 | } |
371 | SymbolKind::Section => elf::STT_SECTION, |
372 | SymbolKind::File => elf::STT_FILE, |
373 | SymbolKind::Tls => elf::STT_TLS, |
374 | SymbolKind::Label => elf::STT_NOTYPE, |
375 | SymbolKind::Unknown => { |
376 | if symbol.is_undefined() { |
377 | elf::STT_NOTYPE |
378 | } else { |
379 | return Err(Error(format!( |
380 | "unimplemented symbol ` {}` kind {:?}" , |
381 | symbol.name().unwrap_or("" ), |
382 | symbol.kind |
383 | ))); |
384 | } |
385 | } |
386 | }; |
387 | let st_bind = if symbol.weak { |
388 | elf::STB_WEAK |
389 | } else if symbol.is_undefined() { |
390 | elf::STB_GLOBAL |
391 | } else if symbol.is_local() { |
392 | elf::STB_LOCAL |
393 | } else { |
394 | elf::STB_GLOBAL |
395 | }; |
396 | (st_bind << 4) + st_type |
397 | }; |
398 | let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags { |
399 | st_other |
400 | } else if symbol.scope == SymbolScope::Linkage { |
401 | elf::STV_HIDDEN |
402 | } else { |
403 | elf::STV_DEFAULT |
404 | }; |
405 | let (st_shndx, section) = match symbol.section { |
406 | SymbolSection::None => { |
407 | debug_assert_eq!(symbol.kind, SymbolKind::File); |
408 | (elf::SHN_ABS, None) |
409 | } |
410 | SymbolSection::Undefined => (elf::SHN_UNDEF, None), |
411 | SymbolSection::Absolute => (elf::SHN_ABS, None), |
412 | SymbolSection::Common => (elf::SHN_COMMON, None), |
413 | SymbolSection::Section(id) => (0, Some(section_offsets[id.0].index)), |
414 | }; |
415 | writer.write_symbol(&Sym { |
416 | name: symbol_offsets[index].str_id, |
417 | section, |
418 | st_info, |
419 | st_other, |
420 | st_shndx, |
421 | st_value: symbol.value, |
422 | st_size: symbol.size, |
423 | }); |
424 | Ok(()) |
425 | }; |
426 | for (index, symbol) in self.symbols.iter().enumerate() { |
427 | if symbol.is_local() { |
428 | write_symbol(index, symbol)?; |
429 | } |
430 | } |
431 | for (index, symbol) in self.symbols.iter().enumerate() { |
432 | if !symbol.is_local() { |
433 | write_symbol(index, symbol)?; |
434 | } |
435 | } |
436 | writer.write_symtab_shndx(); |
437 | writer.write_strtab(); |
438 | |
439 | // Write relocations. |
440 | for (index, section) in self.sections.iter().enumerate() { |
441 | if !section.relocations.is_empty() { |
442 | writer.write_align_relocation(); |
443 | debug_assert_eq!(section_offsets[index].reloc_offset, writer.len()); |
444 | for reloc in §ion.relocations { |
445 | let r_type = match self.architecture { |
446 | Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) { |
447 | (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { |
448 | elf::R_AARCH64_ABS64 |
449 | } |
450 | (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { |
451 | elf::R_AARCH64_ABS32 |
452 | } |
453 | (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { |
454 | elf::R_AARCH64_ABS16 |
455 | } |
456 | (RelocationKind::Relative, RelocationEncoding::Generic, 64) => { |
457 | elf::R_AARCH64_PREL64 |
458 | } |
459 | (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { |
460 | elf::R_AARCH64_PREL32 |
461 | } |
462 | (RelocationKind::Relative, RelocationEncoding::Generic, 16) => { |
463 | elf::R_AARCH64_PREL16 |
464 | } |
465 | (RelocationKind::Relative, RelocationEncoding::AArch64Call, 26) |
466 | | (RelocationKind::PltRelative, RelocationEncoding::AArch64Call, 26) => { |
467 | elf::R_AARCH64_CALL26 |
468 | } |
469 | (RelocationKind::Elf(x), _, _) => x, |
470 | _ => { |
471 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
472 | } |
473 | }, |
474 | Architecture::Aarch64_Ilp32 => { |
475 | match (reloc.kind, reloc.encoding, reloc.size) { |
476 | (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { |
477 | elf::R_AARCH64_P32_ABS32 |
478 | } |
479 | (RelocationKind::Elf(x), _, _) => x, |
480 | _ => { |
481 | return Err(Error(format!( |
482 | "unimplemented relocation {:?}" , |
483 | reloc |
484 | ))); |
485 | } |
486 | } |
487 | } |
488 | Architecture::Arm => match (reloc.kind, reloc.encoding, reloc.size) { |
489 | (RelocationKind::Absolute, _, 32) => elf::R_ARM_ABS32, |
490 | (RelocationKind::Elf(x), _, _) => x, |
491 | _ => { |
492 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
493 | } |
494 | }, |
495 | Architecture::Avr => match (reloc.kind, reloc.encoding, reloc.size) { |
496 | (RelocationKind::Absolute, _, 32) => elf::R_AVR_32, |
497 | (RelocationKind::Absolute, _, 16) => elf::R_AVR_16, |
498 | (RelocationKind::Elf(x), _, _) => x, |
499 | _ => { |
500 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
501 | } |
502 | }, |
503 | Architecture::Bpf => match (reloc.kind, reloc.encoding, reloc.size) { |
504 | (RelocationKind::Absolute, _, 64) => elf::R_BPF_64_64, |
505 | (RelocationKind::Absolute, _, 32) => elf::R_BPF_64_32, |
506 | (RelocationKind::Elf(x), _, _) => x, |
507 | _ => { |
508 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
509 | } |
510 | }, |
511 | Architecture::Csky => match (reloc.kind, reloc.encoding, reloc.size) { |
512 | (RelocationKind::Absolute, _, 32) => elf::R_CKCORE_ADDR32, |
513 | (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { |
514 | elf::R_CKCORE_PCREL32 |
515 | } |
516 | (RelocationKind::Elf(x), _, _) => x, |
517 | _ => { |
518 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
519 | } |
520 | }, |
521 | Architecture::I386 => match (reloc.kind, reloc.size) { |
522 | (RelocationKind::Absolute, 32) => elf::R_386_32, |
523 | (RelocationKind::Relative, 32) => elf::R_386_PC32, |
524 | (RelocationKind::Got, 32) => elf::R_386_GOT32, |
525 | (RelocationKind::PltRelative, 32) => elf::R_386_PLT32, |
526 | (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF, |
527 | (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC, |
528 | (RelocationKind::Absolute, 16) => elf::R_386_16, |
529 | (RelocationKind::Relative, 16) => elf::R_386_PC16, |
530 | (RelocationKind::Absolute, 8) => elf::R_386_8, |
531 | (RelocationKind::Relative, 8) => elf::R_386_PC8, |
532 | (RelocationKind::Elf(x), _) => x, |
533 | _ => { |
534 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
535 | } |
536 | }, |
537 | Architecture::X86_64 | Architecture::X86_64_X32 => { |
538 | match (reloc.kind, reloc.encoding, reloc.size) { |
539 | (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { |
540 | elf::R_X86_64_64 |
541 | } |
542 | (RelocationKind::Relative, RelocationEncoding::X86Branch, 32) => { |
543 | elf::R_X86_64_PLT32 |
544 | } |
545 | (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32, |
546 | (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32, |
547 | (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32, |
548 | (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL, |
549 | (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { |
550 | elf::R_X86_64_32 |
551 | } |
552 | (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => { |
553 | elf::R_X86_64_32S |
554 | } |
555 | (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16, |
556 | (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16, |
557 | (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8, |
558 | (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8, |
559 | (RelocationKind::Elf(x), _, _) => x, |
560 | _ => { |
561 | return Err(Error(format!( |
562 | "unimplemented relocation {:?}" , |
563 | reloc |
564 | ))); |
565 | } |
566 | } |
567 | } |
568 | Architecture::Hexagon => match (reloc.kind, reloc.encoding, reloc.size) { |
569 | (RelocationKind::Absolute, _, 32) => elf::R_HEX_32, |
570 | (RelocationKind::Elf(x), _, _) => x, |
571 | _ => { |
572 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
573 | } |
574 | }, |
575 | Architecture::LoongArch64 => match (reloc.kind, reloc.encoding, reloc.size) |
576 | { |
577 | (RelocationKind::Absolute, _, 32) => elf::R_LARCH_32, |
578 | (RelocationKind::Absolute, _, 64) => elf::R_LARCH_64, |
579 | (RelocationKind::Relative, _, 32) => elf::R_LARCH_32_PCREL, |
580 | (RelocationKind::Relative, _, 64) => elf::R_LARCH_64_PCREL, |
581 | (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 16) |
582 | | ( |
583 | RelocationKind::PltRelative, |
584 | RelocationEncoding::LoongArchBranch, |
585 | 16, |
586 | ) => elf::R_LARCH_B16, |
587 | (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 21) |
588 | | ( |
589 | RelocationKind::PltRelative, |
590 | RelocationEncoding::LoongArchBranch, |
591 | 21, |
592 | ) => elf::R_LARCH_B21, |
593 | (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 26) |
594 | | ( |
595 | RelocationKind::PltRelative, |
596 | RelocationEncoding::LoongArchBranch, |
597 | 26, |
598 | ) => elf::R_LARCH_B26, |
599 | (RelocationKind::Elf(x), _, _) => x, |
600 | _ => { |
601 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
602 | } |
603 | }, |
604 | Architecture::Mips | Architecture::Mips64 => { |
605 | match (reloc.kind, reloc.encoding, reloc.size) { |
606 | (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16, |
607 | (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32, |
608 | (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64, |
609 | (RelocationKind::Elf(x), _, _) => x, |
610 | _ => { |
611 | return Err(Error(format!( |
612 | "unimplemented relocation {:?}" , |
613 | reloc |
614 | ))); |
615 | } |
616 | } |
617 | } |
618 | Architecture::Msp430 => match (reloc.kind, reloc.encoding, reloc.size) { |
619 | (RelocationKind::Absolute, _, 32) => elf::R_MSP430_32, |
620 | (RelocationKind::Absolute, _, 16) => elf::R_MSP430_16_BYTE, |
621 | (RelocationKind::Elf(x), _, _) => x, |
622 | _ => { |
623 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
624 | } |
625 | }, |
626 | Architecture::PowerPc => match (reloc.kind, reloc.encoding, reloc.size) { |
627 | (RelocationKind::Absolute, _, 32) => elf::R_PPC_ADDR32, |
628 | (RelocationKind::Elf(x), _, _) => x, |
629 | _ => { |
630 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
631 | } |
632 | }, |
633 | Architecture::PowerPc64 => match (reloc.kind, reloc.encoding, reloc.size) { |
634 | (RelocationKind::Absolute, _, 32) => elf::R_PPC64_ADDR32, |
635 | (RelocationKind::Absolute, _, 64) => elf::R_PPC64_ADDR64, |
636 | (RelocationKind::Elf(x), _, _) => x, |
637 | _ => { |
638 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
639 | } |
640 | }, |
641 | Architecture::Riscv32 | Architecture::Riscv64 => { |
642 | match (reloc.kind, reloc.encoding, reloc.size) { |
643 | (RelocationKind::Absolute, _, 32) => elf::R_RISCV_32, |
644 | (RelocationKind::Absolute, _, 64) => elf::R_RISCV_64, |
645 | (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { |
646 | elf::R_RISCV_32_PCREL |
647 | } |
648 | (RelocationKind::Elf(x), _, _) => x, |
649 | _ => { |
650 | return Err(Error(format!( |
651 | "unimplemented relocation {:?}" , |
652 | reloc |
653 | ))); |
654 | } |
655 | } |
656 | } |
657 | Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) { |
658 | (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => { |
659 | elf::R_390_8 |
660 | } |
661 | (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { |
662 | elf::R_390_16 |
663 | } |
664 | (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { |
665 | elf::R_390_32 |
666 | } |
667 | (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { |
668 | elf::R_390_64 |
669 | } |
670 | (RelocationKind::Relative, RelocationEncoding::Generic, 16) => { |
671 | elf::R_390_PC16 |
672 | } |
673 | (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { |
674 | elf::R_390_PC32 |
675 | } |
676 | (RelocationKind::Relative, RelocationEncoding::Generic, 64) => { |
677 | elf::R_390_PC64 |
678 | } |
679 | (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => { |
680 | elf::R_390_PC16DBL |
681 | } |
682 | (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => { |
683 | elf::R_390_PC32DBL |
684 | } |
685 | (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => { |
686 | elf::R_390_PLT16DBL |
687 | } |
688 | (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => { |
689 | elf::R_390_PLT32DBL |
690 | } |
691 | (RelocationKind::Got, RelocationEncoding::Generic, 16) => { |
692 | elf::R_390_GOT16 |
693 | } |
694 | (RelocationKind::Got, RelocationEncoding::Generic, 32) => { |
695 | elf::R_390_GOT32 |
696 | } |
697 | (RelocationKind::Got, RelocationEncoding::Generic, 64) => { |
698 | elf::R_390_GOT64 |
699 | } |
700 | (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => { |
701 | elf::R_390_GOTENT |
702 | } |
703 | (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => { |
704 | elf::R_390_GOTOFF16 |
705 | } |
706 | (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => { |
707 | elf::R_390_GOTOFF32 |
708 | } |
709 | (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => { |
710 | elf::R_390_GOTOFF64 |
711 | } |
712 | (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => { |
713 | elf::R_390_GOTPC |
714 | } |
715 | (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => { |
716 | elf::R_390_GOTPCDBL |
717 | } |
718 | (RelocationKind::Elf(x), _, _) => x, |
719 | _ => { |
720 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
721 | } |
722 | }, |
723 | Architecture::Sbf => match (reloc.kind, reloc.encoding, reloc.size) { |
724 | (RelocationKind::Absolute, _, 64) => elf::R_SBF_64_64, |
725 | (RelocationKind::Absolute, _, 32) => elf::R_SBF_64_32, |
726 | (RelocationKind::Elf(x), _, _) => x, |
727 | _ => { |
728 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
729 | } |
730 | }, |
731 | Architecture::Sharc => match (reloc.kind, reloc.encoding, reloc.size) { |
732 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 32) => { |
733 | elf::R_SHARC_ADDR32_V3 |
734 | } |
735 | (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { |
736 | elf::R_SHARC_ADDR_VAR_V3 |
737 | } |
738 | (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 24) => { |
739 | elf::R_SHARC_PCRLONG_V3 |
740 | } |
741 | (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 6) => { |
742 | elf::R_SHARC_PCRSHORT_V3 |
743 | } |
744 | (RelocationKind::Relative, RelocationEncoding::SharcTypeB, 6) => { |
745 | elf::R_SHARC_PCRSHORT_V3 |
746 | } |
747 | (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { |
748 | elf::R_SHARC_ADDR_VAR16_V3 |
749 | } |
750 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 16) => { |
751 | elf::R_SHARC_DATA16_V3 |
752 | } |
753 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 16) => { |
754 | elf::R_SHARC_DATA16_VISA_V3 |
755 | } |
756 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 24) => { |
757 | elf::R_SHARC_ADDR24_V3 |
758 | } |
759 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 6) => { |
760 | elf::R_SHARC_DATA6_V3 |
761 | } |
762 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 6) => { |
763 | elf::R_SHARC_DATA6_VISA_V3 |
764 | } |
765 | (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 7) => { |
766 | elf::R_SHARC_DATA7_VISA_V3 |
767 | } |
768 | (RelocationKind::Elf(x), _, _) => x, |
769 | _ => { |
770 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
771 | } |
772 | }, |
773 | Architecture::Sparc64 => match (reloc.kind, reloc.encoding, reloc.size) { |
774 | // TODO: use R_SPARC_32/R_SPARC_64 if aligned. |
775 | (RelocationKind::Absolute, _, 32) => elf::R_SPARC_UA32, |
776 | (RelocationKind::Absolute, _, 64) => elf::R_SPARC_UA64, |
777 | (RelocationKind::Elf(x), _, _) => x, |
778 | _ => { |
779 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
780 | } |
781 | }, |
782 | Architecture::Xtensa => match (reloc.kind, reloc.encoding, reloc.size) { |
783 | (RelocationKind::Absolute, _, 32) => elf::R_XTENSA_32, |
784 | (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { |
785 | elf::R_XTENSA_32_PCREL |
786 | } |
787 | (RelocationKind::Elf(x), _, _) => x, |
788 | _ => { |
789 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
790 | } |
791 | }, |
792 | _ => { |
793 | if let RelocationKind::Elf(x) = reloc.kind { |
794 | x |
795 | } else { |
796 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
797 | } |
798 | } |
799 | }; |
800 | let r_sym = symbol_offsets[reloc.symbol.0].index.0; |
801 | writer.write_relocation( |
802 | is_rela, |
803 | &Rel { |
804 | r_offset: reloc.offset, |
805 | r_sym, |
806 | r_type, |
807 | r_addend: reloc.addend, |
808 | }, |
809 | ); |
810 | } |
811 | } |
812 | } |
813 | |
814 | writer.write_shstrtab(); |
815 | |
816 | // Write section headers. |
817 | writer.write_null_section_header(); |
818 | |
819 | let symtab_index = writer.symtab_index(); |
820 | for (comdat, comdat_offset) in self.comdats.iter().zip(comdat_offsets.iter()) { |
821 | writer.write_comdat_section_header( |
822 | comdat_offset.str_id, |
823 | symtab_index, |
824 | symbol_offsets[comdat.symbol.0].index, |
825 | comdat_offset.offset, |
826 | comdat.sections.len(), |
827 | ); |
828 | } |
829 | for (index, section) in self.sections.iter().enumerate() { |
830 | let sh_type = match section.kind { |
831 | SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS, |
832 | SectionKind::Note => elf::SHT_NOTE, |
833 | SectionKind::Elf(sh_type) => sh_type, |
834 | _ => elf::SHT_PROGBITS, |
835 | }; |
836 | let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags { |
837 | sh_flags |
838 | } else { |
839 | match section.kind { |
840 | SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, |
841 | SectionKind::Data | SectionKind::ReadOnlyDataWithRel => { |
842 | elf::SHF_ALLOC | elf::SHF_WRITE |
843 | } |
844 | SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, |
845 | SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, |
846 | SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, |
847 | SectionKind::ReadOnlyData => elf::SHF_ALLOC, |
848 | SectionKind::ReadOnlyString => { |
849 | elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE |
850 | } |
851 | SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE, |
852 | SectionKind::Other |
853 | | SectionKind::Debug |
854 | | SectionKind::Metadata |
855 | | SectionKind::Linker |
856 | | SectionKind::Note |
857 | | SectionKind::Elf(_) => 0, |
858 | SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => { |
859 | return Err(Error(format!( |
860 | "unimplemented section ` {}` kind {:?}" , |
861 | section.name().unwrap_or("" ), |
862 | section.kind |
863 | ))); |
864 | } |
865 | } |
866 | .into() |
867 | }; |
868 | // TODO: not sure if this is correct, maybe user should determine this |
869 | let sh_entsize = match section.kind { |
870 | SectionKind::ReadOnlyString | SectionKind::OtherString => 1, |
871 | _ => 0, |
872 | }; |
873 | writer.write_section_header(&SectionHeader { |
874 | name: Some(section_offsets[index].str_id), |
875 | sh_type, |
876 | sh_flags, |
877 | sh_addr: 0, |
878 | sh_offset: section_offsets[index].offset as u64, |
879 | sh_size: section.size, |
880 | sh_link: 0, |
881 | sh_info: 0, |
882 | sh_addralign: section.align, |
883 | sh_entsize, |
884 | }); |
885 | |
886 | if !section.relocations.is_empty() { |
887 | writer.write_relocation_section_header( |
888 | section_offsets[index].reloc_str_id.unwrap(), |
889 | section_offsets[index].index, |
890 | symtab_index, |
891 | section_offsets[index].reloc_offset, |
892 | section.relocations.len(), |
893 | is_rela, |
894 | ); |
895 | } |
896 | } |
897 | |
898 | writer.write_symtab_section_header(symtab_num_local); |
899 | writer.write_symtab_shndx_section_header(); |
900 | writer.write_strtab_section_header(); |
901 | writer.write_shstrtab_section_header(); |
902 | |
903 | debug_assert_eq!(writer.reserved_len(), writer.len()); |
904 | |
905 | Ok(()) |
906 | } |
907 | } |
908 | |