object/write/elf/
object.rs

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