Skip to main content

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