From 82be58d83a2c1fb41ba1babbe59c1d54b100f6ac Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 23 Jul 2024 21:36:37 +1000 Subject: [PATCH] write/elf: fix writing of strtab when symtab is empty Previously, if the symtab was empty then we were writing a strtab that had 0 bytes of data. This gives a linker error: SHT_STRTAB string table section [index 4] is empty Also, if there is a symtab then there must be a strtab, otherwise the error is: invalid sh_type for string table section [index 0]: expected SHT_STRTAB, but got SHT_NULL --- src/write/elf/writer.rs | 18 +++++++++++++++++- tests/round_trip/elf.rs | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/write/elf/writer.rs b/src/write/elf/writer.rs index 5895f56e..756910a0 100644 --- a/src/write/elf/writer.rs +++ b/src/write/elf/writer.rs @@ -658,7 +658,7 @@ impl<'a> Writer<'a> { /// /// This range is used for a section named `.strtab`. /// - /// This function does nothing if no strings were defined. + /// This function does nothing if a string table is not required. /// This must be called after [`Self::add_string`]. pub fn reserve_strtab(&mut self) { debug_assert_eq!(self.strtab_offset, 0); @@ -684,6 +684,9 @@ impl<'a> Writer<'a> { /// Reserve the section index for the string table. /// + /// You should check [`Self::strtab_needed`] before calling this + /// unless you have other means of knowing if this section is needed. + /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_strtab_section_index(&mut self) -> SectionIndex { self.reserve_strtab_section_index_with_name(&b".strtab"[..]) @@ -691,6 +694,9 @@ impl<'a> Writer<'a> { /// Reserve the section index for the string table. /// + /// You should check [`Self::strtab_needed`] before calling this + /// unless you have other means of knowing if this section is needed. + /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_strtab_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.strtab_index, SectionIndex(0)); @@ -732,6 +738,8 @@ impl<'a> Writer<'a> { debug_assert_eq!(self.symtab_offset, 0); debug_assert_eq!(self.symtab_num, 0); self.symtab_num = 1; + // The symtab must link to a strtab. + self.need_strtab = true; SymbolIndex(0) } @@ -752,6 +760,8 @@ impl<'a> Writer<'a> { debug_assert_eq!(self.symtab_shndx_offset, 0); if self.symtab_num == 0 { self.symtab_num = 1; + // The symtab must link to a strtab. + self.need_strtab = true; } let index = self.symtab_num; self.symtab_num += 1; @@ -1052,6 +1062,9 @@ impl<'a> Writer<'a> { /// Reserve the section index for the dynamic string table. /// + /// You should check [`Self::dynstr_needed`] before calling this + /// unless you have other means of knowing if this section is needed. + /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex { self.reserve_dynstr_section_index_with_name(&b".dynstr"[..]) @@ -1059,6 +1072,9 @@ impl<'a> Writer<'a> { /// Reserve the section index for the dynamic string table. /// + /// You should check [`Self::dynstr_needed`] before calling this + /// unless you have other means of knowing if this section is needed. + /// /// This must be called before [`Self::reserve_section_headers`]. pub fn reserve_dynstr_section_index_with_name(&mut self, name: &'a [u8]) -> SectionIndex { debug_assert_eq!(self.dynstr_index, SectionIndex(0)); diff --git a/tests/round_trip/elf.rs b/tests/round_trip/elf.rs index dfc566c5..2f3351ff 100644 --- a/tests/round_trip/elf.rs +++ b/tests/round_trip/elf.rs @@ -42,6 +42,20 @@ fn symtab_shndx() { } } +#[test] +fn empty_symtab() { + let object = write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + let bytes = object.write().unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + let symtab = object.section_by_name(".symtab").unwrap(); + assert_eq!(symtab.size(), 24); + let strtab = object.section_by_name(".strtab").unwrap(); + assert_eq!(strtab.size(), 1); +} + #[test] fn aligned_sections() { let mut object =