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