1 use std::vec::Vec;
2 
3 use crate::elf;
4 use crate::write::elf::writer::*;
5 use crate::write::string::StringId;
6 use crate::write::*;
7 use crate::AddressSize;
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 impl<'a> Object<'a> {
elf_section_info( &self, section: StandardSection, ) -> (&'static [u8], &'static [u8], SectionKind)31     pub(crate) fn elf_section_info(
32         &self,
33         section: StandardSection,
34     ) -> (&'static [u8], &'static [u8], SectionKind) {
35         match section {
36             StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
37             StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
38             StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => {
39                 (&[], &b".rodata"[..], SectionKind::ReadOnlyData)
40             }
41             StandardSection::ReadOnlyDataWithRel => (&[], b".data.rel.ro", SectionKind::Data),
42             StandardSection::UninitializedData => {
43                 (&[], &b".bss"[..], SectionKind::UninitializedData)
44             }
45             StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls),
46             StandardSection::UninitializedTls => {
47                 (&[], &b".tbss"[..], SectionKind::UninitializedTls)
48             }
49             StandardSection::TlsVariables => {
50                 // Unsupported section.
51                 (&[], &[], SectionKind::TlsVariables)
52             }
53             StandardSection::Common => {
54                 // Unsupported section.
55                 (&[], &[], SectionKind::Common)
56             }
57         }
58     }
59 
elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8>60     pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
61         let mut name = section.to_vec();
62         name.push(b'.');
63         name.extend_from_slice(value);
64         name
65     }
66 
elf_has_relocation_addend(&self) -> Result<bool>67     fn elf_has_relocation_addend(&self) -> Result<bool> {
68         Ok(match self.architecture {
69             Architecture::Aarch64 => true,
70             Architecture::Arm => false,
71             Architecture::Avr => true,
72             Architecture::Bpf => false,
73             Architecture::I386 => false,
74             Architecture::X86_64 => true,
75             Architecture::X86_64_X32 => true,
76             Architecture::Hexagon => true,
77             Architecture::Mips => false,
78             Architecture::Mips64 => true,
79             Architecture::Msp430 => true,
80             Architecture::PowerPc => true,
81             Architecture::PowerPc64 => true,
82             Architecture::Riscv64 => true,
83             Architecture::Riscv32 => true,
84             Architecture::S390x => true,
85             Architecture::Sparc64 => true,
86             _ => {
87                 return Err(Error(format!(
88                     "unimplemented architecture {:?}",
89                     self.architecture
90                 )));
91             }
92         })
93     }
94 
elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64>95     pub(crate) fn elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64> {
96         // Return true if we should use a section symbol to avoid preemption.
97         fn want_section_symbol(relocation: &Relocation, symbol: &Symbol) -> bool {
98             if symbol.scope != SymbolScope::Dynamic {
99                 // Only dynamic symbols can be preemptible.
100                 return false;
101             }
102             match symbol.kind {
103                 SymbolKind::Text | SymbolKind::Data => {}
104                 _ => return false,
105             }
106             match relocation.kind {
107                 // Anything using GOT or PLT is preemptible.
108                 // We also require that `Other` relocations must already be correct.
109                 RelocationKind::Got
110                 | RelocationKind::GotRelative
111                 | RelocationKind::GotBaseRelative
112                 | RelocationKind::PltRelative
113                 | RelocationKind::Elf(_) => return false,
114                 // Absolute relocations are preemptible for non-local data.
115                 // TODO: not sure if this rule is exactly correct
116                 // This rule was added to handle global data references in debuginfo.
117                 // Maybe this should be a new relocation kind so that the caller can decide.
118                 RelocationKind::Absolute => {
119                     if symbol.kind == SymbolKind::Data {
120                         return false;
121                     }
122                 }
123                 _ => {}
124             }
125             true
126         }
127 
128         // Use section symbols for relocations where required to avoid preemption.
129         // Otherwise, the linker will fail with:
130         //     relocation R_X86_64_PC32 against symbol `SomeSymbolName' can not be used when
131         //     making a shared object; recompile with -fPIC
132         let symbol = &self.symbols[relocation.symbol.0];
133         if want_section_symbol(relocation, symbol) {
134             if let Some(section) = symbol.section.id() {
135                 relocation.addend += symbol.value as i64;
136                 relocation.symbol = self.section_symbol(section);
137             }
138         }
139 
140         // Determine whether the addend is stored in the relocation or the data.
141         if self.elf_has_relocation_addend()? {
142             Ok(0)
143         } else {
144             let constant = relocation.addend;
145             relocation.addend = 0;
146             Ok(constant)
147         }
148     }
149 
elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()>150     pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
151         // Create reloc section header names so we can reference them.
152         let is_rela = self.elf_has_relocation_addend()?;
153         let reloc_names: Vec<_> = self
154             .sections
155             .iter()
156             .map(|section| {
157                 let mut reloc_name = Vec::with_capacity(
158                     if is_rela { ".rela".len() } else { ".rel".len() } + section.name.len(),
159                 );
160                 if !section.relocations.is_empty() {
161                     reloc_name.extend_from_slice(if is_rela {
162                         &b".rela"[..]
163                     } else {
164                         &b".rel"[..]
165                     });
166                     reloc_name.extend_from_slice(&section.name);
167                 }
168                 reloc_name
169             })
170             .collect();
171 
172         // Start calculating offsets of everything.
173         let is_64 = match self.architecture.address_size().unwrap() {
174             AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false,
175             AddressSize::U64 => true,
176         };
177         let mut writer = Writer::new(self.endian, is_64, buffer);
178         writer.reserve_file_header();
179 
180         // Calculate size of section data.
181         let mut comdat_offsets = Vec::with_capacity(self.comdats.len());
182         for comdat in &self.comdats {
183             if comdat.kind != ComdatKind::Any {
184                 return Err(Error(format!(
185                     "unsupported COMDAT symbol `{}` kind {:?}",
186                     self.symbols[comdat.symbol.0].name().unwrap_or(""),
187                     comdat.kind
188                 )));
189             }
190 
191             writer.reserve_section_index();
192             let offset = writer.reserve_comdat(comdat.sections.len());
193             let str_id = writer.add_section_name(b".group");
194             comdat_offsets.push(ComdatOffsets { offset, str_id });
195         }
196         let mut section_offsets = Vec::with_capacity(self.sections.len());
197         for (section, reloc_name) in self.sections.iter().zip(reloc_names.iter()) {
198             let index = writer.reserve_section_index();
199             let offset = writer.reserve(section.data.len(), section.align as usize);
200             let str_id = writer.add_section_name(&section.name);
201             let mut reloc_str_id = None;
202             if !section.relocations.is_empty() {
203                 writer.reserve_section_index();
204                 reloc_str_id = Some(writer.add_section_name(reloc_name));
205             }
206             section_offsets.push(SectionOffsets {
207                 index,
208                 offset,
209                 str_id,
210                 // Relocation data is reserved later.
211                 reloc_offset: 0,
212                 reloc_str_id,
213             });
214         }
215 
216         // Calculate index of symbols and add symbol strings to strtab.
217         let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
218         // Local symbols must come before global.
219         for (index, symbol) in self.symbols.iter().enumerate() {
220             if symbol.is_local() {
221                 let section_index = symbol.section.id().map(|s| section_offsets[s.0].index);
222                 symbol_offsets[index].index = writer.reserve_symbol_index(section_index);
223             }
224         }
225         let symtab_num_local = writer.symbol_count();
226         for (index, symbol) in self.symbols.iter().enumerate() {
227             if !symbol.is_local() {
228                 let section_index = symbol.section.id().map(|s| section_offsets[s.0].index);
229                 symbol_offsets[index].index = writer.reserve_symbol_index(section_index);
230             }
231         }
232         for (index, symbol) in self.symbols.iter().enumerate() {
233             if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() {
234                 symbol_offsets[index].str_id = Some(writer.add_string(&symbol.name));
235             }
236         }
237 
238         // Calculate size of symbols.
239         writer.reserve_symtab_section_index();
240         writer.reserve_symtab();
241         if writer.symtab_shndx_needed() {
242             writer.reserve_symtab_shndx_section_index();
243         }
244         writer.reserve_symtab_shndx();
245         writer.reserve_strtab_section_index();
246         writer.reserve_strtab();
247 
248         // Calculate size of relocations.
249         for (index, section) in self.sections.iter().enumerate() {
250             let count = section.relocations.len();
251             if count != 0 {
252                 section_offsets[index].reloc_offset = writer.reserve_relocations(count, is_rela);
253             }
254         }
255 
256         // Calculate size of section headers.
257         writer.reserve_shstrtab_section_index();
258         writer.reserve_shstrtab();
259         writer.reserve_section_headers();
260 
261         // Start writing.
262         let e_type = elf::ET_REL;
263         let e_machine = match self.architecture {
264             Architecture::Aarch64 => elf::EM_AARCH64,
265             Architecture::Arm => elf::EM_ARM,
266             Architecture::Avr => elf::EM_AVR,
267             Architecture::Bpf => elf::EM_BPF,
268             Architecture::I386 => elf::EM_386,
269             Architecture::X86_64 => elf::EM_X86_64,
270             Architecture::X86_64_X32 => elf::EM_X86_64,
271             Architecture::Hexagon => elf::EM_HEXAGON,
272             Architecture::Mips => elf::EM_MIPS,
273             Architecture::Mips64 => elf::EM_MIPS,
274             Architecture::Msp430 => elf::EM_MSP430,
275             Architecture::PowerPc => elf::EM_PPC,
276             Architecture::PowerPc64 => elf::EM_PPC64,
277             Architecture::Riscv32 => elf::EM_RISCV,
278             Architecture::Riscv64 => elf::EM_RISCV,
279             Architecture::S390x => elf::EM_S390,
280             Architecture::Sparc64 => elf::EM_SPARCV9,
281             _ => {
282                 return Err(Error(format!(
283                     "unimplemented architecture {:?}",
284                     self.architecture
285                 )));
286             }
287         };
288         let e_flags = if let FileFlags::Elf { e_flags } = self.flags {
289             e_flags
290         } else {
291             0
292         };
293         writer.write_file_header(&FileHeader {
294             os_abi: elf::ELFOSABI_NONE,
295             abi_version: 0,
296             e_type,
297             e_machine,
298             e_entry: 0,
299             e_flags,
300         })?;
301 
302         // Write section data.
303         for comdat in &self.comdats {
304             writer.write_comdat_header();
305             for section in &comdat.sections {
306                 writer.write_comdat_entry(section_offsets[section.0].index);
307             }
308         }
309         for (index, section) in self.sections.iter().enumerate() {
310             let len = section.data.len();
311             if len != 0 {
312                 writer.write_align(section.align as usize);
313                 debug_assert_eq!(section_offsets[index].offset, writer.len());
314                 writer.write(&section.data);
315             }
316         }
317 
318         // Write symbols.
319         writer.write_null_symbol();
320         let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> {
321             let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags {
322                 st_info
323             } else {
324                 let st_type = match symbol.kind {
325                     SymbolKind::Null => elf::STT_NOTYPE,
326                     SymbolKind::Text => {
327                         if symbol.is_undefined() {
328                             elf::STT_NOTYPE
329                         } else {
330                             elf::STT_FUNC
331                         }
332                     }
333                     SymbolKind::Data => {
334                         if symbol.is_undefined() {
335                             elf::STT_NOTYPE
336                         } else if symbol.is_common() {
337                             elf::STT_COMMON
338                         } else {
339                             elf::STT_OBJECT
340                         }
341                     }
342                     SymbolKind::Section => elf::STT_SECTION,
343                     SymbolKind::File => elf::STT_FILE,
344                     SymbolKind::Tls => elf::STT_TLS,
345                     SymbolKind::Label => elf::STT_NOTYPE,
346                     SymbolKind::Unknown => {
347                         if symbol.is_undefined() {
348                             elf::STT_NOTYPE
349                         } else {
350                             return Err(Error(format!(
351                                 "unimplemented symbol `{}` kind {:?}",
352                                 symbol.name().unwrap_or(""),
353                                 symbol.kind
354                             )));
355                         }
356                     }
357                 };
358                 let st_bind = if symbol.weak {
359                     elf::STB_WEAK
360                 } else if symbol.is_undefined() {
361                     elf::STB_GLOBAL
362                 } else if symbol.is_local() {
363                     elf::STB_LOCAL
364                 } else {
365                     elf::STB_GLOBAL
366                 };
367                 (st_bind << 4) + st_type
368             };
369             let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags {
370                 st_other
371             } else if symbol.scope == SymbolScope::Linkage {
372                 elf::STV_HIDDEN
373             } else {
374                 elf::STV_DEFAULT
375             };
376             let (st_shndx, section) = match symbol.section {
377                 SymbolSection::None => {
378                     debug_assert_eq!(symbol.kind, SymbolKind::File);
379                     (elf::SHN_ABS, None)
380                 }
381                 SymbolSection::Undefined => (elf::SHN_UNDEF, None),
382                 SymbolSection::Absolute => (elf::SHN_ABS, None),
383                 SymbolSection::Common => (elf::SHN_COMMON, None),
384                 SymbolSection::Section(id) => (0, Some(section_offsets[id.0].index)),
385             };
386             writer.write_symbol(&Sym {
387                 name: symbol_offsets[index].str_id,
388                 section,
389                 st_info,
390                 st_other,
391                 st_shndx,
392                 st_value: symbol.value,
393                 st_size: symbol.size,
394             });
395             Ok(())
396         };
397         for (index, symbol) in self.symbols.iter().enumerate() {
398             if symbol.is_local() {
399                 write_symbol(index, symbol)?;
400             }
401         }
402         for (index, symbol) in self.symbols.iter().enumerate() {
403             if !symbol.is_local() {
404                 write_symbol(index, symbol)?;
405             }
406         }
407         writer.write_symtab_shndx();
408         writer.write_strtab();
409 
410         // Write relocations.
411         for (index, section) in self.sections.iter().enumerate() {
412             if !section.relocations.is_empty() {
413                 writer.write_align_relocation();
414                 debug_assert_eq!(section_offsets[index].reloc_offset, writer.len());
415                 for reloc in &section.relocations {
416                     let r_type = match self.architecture {
417                         Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) {
418                             (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
419                                 elf::R_AARCH64_ABS64
420                             }
421                             (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
422                                 elf::R_AARCH64_ABS32
423                             }
424                             (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
425                                 elf::R_AARCH64_ABS16
426                             }
427                             (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
428                                 elf::R_AARCH64_PREL64
429                             }
430                             (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
431                                 elf::R_AARCH64_PREL32
432                             }
433                             (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
434                                 elf::R_AARCH64_PREL16
435                             }
436                             (RelocationKind::Relative, RelocationEncoding::AArch64Call, 26)
437                             | (RelocationKind::PltRelative, RelocationEncoding::AArch64Call, 26) => {
438                                 elf::R_AARCH64_CALL26
439                             }
440                             (RelocationKind::Elf(x), _, _) => x,
441                             _ => {
442                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
443                             }
444                         },
445                         Architecture::Arm => match (reloc.kind, reloc.encoding, reloc.size) {
446                             (RelocationKind::Absolute, _, 32) => elf::R_ARM_ABS32,
447                             (RelocationKind::Elf(x), _, _) => x,
448                             _ => {
449                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
450                             }
451                         },
452                         Architecture::Avr => match (reloc.kind, reloc.encoding, reloc.size) {
453                             (RelocationKind::Absolute, _, 32) => elf::R_AVR_32,
454                             (RelocationKind::Absolute, _, 16) => elf::R_AVR_16,
455                             (RelocationKind::Elf(x), _, _) => x,
456                             _ => {
457                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
458                             }
459                         },
460                         Architecture::Bpf => match (reloc.kind, reloc.encoding, reloc.size) {
461                             (RelocationKind::Absolute, _, 64) => elf::R_BPF_64_64,
462                             (RelocationKind::Absolute, _, 32) => elf::R_BPF_64_32,
463                             (RelocationKind::Elf(x), _, _) => x,
464                             _ => {
465                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
466                             }
467                         },
468                         Architecture::I386 => match (reloc.kind, reloc.size) {
469                             (RelocationKind::Absolute, 32) => elf::R_386_32,
470                             (RelocationKind::Relative, 32) => elf::R_386_PC32,
471                             (RelocationKind::Got, 32) => elf::R_386_GOT32,
472                             (RelocationKind::PltRelative, 32) => elf::R_386_PLT32,
473                             (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF,
474                             (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC,
475                             (RelocationKind::Absolute, 16) => elf::R_386_16,
476                             (RelocationKind::Relative, 16) => elf::R_386_PC16,
477                             (RelocationKind::Absolute, 8) => elf::R_386_8,
478                             (RelocationKind::Relative, 8) => elf::R_386_PC8,
479                             (RelocationKind::Elf(x), _) => x,
480                             _ => {
481                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
482                             }
483                         },
484                         Architecture::X86_64 | Architecture::X86_64_X32 => {
485                             match (reloc.kind, reloc.encoding, reloc.size) {
486                                 (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
487                                     elf::R_X86_64_64
488                                 }
489                                 (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32,
490                                 (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32,
491                                 (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32,
492                                 (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL,
493                                 (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
494                                     elf::R_X86_64_32
495                                 }
496                                 (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => {
497                                     elf::R_X86_64_32S
498                                 }
499                                 (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16,
500                                 (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16,
501                                 (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8,
502                                 (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8,
503                                 (RelocationKind::Elf(x), _, _) => x,
504                                 _ => {
505                                     return Err(Error(format!(
506                                         "unimplemented relocation {:?}",
507                                         reloc
508                                     )));
509                                 }
510                             }
511                         }
512                         Architecture::Hexagon => match (reloc.kind, reloc.encoding, reloc.size) {
513                             (RelocationKind::Absolute, _, 32) => elf::R_HEX_32,
514                             (RelocationKind::Elf(x), _, _) => x,
515                             _ => {
516                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
517                             }
518                         },
519                         Architecture::Mips | Architecture::Mips64 => {
520                             match (reloc.kind, reloc.encoding, reloc.size) {
521                                 (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16,
522                                 (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32,
523                                 (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64,
524                                 (RelocationKind::Elf(x), _, _) => x,
525                                 _ => {
526                                     return Err(Error(format!(
527                                         "unimplemented relocation {:?}",
528                                         reloc
529                                     )));
530                                 }
531                             }
532                         }
533                         Architecture::Msp430 => match (reloc.kind, reloc.encoding, reloc.size) {
534                             (RelocationKind::Absolute, _, 32) => elf::R_MSP430_32,
535                             (RelocationKind::Absolute, _, 16) => elf::R_MSP430_16_BYTE,
536                             (RelocationKind::Elf(x), _, _) => x,
537                             _ => {
538                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
539                             }
540                         },
541                         Architecture::PowerPc => match (reloc.kind, reloc.encoding, reloc.size) {
542                             (RelocationKind::Absolute, _, 32) => elf::R_PPC_ADDR32,
543                             (RelocationKind::Elf(x), _, _) => x,
544                             _ => {
545                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
546                             }
547                         },
548                         Architecture::PowerPc64 => match (reloc.kind, reloc.encoding, reloc.size) {
549                             (RelocationKind::Absolute, _, 32) => elf::R_PPC64_ADDR32,
550                             (RelocationKind::Absolute, _, 64) => elf::R_PPC64_ADDR64,
551                             (RelocationKind::Elf(x), _, _) => x,
552                             _ => {
553                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
554                             }
555                         },
556                         Architecture::Riscv32 | Architecture::Riscv64 => {
557                             match (reloc.kind, reloc.encoding, reloc.size) {
558                                 (RelocationKind::Absolute, _, 32) => elf::R_RISCV_32,
559                                 (RelocationKind::Absolute, _, 64) => elf::R_RISCV_64,
560                                 (RelocationKind::Elf(x), _, _) => x,
561                                 _ => {
562                                     return Err(Error(format!(
563                                         "unimplemented relocation {:?}",
564                                         reloc
565                                     )));
566                                 }
567                             }
568                         }
569                         Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) {
570                             (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => {
571                                 elf::R_390_8
572                             }
573                             (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
574                                 elf::R_390_16
575                             }
576                             (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
577                                 elf::R_390_32
578                             }
579                             (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
580                                 elf::R_390_64
581                             }
582                             (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
583                                 elf::R_390_PC16
584                             }
585                             (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
586                                 elf::R_390_PC32
587                             }
588                             (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
589                                 elf::R_390_PC64
590                             }
591                             (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => {
592                                 elf::R_390_PC16DBL
593                             }
594                             (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => {
595                                 elf::R_390_PC32DBL
596                             }
597                             (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => {
598                                 elf::R_390_PLT16DBL
599                             }
600                             (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => {
601                                 elf::R_390_PLT32DBL
602                             }
603                             (RelocationKind::Got, RelocationEncoding::Generic, 16) => {
604                                 elf::R_390_GOT16
605                             }
606                             (RelocationKind::Got, RelocationEncoding::Generic, 32) => {
607                                 elf::R_390_GOT32
608                             }
609                             (RelocationKind::Got, RelocationEncoding::Generic, 64) => {
610                                 elf::R_390_GOT64
611                             }
612                             (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => {
613                                 elf::R_390_GOTENT
614                             }
615                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => {
616                                 elf::R_390_GOTOFF16
617                             }
618                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => {
619                                 elf::R_390_GOTOFF32
620                             }
621                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => {
622                                 elf::R_390_GOTOFF64
623                             }
624                             (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => {
625                                 elf::R_390_GOTPC
626                             }
627                             (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => {
628                                 elf::R_390_GOTPCDBL
629                             }
630                             (RelocationKind::Elf(x), _, _) => x,
631                             _ => {
632                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
633                             }
634                         },
635                         Architecture::Sparc64 => match (reloc.kind, reloc.encoding, reloc.size) {
636                             // TODO: use R_SPARC_32/R_SPARC_64 if aligned.
637                             (RelocationKind::Absolute, _, 32) => elf::R_SPARC_UA32,
638                             (RelocationKind::Absolute, _, 64) => elf::R_SPARC_UA64,
639                             (RelocationKind::Elf(x), _, _) => x,
640                             _ => {
641                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
642                             }
643                         },
644                         _ => {
645                             if let RelocationKind::Elf(x) = reloc.kind {
646                                 x
647                             } else {
648                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
649                             }
650                         }
651                     };
652                     let r_sym = symbol_offsets[reloc.symbol.0].index.0;
653                     writer.write_relocation(
654                         is_rela,
655                         &Rel {
656                             r_offset: reloc.offset,
657                             r_sym,
658                             r_type,
659                             r_addend: reloc.addend,
660                         },
661                     );
662                 }
663             }
664         }
665 
666         writer.write_shstrtab();
667 
668         // Write section headers.
669         writer.write_null_section_header();
670 
671         let symtab_index = writer.symtab_index();
672         for (comdat, comdat_offset) in self.comdats.iter().zip(comdat_offsets.iter()) {
673             writer.write_comdat_section_header(
674                 comdat_offset.str_id,
675                 symtab_index,
676                 symbol_offsets[comdat.symbol.0].index,
677                 comdat_offset.offset,
678                 comdat.sections.len(),
679             );
680         }
681         for (index, section) in self.sections.iter().enumerate() {
682             let sh_type = match section.kind {
683                 SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS,
684                 SectionKind::Note => elf::SHT_NOTE,
685                 SectionKind::Elf(sh_type) => sh_type,
686                 _ => elf::SHT_PROGBITS,
687             };
688             let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags {
689                 sh_flags
690             } else {
691                 match section.kind {
692                     SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR,
693                     SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE,
694                     SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
695                     SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE,
696                     SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
697                     SectionKind::ReadOnlyData => elf::SHF_ALLOC,
698                     SectionKind::ReadOnlyString => {
699                         elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE
700                     }
701                     SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE,
702                     SectionKind::Other
703                     | SectionKind::Debug
704                     | SectionKind::Metadata
705                     | SectionKind::Linker
706                     | SectionKind::Note
707                     | SectionKind::Elf(_) => 0,
708                     SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => {
709                         return Err(Error(format!(
710                             "unimplemented section `{}` kind {:?}",
711                             section.name().unwrap_or(""),
712                             section.kind
713                         )));
714                     }
715                 }
716                 .into()
717             };
718             // TODO: not sure if this is correct, maybe user should determine this
719             let sh_entsize = match section.kind {
720                 SectionKind::ReadOnlyString | SectionKind::OtherString => 1,
721                 _ => 0,
722             };
723             writer.write_section_header(&SectionHeader {
724                 name: Some(section_offsets[index].str_id),
725                 sh_type,
726                 sh_flags,
727                 sh_addr: 0,
728                 sh_offset: section_offsets[index].offset as u64,
729                 sh_size: section.size,
730                 sh_link: 0,
731                 sh_info: 0,
732                 sh_addralign: section.align,
733                 sh_entsize,
734             });
735 
736             if !section.relocations.is_empty() {
737                 writer.write_relocation_section_header(
738                     section_offsets[index].reloc_str_id.unwrap(),
739                     section_offsets[index].index,
740                     symtab_index,
741                     section_offsets[index].reloc_offset,
742                     section.relocations.len(),
743                     is_rela,
744                 );
745             }
746         }
747 
748         writer.write_symtab_section_header(symtab_num_local);
749         writer.write_symtab_shndx_section_header();
750         writer.write_strtab_section_header();
751         writer.write_shstrtab_section_header();
752 
753         debug_assert_eq!(writer.reserved_len(), writer.len());
754 
755         Ok(())
756     }
757 }
758