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