elf: allow for absence of dynstr (#646)

.dynstr doesn't need to be present if there are no dynamic strings.

- handle section index 0 in read::elf::SectionTable::strings
- don't require .dynstr when writing if there are no strings
- don't print name of symbol index 0 in readobj example
This commit is contained in:
Philip Craig
2024-03-19 14:56:51 +10:00
committed by GitHub
parent 67d53c27f7
commit f3432e9807
16 changed files with 139 additions and 48 deletions
+13 -5
View File
@@ -398,11 +398,15 @@ fn print_section_symbols<Elf: FileHeader>(
for (index, symbol) in symbols.iter().enumerate() {
p.group("Symbol", |p| {
p.field("Index", index);
p.field_string(
"Name",
symbol.st_name(endian),
symbol.name(endian, symbols.strings()),
);
if index == 0 {
p.field_hex("Name", symbol.st_name(endian));
} else {
p.field_string(
"Name",
symbol.st_name(endian),
symbol.name(endian, symbols.strings()),
);
}
if let Some(versions) = versions.as_ref() {
let version_index = versions.version_index(endian, index);
print_version(p, Some(versions), version_index);
@@ -511,6 +515,10 @@ fn print_rel_symbol<Elf: FileHeader>(
symbols: Option<SymbolTable<'_, Elf>>,
sym: u32,
) {
if sym == 0 {
p.field_hex("Symbol", sym);
return;
}
let name = symbols.and_then(|symbols| {
symbols
.symbol(sym as usize)
@@ -167,7 +167,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -338,7 +338,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -559,37 +559,37 @@ SectionHeader {
Relocation {
Offset: 0x10D80
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x720
}
Relocation {
Offset: 0x10D88
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x6D8
}
Relocation {
Offset: 0x10FC8
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x7C8
}
Relocation {
Offset: 0x10FE8
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x748
}
Relocation {
Offset: 0x10FF0
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x724
}
Relocation {
Offset: 0x11008
Type: R_AARCH64_RELATIVE (0x403)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x11008
}
Relocation {
@@ -971,7 +971,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -269,7 +269,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -442,7 +442,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -984,7 +984,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
+1 -1
View File
@@ -197,7 +197,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
+5 -5
View File
@@ -371,7 +371,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -547,19 +547,19 @@ SectionHeader {
Relocation {
Offset: 0x200DA8
Type: R_X86_64_RELATIVE (0x8)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x670
}
Relocation {
Offset: 0x200DB0
Type: R_X86_64_RELATIVE (0x8)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x630
}
Relocation {
Offset: 0x201008
Type: R_X86_64_RELATIVE (0x8)
Symbol: "" (0x0)
Symbol: 0x0
Addend: 0x201008
}
Relocation {
@@ -959,7 +959,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -227,7 +227,7 @@ SectionHeader {
EntrySize: 0x10
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -185,7 +185,7 @@ SectionHeader {
EntrySize: 0x10
Symbol {
Index: 0
Name: "" (0x0)
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -211,7 +211,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -583,7 +583,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
+5 -5
View File
@@ -371,7 +371,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -547,19 +547,19 @@ SectionHeader {
Relocation {
Offset: 0x200DA8
Type: R_X86_64_RELATIVE (0x8)
Symbol: ""
Symbol: 0x0
Addend: 0x670
}
Relocation {
Offset: 0x200DB0
Type: R_X86_64_RELATIVE (0x8)
Symbol: ""
Symbol: 0x0
Addend: 0x630
}
Relocation {
Offset: 0x201008
Type: R_X86_64_RELATIVE (0x8)
Symbol: ""
Symbol: 0x0
Addend: 0x201008
}
Relocation {
@@ -959,7 +959,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
@@ -222,7 +222,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Version: VER_NDX_LOCAL (0x0)
Value: 0x0
Size: 0x0
@@ -605,7 +605,7 @@ SectionHeader {
EntrySize: 0x18
Symbol {
Index: 0
Name: ""
Name: 0x0
Value: 0x0
Size: 0x0
Type: STT_NOTYPE (0x0)
+6
View File
@@ -1034,15 +1034,21 @@ impl<'data> Builder<'data> {
return Err(Error::new(
".symtab.shndx section is needed but not present",
));
} else if symtab_shndx_id.is_some() {
writer.require_symtab_shndx();
}
if strtab_id.is_none() && writer.strtab_needed() {
return Err(Error::new(".strtab section is needed but not present"));
} else if strtab_id.is_some() {
writer.require_strtab();
}
if dynsym_id.is_none() && !out_dynsyms.is_empty() {
return Err(Error::new(".dynsym section is needed but not present"));
}
if dynstr_id.is_none() && writer.dynstr_needed() {
return Err(Error::new(".dynstr section is needed but not present"));
} else if dynstr_id.is_some() {
writer.require_dynstr();
}
if gnu_verdef_id.is_none() && verdef_count > 0 {
return Err(Error::new(
+4
View File
@@ -86,6 +86,7 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> {
/// Return the string table at the given section index.
///
/// Returns an empty string table if the index is 0.
/// Returns an error if the section is not a string table.
#[inline]
pub fn strings(
@@ -94,6 +95,9 @@ impl<'data, Elf: FileHeader, R: ReadRef<'data>> SectionTable<'data, Elf, R> {
data: R,
index: SectionIndex,
) -> read::Result<StringTable<'data, R>> {
if index == SectionIndex(0) {
return Ok(StringTable::default());
}
self.section(index)?
.strings(endian, data)?
.read_error("Invalid ELF string section type")
+16 -14
View File
@@ -641,6 +641,11 @@ impl<'a> Writer<'a> {
self.need_strtab
}
/// Require the string table even if no strings were added.
pub fn require_strtab(&mut self) {
self.need_strtab = true;
}
/// Reserve the range for the string table.
///
/// This range is used for a section named `.strtab`.
@@ -719,8 +724,6 @@ 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)
}
@@ -741,8 +744,6 @@ 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;
@@ -893,6 +894,12 @@ impl<'a> Writer<'a> {
self.need_symtab_shndx
}
/// Require the extended section indices for the symbol table even
/// if no section indices are too large.
pub fn require_symtab_shndx(&mut self) {
self.need_symtab_shndx = true;
}
/// Reserve the range for the extended section indices for the symbol table.
///
/// This range is used for a section named `.symtab_shndx`.
@@ -992,6 +999,11 @@ impl<'a> Writer<'a> {
self.need_dynstr
}
/// Require the dynamic string table even if no strings were added.
pub fn require_dynstr(&mut self) {
self.need_dynstr = true;
}
/// Reserve the range for the dynamic string table.
///
/// This range is used for a section named `.dynstr`.
@@ -1000,9 +1012,6 @@ impl<'a> Writer<'a> {
/// This must be called after [`Self::add_dynamic_string`].
pub fn reserve_dynstr(&mut self) -> usize {
debug_assert_eq!(self.dynstr_offset, 0);
if !self.need_dynstr {
return 0;
}
// Start with null string.
self.dynstr_data = vec![0];
self.dynstr.write(1, &mut self.dynstr_data);
@@ -1014,9 +1023,6 @@ impl<'a> Writer<'a> {
///
/// This must be called after [`Self::reserve_dynstr`].
pub fn dynstr_len(&mut self) -> usize {
if !self.need_dynstr {
return 0;
}
debug_assert_ne!(self.dynstr_offset, 0);
self.dynstr_data.len()
}
@@ -1087,8 +1093,6 @@ impl<'a> Writer<'a> {
debug_assert_eq!(self.dynsym_offset, 0);
debug_assert_eq!(self.dynsym_num, 0);
self.dynsym_num = 1;
// The symtab must link to a strtab.
self.need_dynstr = true;
SymbolIndex(0)
}
@@ -1105,8 +1109,6 @@ impl<'a> Writer<'a> {
debug_assert_eq!(self.dynsym_offset, 0);
if self.dynsym_num == 0 {
self.dynsym_num = 1;
// The symtab must link to a strtab.
self.need_dynstr = true;
}
let index = self.dynsym_num;
self.dynsym_num += 1;
+71
View File
@@ -37,3 +37,74 @@ fn test_nobits_offset() {
let mut buf = Vec::new();
builder.write(&mut buf).unwrap();
}
// Test that we can read and write a file with no dynamic string table.
#[test]
fn test_no_dynstr() {
let mut builder = build::elf::Builder::new(object::Endianness::Little, true);
builder.header.e_type = elf::ET_EXEC;
builder.header.e_machine = elf::EM_X86_64;
builder.header.e_phoff = 0x40;
let section = builder.sections.add();
section.name = b".shstrtab"[..].into();
section.sh_type = elf::SHT_STRTAB;
section.data = build::elf::SectionData::SectionString;
let section = builder.sections.add();
section.name = b".dynsym"[..].into();
section.sh_type = elf::SHT_DYNSYM;
section.sh_flags = elf::SHF_ALLOC as u64;
section.sh_addr = 0x1000;
section.sh_offset = 0x1000;
section.sh_addralign = 8;
section.data = build::elf::SectionData::DynamicSymbol;
let dynsym_id = section.id();
let section = builder.sections.add();
section.name = b".rela.dyn"[..].into();
section.sh_type = elf::SHT_RELA;
section.sh_flags = elf::SHF_ALLOC as u64;
section.sh_addr = 0x1100;
section.sh_offset = 0x1100;
section.sh_addralign = 8;
section.data =
build::elf::SectionData::DynamicRelocation(vec![build::elf::DynamicRelocation {
r_offset: 0x1000,
symbol: None,
r_type: elf::R_X86_64_64,
r_addend: 0x300,
}]);
let rela_id = section.id();
let segment = builder.segments.add();
segment.p_type = elf::PT_LOAD;
segment.p_flags = elf::PF_R;
segment.p_offset = 0x1000;
segment.p_vaddr = 0x1000;
segment.p_paddr = 0x1000;
segment.p_filesz = 0x200;
segment.p_memsz = 0x200;
segment.p_align = 8;
segment.sections.push(dynsym_id);
segment.sections.push(rela_id);
let mut buf = Vec::new();
builder.write(&mut buf).unwrap();
let builder = build::elf::Builder::read(&*buf).unwrap();
assert_eq!(builder.sections.count(), 3);
assert_eq!(builder.segments.count(), 1);
for section in &builder.sections {
match &section.data {
build::elf::SectionData::DynamicSymbol => {
assert_eq!(section.sh_offset, 0x1000);
}
build::elf::SectionData::DynamicRelocation(rela) => {
assert_eq!(section.sh_offset, 0x1100);
assert_eq!(rela.len(), 1);
}
_ => {}
}
}
}