Repository: gimli-rs/object (rust)

Issue:
rustc fails to build with object 0.35+
Building compiler with object updated to 0.35+ on x86_64-unknown-linux-gnu results with
```
  = note: rust-lld: error: /home/user/rust/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps/libpanic_unwind-0a0cf8f8a42e5845.rlib(lib.rmeta): SHT_STRTAB string table section [index 4] is empty
          collect2: error: ld returned 1 exit status
```
see https://github.com/rust-lang/rust/pull/128040

I've bisected object to this https://github.com/gimli-rs/object/pull/646 PR

https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/compiler.20fails.20to.20build.20with.20object.200.2E35

current master fd84037eb96912392759c70ea7544bb24dd236e1 fails too

Pull request description:
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`

Closes #709

Patch:
diff --git a/src/write/elf/writer.rs b/src/write/elf/writer.rs
index 5895f56..756910a 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));


Test patch:
diff --git a/tests/round_trip/elf.rs b/tests/round_trip/elf.rs
index dfc566c..2f3351f 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 =