1 use std::mem;
2 use std::vec::Vec;
3 
4 use crate::elf;
5 use crate::endian::*;
6 use crate::pod::{bytes_of, BytesMut, WritableBuffer};
7 use crate::write::string::*;
8 use crate::write::util::*;
9 use crate::write::*;
10 
11 #[derive(Default, Clone, Copy)]
12 struct ComdatOffsets {
13     offset: usize,
14     str_id: Option<StringId>,
15     len: usize,
16 }
17 
18 #[derive(Default, Clone, Copy)]
19 struct SectionOffsets {
20     index: usize,
21     offset: usize,
22     str_id: Option<StringId>,
23     reloc_index: usize,
24     reloc_offset: usize,
25     reloc_len: usize,
26     reloc_str_id: Option<StringId>,
27 }
28 
29 #[derive(Default, Clone, Copy)]
30 struct SymbolOffsets {
31     index: usize,
32     str_id: Option<StringId>,
33 }
34 
35 impl Object {
elf_section_info( &self, section: StandardSection, ) -> (&'static [u8], &'static [u8], SectionKind)36     pub(crate) fn elf_section_info(
37         &self,
38         section: StandardSection,
39     ) -> (&'static [u8], &'static [u8], SectionKind) {
40         match section {
41             StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
42             StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
43             StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => {
44                 (&[], &b".rodata"[..], SectionKind::ReadOnlyData)
45             }
46             StandardSection::ReadOnlyDataWithRel => (&[], b".data.rel.ro", SectionKind::Data),
47             StandardSection::UninitializedData => {
48                 (&[], &b".bss"[..], SectionKind::UninitializedData)
49             }
50             StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls),
51             StandardSection::UninitializedTls => {
52                 (&[], &b".tbss"[..], SectionKind::UninitializedTls)
53             }
54             StandardSection::TlsVariables => {
55                 // Unsupported section.
56                 (&[], &[], SectionKind::TlsVariables)
57             }
58             StandardSection::Common => {
59                 // Unsupported section.
60                 (&[], &[], SectionKind::Common)
61             }
62         }
63     }
64 
elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8>65     pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
66         let mut name = section.to_vec();
67         name.push(b'.');
68         name.extend(value);
69         name
70     }
71 
elf_has_relocation_addend(&self) -> Result<bool>72     fn elf_has_relocation_addend(&self) -> Result<bool> {
73         Ok(match self.architecture {
74             Architecture::Arm => false,
75             Architecture::Aarch64 => true,
76             Architecture::I386 => false,
77             Architecture::X86_64 => true,
78             Architecture::S390x => true,
79             Architecture::Mips => false,
80             _ => {
81                 return Err(Error(format!(
82                     "unimplemented architecture {:?}",
83                     self.architecture
84                 )));
85             }
86         })
87     }
88 
elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64>89     pub(crate) fn elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64> {
90         // Return true if we should use a section symbol to avoid preemption.
91         fn want_section_symbol(relocation: &Relocation, symbol: &Symbol) -> bool {
92             if symbol.scope != SymbolScope::Dynamic {
93                 // Only dynamic symbols can be preemptible.
94                 return false;
95             }
96             match symbol.kind {
97                 SymbolKind::Text | SymbolKind::Data => {}
98                 _ => return false,
99             }
100             match relocation.kind {
101                 // Anything using GOT or PLT is preemptible.
102                 // We also require that `Other` relocations must already be correct.
103                 RelocationKind::Got
104                 | RelocationKind::GotRelative
105                 | RelocationKind::GotBaseRelative
106                 | RelocationKind::PltRelative
107                 | RelocationKind::Elf(_) => return false,
108                 // Absolute relocations are preemptible for non-local data.
109                 // TODO: not sure if this rule is exactly correct
110                 // This rule was added to handle global data references in debuginfo.
111                 // Maybe this should be a new relocation kind so that the caller can decide.
112                 RelocationKind::Absolute => {
113                     if symbol.kind == SymbolKind::Data {
114                         return false;
115                     }
116                 }
117                 _ => {}
118             }
119             true
120         }
121 
122         // Use section symbols for relocations where required to avoid preemption.
123         // Otherwise, the linker will fail with:
124         //     relocation R_X86_64_PC32 against symbol `SomeSymbolName' can not be used when
125         //     making a shared object; recompile with -fPIC
126         let symbol = &self.symbols[relocation.symbol.0];
127         if want_section_symbol(relocation, symbol) {
128             if let Some(section) = symbol.section.id() {
129                 relocation.addend += symbol.value as i64;
130                 relocation.symbol = self.section_symbol(section);
131             }
132         }
133 
134         // Determine whether the addend is stored in the relocation or the data.
135         if self.elf_has_relocation_addend()? {
136             Ok(0)
137         } else {
138             let constant = relocation.addend;
139             relocation.addend = 0;
140             Ok(constant)
141         }
142     }
143 
elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()>144     pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
145         let address_size = self.architecture.address_size().unwrap();
146         let endian = self.endian;
147         let elf32 = Elf32 { endian };
148         let elf64 = Elf64 { endian };
149         let elf: &dyn Elf = match address_size {
150             AddressSize::U32 => &elf32,
151             AddressSize::U64 => &elf64,
152         };
153         let pointer_align = address_size.bytes() as usize;
154 
155         // Calculate offsets of everything.
156         let mut offset = 0;
157 
158         // ELF header.
159         let e_ehsize = elf.file_header_size();
160         offset += e_ehsize;
161 
162         // Create reloc section header names.
163         let is_rela = self.elf_has_relocation_addend()?;
164         let reloc_names: Vec<_> = self
165             .sections
166             .iter()
167             .map(|section| {
168                 let mut reloc_name = Vec::new();
169                 if !section.relocations.is_empty() {
170                     reloc_name.extend_from_slice(if is_rela {
171                         &b".rela"[..]
172                     } else {
173                         &b".rel"[..]
174                     });
175                     reloc_name.extend_from_slice(&section.name);
176                 }
177                 reloc_name
178             })
179             .collect();
180 
181         // Calculate size of section data.
182         let mut shstrtab = StringTable::default();
183         let mut comdat_offsets = vec![ComdatOffsets::default(); self.comdats.len()];
184         let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
185         // Null section.
186         let mut section_num = 1;
187         for (index, comdat) in self.comdats.iter().enumerate() {
188             if comdat.kind != ComdatKind::Any {
189                 return Err(Error(format!(
190                     "unsupported COMDAT symbol `{}` kind {:?}",
191                     self.symbols[comdat.symbol.0].name().unwrap_or(""),
192                     comdat.kind
193                 )));
194             }
195 
196             comdat_offsets[index].str_id = Some(shstrtab.add(b".group"));
197             section_num += 1;
198             offset = align(offset, 4);
199             comdat_offsets[index].offset = offset;
200             let len = (comdat.sections.len() + 1) * 4;
201             comdat_offsets[index].len = len;
202             offset += len;
203         }
204         for (index, section) in self.sections.iter().enumerate() {
205             section_offsets[index].str_id = Some(shstrtab.add(&section.name));
206             section_offsets[index].index = section_num;
207             section_num += 1;
208 
209             let len = section.data.len();
210             if len != 0 {
211                 offset = align(offset, section.align as usize);
212                 section_offsets[index].offset = offset;
213                 offset += len;
214             } else {
215                 section_offsets[index].offset = offset;
216             }
217 
218             if !section.relocations.is_empty() {
219                 section_offsets[index].reloc_str_id = Some(shstrtab.add(&reloc_names[index]));
220                 section_offsets[index].reloc_index = section_num;
221                 section_num += 1;
222             }
223         }
224 
225         // Calculate index of symbols and add symbol strings to strtab.
226         let mut strtab = StringTable::default();
227         let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
228         // Null symbol.
229         let mut symtab_count = 1;
230         // Local symbols must come before global.
231         for (index, symbol) in self.symbols.iter().enumerate() {
232             if symbol.is_local() {
233                 symbol_offsets[index].index = symtab_count;
234                 symtab_count += 1;
235             }
236         }
237         let symtab_count_local = symtab_count;
238         for (index, symbol) in self.symbols.iter().enumerate() {
239             if !symbol.is_local() {
240                 symbol_offsets[index].index = symtab_count;
241                 symtab_count += 1;
242             }
243         }
244         for (index, symbol) in self.symbols.iter().enumerate() {
245             if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() {
246                 symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
247             }
248         }
249 
250         // Calculate size of symtab.
251         let symtab_str_id = shstrtab.add(&b".symtab"[..]);
252         offset = align(offset, pointer_align);
253         let symtab_offset = offset;
254         let symtab_len = symtab_count * elf.symbol_size();
255         offset += symtab_len;
256         let symtab_index = section_num;
257         section_num += 1;
258 
259         // Calculate size of symtab_shndx.
260         let mut need_symtab_shndx = false;
261         for symbol in &self.symbols {
262             let index = symbol
263                 .section
264                 .id()
265                 .map(|s| section_offsets[s.0].index)
266                 .unwrap_or(0);
267             if index >= elf::SHN_LORESERVE as usize {
268                 need_symtab_shndx = true;
269                 break;
270             }
271         }
272         let symtab_shndx_offset = offset;
273         let mut symtab_shndx_str_id = None;
274         let mut symtab_shndx_len = 0;
275         if need_symtab_shndx {
276             symtab_shndx_str_id = Some(shstrtab.add(&b".symtab_shndx"[..]));
277             symtab_shndx_len = symtab_count * 4;
278             offset += symtab_shndx_len;
279             section_num += 1;
280         }
281 
282         // Calculate size of strtab.
283         let strtab_str_id = shstrtab.add(&b".strtab"[..]);
284         let strtab_offset = offset;
285         let mut strtab_data = Vec::new();
286         // Null name.
287         strtab_data.push(0);
288         strtab.write(1, &mut strtab_data);
289         offset += strtab_data.len();
290         let strtab_index = section_num;
291         section_num += 1;
292 
293         // Calculate size of relocations.
294         for (index, section) in self.sections.iter().enumerate() {
295             let count = section.relocations.len();
296             if count != 0 {
297                 offset = align(offset, pointer_align);
298                 section_offsets[index].reloc_offset = offset;
299                 let len = count * elf.rel_size(is_rela);
300                 section_offsets[index].reloc_len = len;
301                 offset += len;
302             }
303         }
304 
305         // Calculate size of shstrtab.
306         let shstrtab_str_id = shstrtab.add(&b".shstrtab"[..]);
307         let shstrtab_offset = offset;
308         let mut shstrtab_data = Vec::new();
309         // Null section name.
310         shstrtab_data.push(0);
311         shstrtab.write(1, &mut shstrtab_data);
312         offset += shstrtab_data.len();
313         let shstrtab_index = section_num;
314         section_num += 1;
315 
316         // Calculate size of section headers.
317         offset = align(offset, pointer_align);
318         let e_shoff = offset;
319         let e_shentsize = elf.section_header_size();
320         offset += section_num * e_shentsize;
321 
322         // Start writing.
323         buffer
324             .reserve(offset)
325             .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
326 
327         // Write file header.
328         let e_ident = elf::Ident {
329             magic: elf::ELFMAG,
330             class: match address_size {
331                 AddressSize::U32 => elf::ELFCLASS32,
332                 AddressSize::U64 => elf::ELFCLASS64,
333             },
334             data: if endian.is_little_endian() {
335                 elf::ELFDATA2LSB
336             } else {
337                 elf::ELFDATA2MSB
338             },
339             version: elf::EV_CURRENT,
340             os_abi: elf::ELFOSABI_NONE,
341             abi_version: 0,
342             padding: [0; 7],
343         };
344         let e_type = elf::ET_REL;
345         let e_machine = match self.architecture {
346             Architecture::Arm => elf::EM_ARM,
347             Architecture::Aarch64 => elf::EM_AARCH64,
348             Architecture::I386 => elf::EM_386,
349             Architecture::X86_64 => elf::EM_X86_64,
350             Architecture::S390x => elf::EM_S390,
351             Architecture::Mips => elf::EM_MIPS,
352             _ => {
353                 return Err(Error(format!(
354                     "unimplemented architecture {:?}",
355                     self.architecture
356                 )));
357             }
358         };
359         let e_flags = if let FileFlags::Elf { e_flags } = self.flags {
360             e_flags
361         } else {
362             0
363         };
364         let e_shnum = if section_num >= elf::SHN_LORESERVE as usize {
365             0
366         } else {
367             section_num as u16
368         };
369         let e_shstrndx = if shstrtab_index >= elf::SHN_LORESERVE as usize {
370             elf::SHN_XINDEX
371         } else {
372             shstrtab_index as u16
373         };
374 
375         elf.write_file_header(
376             buffer,
377             FileHeader {
378                 e_ident,
379                 e_type,
380                 e_machine,
381                 e_version: elf::EV_CURRENT.into(),
382                 e_entry: 0,
383                 e_phoff: 0,
384                 e_shoff: e_shoff as u64,
385                 e_flags,
386                 e_ehsize: e_ehsize as u16,
387                 e_phentsize: 0,
388                 e_phnum: 0,
389                 e_shentsize: e_shentsize as u16,
390                 e_shnum,
391                 e_shstrndx,
392             },
393         );
394 
395         // Write section data.
396         for (index, comdat) in self.comdats.iter().enumerate() {
397             let mut data = BytesMut::new();
398             data.write(&U32::new(endian, elf::GRP_COMDAT));
399             for section in &comdat.sections {
400                 data.write(&U32::new(endian, section_offsets[section.0].index as u32));
401             }
402 
403             write_align(buffer, 4);
404             debug_assert_eq!(comdat_offsets[index].offset, buffer.len());
405             debug_assert_eq!(comdat_offsets[index].len, data.len());
406             buffer.extend(data.as_slice());
407         }
408         for (index, section) in self.sections.iter().enumerate() {
409             let len = section.data.len();
410             if len != 0 {
411                 write_align(buffer, section.align as usize);
412                 debug_assert_eq!(section_offsets[index].offset, buffer.len());
413                 buffer.extend(section.data.as_slice());
414             }
415         }
416 
417         // Write symbols.
418         write_align(buffer, pointer_align);
419         debug_assert_eq!(symtab_offset, buffer.len());
420         elf.write_symbol(
421             buffer,
422             Sym {
423                 st_name: 0,
424                 st_info: 0,
425                 st_other: 0,
426                 st_shndx: 0,
427                 st_value: 0,
428                 st_size: 0,
429             },
430         );
431         let mut symtab_shndx = BytesMut::new();
432         if need_symtab_shndx {
433             symtab_shndx.write(&U32::new(endian, 0));
434         }
435         let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> {
436             let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags {
437                 st_info
438             } else {
439                 let st_type = match symbol.kind {
440                     SymbolKind::Null => elf::STT_NOTYPE,
441                     SymbolKind::Text => {
442                         if symbol.is_undefined() {
443                             elf::STT_NOTYPE
444                         } else {
445                             elf::STT_FUNC
446                         }
447                     }
448                     SymbolKind::Data => {
449                         if symbol.is_undefined() {
450                             elf::STT_NOTYPE
451                         } else if symbol.is_common() {
452                             elf::STT_COMMON
453                         } else {
454                             elf::STT_OBJECT
455                         }
456                     }
457                     SymbolKind::Section => elf::STT_SECTION,
458                     SymbolKind::File => elf::STT_FILE,
459                     SymbolKind::Tls => elf::STT_TLS,
460                     SymbolKind::Label => elf::STT_NOTYPE,
461                     SymbolKind::Unknown => {
462                         if symbol.is_undefined() {
463                             elf::STT_NOTYPE
464                         } else {
465                             return Err(Error(format!(
466                                 "unimplemented symbol `{}` kind {:?}",
467                                 symbol.name().unwrap_or(""),
468                                 symbol.kind
469                             )));
470                         }
471                     }
472                 };
473                 let st_bind = if symbol.weak {
474                     elf::STB_WEAK
475                 } else if symbol.is_undefined() {
476                     elf::STB_GLOBAL
477                 } else if symbol.is_local() {
478                     elf::STB_LOCAL
479                 } else {
480                     elf::STB_GLOBAL
481                 };
482                 (st_bind << 4) + st_type
483             };
484             let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags {
485                 st_other
486             } else if symbol.scope == SymbolScope::Linkage {
487                 elf::STV_HIDDEN
488             } else {
489                 elf::STV_DEFAULT
490             };
491             let (st_shndx, xindex) = match symbol.section {
492                 SymbolSection::None => {
493                     debug_assert_eq!(symbol.kind, SymbolKind::File);
494                     (elf::SHN_ABS, 0)
495                 }
496                 SymbolSection::Undefined => (elf::SHN_UNDEF, 0),
497                 SymbolSection::Absolute => (elf::SHN_ABS, 0),
498                 SymbolSection::Common => (elf::SHN_COMMON, 0),
499                 SymbolSection::Section(id) => {
500                     let index = section_offsets[id.0].index as u32;
501                     (
502                         if index >= elf::SHN_LORESERVE as u32 {
503                             elf::SHN_XINDEX
504                         } else {
505                             index as u16
506                         },
507                         index,
508                     )
509                 }
510             };
511             let st_name = symbol_offsets[index]
512                 .str_id
513                 .map(|id| strtab.get_offset(id))
514                 .unwrap_or(0) as u32;
515             elf.write_symbol(
516                 buffer,
517                 Sym {
518                     st_name,
519                     st_info,
520                     st_other,
521                     st_shndx,
522                     st_value: symbol.value,
523                     st_size: symbol.size,
524                 },
525             );
526             if need_symtab_shndx {
527                 symtab_shndx.write(&U32::new(endian, xindex));
528             }
529             Ok(())
530         };
531         for (index, symbol) in self.symbols.iter().enumerate() {
532             if symbol.is_local() {
533                 write_symbol(index, symbol)?;
534             }
535         }
536         for (index, symbol) in self.symbols.iter().enumerate() {
537             if !symbol.is_local() {
538                 write_symbol(index, symbol)?;
539             }
540         }
541         if need_symtab_shndx {
542             debug_assert_eq!(symtab_shndx_offset, buffer.len());
543             debug_assert_eq!(symtab_shndx_len, symtab_shndx.len());
544             buffer.extend(symtab_shndx.as_slice());
545         }
546 
547         // Write strtab section.
548         debug_assert_eq!(strtab_offset, buffer.len());
549         buffer.extend(&strtab_data);
550 
551         // Write relocations.
552         for (index, section) in self.sections.iter().enumerate() {
553             if !section.relocations.is_empty() {
554                 write_align(buffer, pointer_align);
555                 debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
556                 for reloc in &section.relocations {
557                     let r_type = match self.architecture {
558                         Architecture::I386 => match (reloc.kind, reloc.size) {
559                             (RelocationKind::Absolute, 32) => elf::R_386_32,
560                             (RelocationKind::Relative, 32) => elf::R_386_PC32,
561                             (RelocationKind::Got, 32) => elf::R_386_GOT32,
562                             (RelocationKind::PltRelative, 32) => elf::R_386_PLT32,
563                             (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF,
564                             (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC,
565                             (RelocationKind::Absolute, 16) => elf::R_386_16,
566                             (RelocationKind::Relative, 16) => elf::R_386_PC16,
567                             (RelocationKind::Absolute, 8) => elf::R_386_8,
568                             (RelocationKind::Relative, 8) => elf::R_386_PC8,
569                             (RelocationKind::Elf(x), _) => x,
570                             _ => {
571                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
572                             }
573                         },
574                         Architecture::X86_64 => match (reloc.kind, reloc.encoding, reloc.size) {
575                             (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
576                                 elf::R_X86_64_64
577                             }
578                             (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32,
579                             (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32,
580                             (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32,
581                             (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL,
582                             (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
583                                 elf::R_X86_64_32
584                             }
585                             (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => {
586                                 elf::R_X86_64_32S
587                             }
588                             (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16,
589                             (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16,
590                             (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8,
591                             (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8,
592                             (RelocationKind::Elf(x), _, _) => x,
593                             _ => {
594                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
595                             }
596                         },
597                         Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) {
598                             (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
599                                 elf::R_AARCH64_ABS32
600                             }
601                             (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
602                                 elf::R_AARCH64_ABS64
603                             }
604                             (RelocationKind::Elf(x), _, _) => x,
605                             _ => {
606                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
607                             }
608                         },
609                         Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) {
610                             (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => {
611                                 elf::R_390_8
612                             }
613                             (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => {
614                                 elf::R_390_16
615                             }
616                             (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => {
617                                 elf::R_390_32
618                             }
619                             (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => {
620                                 elf::R_390_64
621                             }
622                             (RelocationKind::Relative, RelocationEncoding::Generic, 16) => {
623                                 elf::R_390_PC16
624                             }
625                             (RelocationKind::Relative, RelocationEncoding::Generic, 32) => {
626                                 elf::R_390_PC32
627                             }
628                             (RelocationKind::Relative, RelocationEncoding::Generic, 64) => {
629                                 elf::R_390_PC64
630                             }
631                             (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => {
632                                 elf::R_390_PC16DBL
633                             }
634                             (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => {
635                                 elf::R_390_PC32DBL
636                             }
637                             (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => {
638                                 elf::R_390_PLT16DBL
639                             }
640                             (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => {
641                                 elf::R_390_PLT32DBL
642                             }
643                             (RelocationKind::Got, RelocationEncoding::Generic, 16) => {
644                                 elf::R_390_GOT16
645                             }
646                             (RelocationKind::Got, RelocationEncoding::Generic, 32) => {
647                                 elf::R_390_GOT32
648                             }
649                             (RelocationKind::Got, RelocationEncoding::Generic, 64) => {
650                                 elf::R_390_GOT64
651                             }
652                             (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => {
653                                 elf::R_390_GOTENT
654                             }
655                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => {
656                                 elf::R_390_GOTOFF16
657                             }
658                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => {
659                                 elf::R_390_GOTOFF32
660                             }
661                             (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => {
662                                 elf::R_390_GOTOFF64
663                             }
664                             (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => {
665                                 elf::R_390_GOTPC
666                             }
667                             (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => {
668                                 elf::R_390_GOTPCDBL
669                             }
670                             (RelocationKind::Elf(x), _, _) => x,
671                             _ => {
672                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
673                             }
674                         },
675                         Architecture::Mips => match (reloc.kind, reloc.encoding, reloc.size) {
676                             (RelocationKind::Elf(x), _, _) => x,
677                             _ => {
678                                 return Err(Error(format!("unimplemented relocation {:?}", reloc)));
679                             }
680                         },
681                         _ => {
682                             return Err(Error(format!(
683                                 "unimplemented architecture {:?}",
684                                 self.architecture
685                             )));
686                         }
687                     };
688                     let r_sym = symbol_offsets[reloc.symbol.0].index as u32;
689                     elf.write_rel(
690                         buffer,
691                         is_rela,
692                         Rel {
693                             r_offset: reloc.offset,
694                             r_sym,
695                             r_type,
696                             r_addend: reloc.addend,
697                         },
698                     );
699                 }
700             }
701         }
702 
703         // Write shstrtab section.
704         debug_assert_eq!(shstrtab_offset, buffer.len());
705         buffer.extend(&shstrtab_data);
706 
707         // Write section headers.
708         write_align(buffer, pointer_align);
709         debug_assert_eq!(e_shoff, buffer.len());
710         elf.write_section_header(
711             buffer,
712             SectionHeader {
713                 sh_name: 0,
714                 sh_type: 0,
715                 sh_flags: 0,
716                 sh_addr: 0,
717                 sh_offset: 0,
718                 sh_size: if section_num >= elf::SHN_LORESERVE as usize {
719                     section_num as u64
720                 } else {
721                     0
722                 },
723                 sh_link: if shstrtab_index >= elf::SHN_LORESERVE as usize {
724                     shstrtab_index as u32
725                 } else {
726                     0
727                 },
728                 // TODO: e_phnum overflow
729                 sh_info: 0,
730                 sh_addralign: 0,
731                 sh_entsize: 0,
732             },
733         );
734         for (index, comdat) in self.comdats.iter().enumerate() {
735             let sh_name = comdat_offsets[index]
736                 .str_id
737                 .map(|id| shstrtab.get_offset(id))
738                 .unwrap_or(0) as u32;
739             elf.write_section_header(
740                 buffer,
741                 SectionHeader {
742                     sh_name,
743                     sh_type: elf::SHT_GROUP,
744                     sh_flags: 0,
745                     sh_addr: 0,
746                     sh_offset: comdat_offsets[index].offset as u64,
747                     sh_size: comdat_offsets[index].len as u64,
748                     sh_link: symtab_index as u32,
749                     sh_info: symbol_offsets[comdat.symbol.0].index as u32,
750                     sh_addralign: 4,
751                     sh_entsize: 4,
752                 },
753             );
754         }
755         for (index, section) in self.sections.iter().enumerate() {
756             let sh_type = match section.kind {
757                 SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS,
758                 SectionKind::Note => elf::SHT_NOTE,
759                 SectionKind::Elf(sh_type) => sh_type,
760                 _ => elf::SHT_PROGBITS,
761             };
762             let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags {
763                 sh_flags
764             } else {
765                 match section.kind {
766                     SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR,
767                     SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE,
768                     SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
769                     SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE,
770                     SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS,
771                     SectionKind::ReadOnlyData => elf::SHF_ALLOC,
772                     SectionKind::ReadOnlyString => {
773                         elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE
774                     }
775                     SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE,
776                     SectionKind::Other
777                     | SectionKind::Debug
778                     | SectionKind::Metadata
779                     | SectionKind::Linker
780                     | SectionKind::Note
781                     | SectionKind::Elf(_) => 0,
782                     SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => {
783                         return Err(Error(format!(
784                             "unimplemented section `{}` kind {:?}",
785                             section.name().unwrap_or(""),
786                             section.kind
787                         )));
788                     }
789                 }
790                 .into()
791             };
792             // TODO: not sure if this is correct, maybe user should determine this
793             let sh_entsize = match section.kind {
794                 SectionKind::ReadOnlyString | SectionKind::OtherString => 1,
795                 _ => 0,
796             };
797             let sh_name = section_offsets[index]
798                 .str_id
799                 .map(|id| shstrtab.get_offset(id))
800                 .unwrap_or(0) as u32;
801             elf.write_section_header(
802                 buffer,
803                 SectionHeader {
804                     sh_name,
805                     sh_type,
806                     sh_flags,
807                     sh_addr: 0,
808                     sh_offset: section_offsets[index].offset as u64,
809                     sh_size: section.size,
810                     sh_link: 0,
811                     sh_info: 0,
812                     sh_addralign: section.align,
813                     sh_entsize,
814                 },
815             );
816 
817             if !section.relocations.is_empty() {
818                 let sh_name = section_offsets[index]
819                     .reloc_str_id
820                     .map(|id| shstrtab.get_offset(id))
821                     .unwrap_or(0);
822                 elf.write_section_header(
823                     buffer,
824                     SectionHeader {
825                         sh_name: sh_name as u32,
826                         sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL },
827                         sh_flags: elf::SHF_INFO_LINK.into(),
828                         sh_addr: 0,
829                         sh_offset: section_offsets[index].reloc_offset as u64,
830                         sh_size: section_offsets[index].reloc_len as u64,
831                         sh_link: symtab_index as u32,
832                         sh_info: section_offsets[index].index as u32,
833                         sh_addralign: pointer_align as u64,
834                         sh_entsize: elf.rel_size(is_rela) as u64,
835                     },
836                 );
837             }
838         }
839 
840         // Write symtab section header.
841         elf.write_section_header(
842             buffer,
843             SectionHeader {
844                 sh_name: shstrtab.get_offset(symtab_str_id) as u32,
845                 sh_type: elf::SHT_SYMTAB,
846                 sh_flags: 0,
847                 sh_addr: 0,
848                 sh_offset: symtab_offset as u64,
849                 sh_size: symtab_len as u64,
850                 sh_link: strtab_index as u32,
851                 sh_info: symtab_count_local as u32,
852                 sh_addralign: pointer_align as u64,
853                 sh_entsize: elf.symbol_size() as u64,
854             },
855         );
856 
857         // Write symtab_shndx section header.
858         if need_symtab_shndx {
859             elf.write_section_header(
860                 buffer,
861                 SectionHeader {
862                     sh_name: shstrtab.get_offset(symtab_shndx_str_id.unwrap()) as u32,
863                     sh_type: elf::SHT_SYMTAB_SHNDX,
864                     sh_flags: 0,
865                     sh_addr: 0,
866                     sh_offset: symtab_shndx_offset as u64,
867                     sh_size: symtab_shndx_len as u64,
868                     sh_link: symtab_index as u32,
869                     sh_info: symtab_count_local as u32,
870                     sh_addralign: 4,
871                     sh_entsize: 4,
872                 },
873             );
874         }
875 
876         // Write strtab section header.
877         elf.write_section_header(
878             buffer,
879             SectionHeader {
880                 sh_name: shstrtab.get_offset(strtab_str_id) as u32,
881                 sh_type: elf::SHT_STRTAB,
882                 sh_flags: 0,
883                 sh_addr: 0,
884                 sh_offset: strtab_offset as u64,
885                 sh_size: strtab_data.len() as u64,
886                 sh_link: 0,
887                 sh_info: 0,
888                 sh_addralign: 1,
889                 sh_entsize: 0,
890             },
891         );
892 
893         // Write shstrtab section header.
894         elf.write_section_header(
895             buffer,
896             SectionHeader {
897                 sh_name: shstrtab.get_offset(shstrtab_str_id) as u32,
898                 sh_type: elf::SHT_STRTAB,
899                 sh_flags: 0,
900                 sh_addr: 0,
901                 sh_offset: shstrtab_offset as u64,
902                 sh_size: shstrtab_data.len() as u64,
903                 sh_link: 0,
904                 sh_info: 0,
905                 sh_addralign: 1,
906                 sh_entsize: 0,
907             },
908         );
909 
910         debug_assert_eq!(offset, buffer.len());
911 
912         Ok(())
913     }
914 }
915 
916 /// Native endian version of `FileHeader64`.
917 struct FileHeader {
918     e_ident: elf::Ident,
919     e_type: u16,
920     e_machine: u16,
921     e_version: u32,
922     e_entry: u64,
923     e_phoff: u64,
924     e_shoff: u64,
925     e_flags: u32,
926     e_ehsize: u16,
927     e_phentsize: u16,
928     e_phnum: u16,
929     e_shentsize: u16,
930     e_shnum: u16,
931     e_shstrndx: u16,
932 }
933 
934 /// Native endian version of `SectionHeader64`.
935 struct SectionHeader {
936     sh_name: u32,
937     sh_type: u32,
938     sh_flags: u64,
939     sh_addr: u64,
940     sh_offset: u64,
941     sh_size: u64,
942     sh_link: u32,
943     sh_info: u32,
944     sh_addralign: u64,
945     sh_entsize: u64,
946 }
947 
948 /// Native endian version of `Sym64`.
949 struct Sym {
950     st_name: u32,
951     st_info: u8,
952     st_other: u8,
953     st_shndx: u16,
954     st_value: u64,
955     st_size: u64,
956 }
957 
958 /// Unified native endian version of `Rel*`.
959 struct Rel {
960     r_offset: u64,
961     r_sym: u32,
962     r_type: u32,
963     r_addend: i64,
964 }
965 
966 trait Elf {
file_header_size(&self) -> usize967     fn file_header_size(&self) -> usize;
section_header_size(&self) -> usize968     fn section_header_size(&self) -> usize;
symbol_size(&self) -> usize969     fn symbol_size(&self) -> usize;
rel_size(&self, is_rela: bool) -> usize970     fn rel_size(&self, is_rela: bool) -> usize;
write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader)971     fn write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader);
write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)972     fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym)973     fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym);
write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel)974     fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel);
975 }
976 
977 struct Elf32<E> {
978     endian: E,
979 }
980 
981 impl<E: Endian> Elf for Elf32<E> {
file_header_size(&self) -> usize982     fn file_header_size(&self) -> usize {
983         mem::size_of::<elf::FileHeader32<E>>()
984     }
985 
section_header_size(&self) -> usize986     fn section_header_size(&self) -> usize {
987         mem::size_of::<elf::SectionHeader32<E>>()
988     }
989 
symbol_size(&self) -> usize990     fn symbol_size(&self) -> usize {
991         mem::size_of::<elf::Sym32<E>>()
992     }
993 
rel_size(&self, is_rela: bool) -> usize994     fn rel_size(&self, is_rela: bool) -> usize {
995         if is_rela {
996             mem::size_of::<elf::Rela32<E>>()
997         } else {
998             mem::size_of::<elf::Rel32<E>>()
999         }
1000     }
1001 
write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader)1002     fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
1003         let endian = self.endian;
1004         let file = elf::FileHeader32 {
1005             e_ident: file.e_ident,
1006             e_type: U16::new(endian, file.e_type),
1007             e_machine: U16::new(endian, file.e_machine),
1008             e_version: U32::new(endian, file.e_version),
1009             e_entry: U32::new(endian, file.e_entry as u32),
1010             e_phoff: U32::new(endian, file.e_phoff as u32),
1011             e_shoff: U32::new(endian, file.e_shoff as u32),
1012             e_flags: U32::new(endian, file.e_flags),
1013             e_ehsize: U16::new(endian, file.e_ehsize),
1014             e_phentsize: U16::new(endian, file.e_phentsize),
1015             e_phnum: U16::new(endian, file.e_phnum),
1016             e_shentsize: U16::new(endian, file.e_shentsize),
1017             e_shnum: U16::new(endian, file.e_shnum),
1018             e_shstrndx: U16::new(endian, file.e_shstrndx),
1019         };
1020         buffer.extend(bytes_of(&file));
1021     }
1022 
write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)1023     fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
1024         let endian = self.endian;
1025         let section = elf::SectionHeader32 {
1026             sh_name: U32::new(endian, section.sh_name),
1027             sh_type: U32::new(endian, section.sh_type),
1028             sh_flags: U32::new(endian, section.sh_flags as u32),
1029             sh_addr: U32::new(endian, section.sh_addr as u32),
1030             sh_offset: U32::new(endian, section.sh_offset as u32),
1031             sh_size: U32::new(endian, section.sh_size as u32),
1032             sh_link: U32::new(endian, section.sh_link),
1033             sh_info: U32::new(endian, section.sh_info),
1034             sh_addralign: U32::new(endian, section.sh_addralign as u32),
1035             sh_entsize: U32::new(endian, section.sh_entsize as u32),
1036         };
1037         buffer.extend(bytes_of(&section));
1038     }
1039 
write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym)1040     fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
1041         let endian = self.endian;
1042         let symbol = elf::Sym32 {
1043             st_name: U32::new(endian, symbol.st_name),
1044             st_info: symbol.st_info,
1045             st_other: symbol.st_other,
1046             st_shndx: U16::new(endian, symbol.st_shndx),
1047             st_value: U32::new(endian, symbol.st_value as u32),
1048             st_size: U32::new(endian, symbol.st_size as u32),
1049         };
1050         buffer.extend(bytes_of(&symbol));
1051     }
1052 
write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel)1053     fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) {
1054         let endian = self.endian;
1055         if is_rela {
1056             let rel = elf::Rela32 {
1057                 r_offset: U32::new(endian, rel.r_offset as u32),
1058                 r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1059                 r_addend: I32::new(endian, rel.r_addend as i32),
1060             };
1061             buffer.extend(bytes_of(&rel));
1062         } else {
1063             let rel = elf::Rel32 {
1064                 r_offset: U32::new(endian, rel.r_offset as u32),
1065                 r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8),
1066             };
1067             buffer.extend(bytes_of(&rel));
1068         }
1069     }
1070 }
1071 
1072 struct Elf64<E> {
1073     endian: E,
1074 }
1075 
1076 impl<E: Endian> Elf for Elf64<E> {
file_header_size(&self) -> usize1077     fn file_header_size(&self) -> usize {
1078         mem::size_of::<elf::FileHeader64<E>>()
1079     }
1080 
section_header_size(&self) -> usize1081     fn section_header_size(&self) -> usize {
1082         mem::size_of::<elf::SectionHeader64<E>>()
1083     }
1084 
symbol_size(&self) -> usize1085     fn symbol_size(&self) -> usize {
1086         mem::size_of::<elf::Sym64<E>>()
1087     }
1088 
rel_size(&self, is_rela: bool) -> usize1089     fn rel_size(&self, is_rela: bool) -> usize {
1090         if is_rela {
1091             mem::size_of::<elf::Rela64<E>>()
1092         } else {
1093             mem::size_of::<elf::Rel64<E>>()
1094         }
1095     }
1096 
write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader)1097     fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
1098         let endian = self.endian;
1099         let file = elf::FileHeader64 {
1100             e_ident: file.e_ident,
1101             e_type: U16::new(endian, file.e_type),
1102             e_machine: U16::new(endian, file.e_machine),
1103             e_version: U32::new(endian, file.e_version),
1104             e_entry: U64::new(endian, file.e_entry),
1105             e_phoff: U64::new(endian, file.e_phoff),
1106             e_shoff: U64::new(endian, file.e_shoff),
1107             e_flags: U32::new(endian, file.e_flags),
1108             e_ehsize: U16::new(endian, file.e_ehsize),
1109             e_phentsize: U16::new(endian, file.e_phentsize),
1110             e_phnum: U16::new(endian, file.e_phnum),
1111             e_shentsize: U16::new(endian, file.e_shentsize),
1112             e_shnum: U16::new(endian, file.e_shnum),
1113             e_shstrndx: U16::new(endian, file.e_shstrndx),
1114         };
1115         buffer.extend(bytes_of(&file))
1116     }
1117 
write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader)1118     fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
1119         let endian = self.endian;
1120         let section = elf::SectionHeader64 {
1121             sh_name: U32::new(endian, section.sh_name),
1122             sh_type: U32::new(endian, section.sh_type),
1123             sh_flags: U64::new(endian, section.sh_flags),
1124             sh_addr: U64::new(endian, section.sh_addr),
1125             sh_offset: U64::new(endian, section.sh_offset),
1126             sh_size: U64::new(endian, section.sh_size),
1127             sh_link: U32::new(endian, section.sh_link),
1128             sh_info: U32::new(endian, section.sh_info),
1129             sh_addralign: U64::new(endian, section.sh_addralign),
1130             sh_entsize: U64::new(endian, section.sh_entsize),
1131         };
1132         buffer.extend(bytes_of(&section));
1133     }
1134 
write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym)1135     fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
1136         let endian = self.endian;
1137         let symbol = elf::Sym64 {
1138             st_name: U32::new(endian, symbol.st_name),
1139             st_info: symbol.st_info,
1140             st_other: symbol.st_other,
1141             st_shndx: U16::new(endian, symbol.st_shndx),
1142             st_value: U64::new(endian, symbol.st_value),
1143             st_size: U64::new(endian, symbol.st_size),
1144         };
1145         buffer.extend(bytes_of(&symbol));
1146     }
1147 
write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel)1148     fn write_rel(&self, buffer: &mut dyn WritableBuffer, is_rela: bool, rel: Rel) {
1149         let endian = self.endian;
1150         if is_rela {
1151             let rel = elf::Rela64 {
1152                 r_offset: U64::new(endian, rel.r_offset),
1153                 r_info: elf::Rela64::r_info(endian, rel.r_sym, rel.r_type),
1154                 r_addend: I64::new(endian, rel.r_addend),
1155             };
1156             buffer.extend(bytes_of(&rel));
1157         } else {
1158             let rel = elf::Rel64 {
1159                 r_offset: U64::new(endian, rel.r_offset),
1160                 r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type),
1161             };
1162             buffer.extend(bytes_of(&rel));
1163         }
1164     }
1165 }
1166