254 lines
8.7 KiB
Rust
254 lines
8.7 KiB
Rust
use object::{build, elf};
|
|
|
|
// Test that offset 0 is supported for SHT_NOBITS sections.
|
|
#[test]
|
|
fn test_nobits_offset() {
|
|
let mut builder = build::elf::Builder::new(object::Endianness::Little, true);
|
|
builder.header.e_type = elf::ET_EXEC;
|
|
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".bss"[..].into();
|
|
section.sh_type = elf::SHT_NOBITS;
|
|
section.sh_flags = (elf::SHF_ALLOC | elf::SHF_WRITE) as u64;
|
|
section.sh_addr = 0x1000;
|
|
section.sh_offset = 0;
|
|
section.sh_size = 0x1000;
|
|
section.sh_addralign = 16;
|
|
section.data = build::elf::SectionData::UninitializedData(0x1000);
|
|
let section_id = section.id();
|
|
|
|
let segment = builder.segments.add();
|
|
segment.p_type = elf::PT_LOAD;
|
|
segment.p_flags = elf::PF_R | elf::PF_W;
|
|
segment.p_offset = 0x1000;
|
|
segment.p_vaddr = 0x1000;
|
|
segment.p_paddr = 0x1000;
|
|
segment.p_filesz = 0;
|
|
segment.p_memsz = 0x1000;
|
|
segment.p_align = 16;
|
|
segment.sections.push(section_id);
|
|
|
|
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_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_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();
|
|
|
|
builder.set_section_sizes();
|
|
|
|
let segment = builder.segments.add();
|
|
segment.p_type = elf::PT_LOAD;
|
|
segment.p_flags = elf::PF_R;
|
|
segment.p_filesz = 0x1000;
|
|
segment.p_memsz = 0x1000;
|
|
segment.p_align = 8;
|
|
segment.append_section(builder.sections.get_mut(dynsym_id));
|
|
segment.append_section(builder.sections.get_mut(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 §ion.data {
|
|
build::elf::SectionData::DynamicSymbol => {
|
|
assert_eq!(section.sh_offset, 0x1000);
|
|
}
|
|
build::elf::SectionData::DynamicRelocation(rela) => {
|
|
assert_eq!(section.sh_offset, 0x1018);
|
|
assert_eq!(rela.len(), 1);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_attribute() {
|
|
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 attributes = build::elf::AttributesSection {
|
|
subsections: vec![build::elf::AttributesSubsection {
|
|
vendor: b"GNU"[..].into(),
|
|
subsubsections: vec![
|
|
(build::elf::AttributesSubsubsection {
|
|
tag: build::elf::AttributeTag::File,
|
|
data: b"123"[..].into(),
|
|
}),
|
|
],
|
|
}],
|
|
};
|
|
let section = builder.sections.add();
|
|
section.name = b".gnu.attributes"[..].into();
|
|
section.sh_type = elf::SHT_GNU_ATTRIBUTES;
|
|
section.sh_addralign = 8;
|
|
section.data = build::elf::SectionData::Attributes(attributes);
|
|
|
|
let mut buf = Vec::new();
|
|
builder.write(&mut buf).unwrap();
|
|
|
|
let builder = build::elf::Builder::read(&*buf).unwrap();
|
|
assert_eq!(builder.sections.count(), 2);
|
|
for section in &builder.sections {
|
|
if let build::elf::SectionData::Attributes(attributes) = §ion.data {
|
|
assert_eq!(attributes.subsections.len(), 1);
|
|
assert_eq!(attributes.subsections[0].vendor.as_slice(), b"GNU");
|
|
assert_eq!(attributes.subsections[0].subsubsections.len(), 1);
|
|
assert_eq!(
|
|
attributes.subsections[0].subsubsections[0].tag,
|
|
build::elf::AttributeTag::File
|
|
);
|
|
assert_eq!(
|
|
attributes.subsections[0].subsubsections[0].data.as_slice(),
|
|
b"123"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_dynsym() {
|
|
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".text"[..].into();
|
|
section.sh_type = elf::SHT_PROGBITS;
|
|
section.sh_flags = (elf::SHF_ALLOC | elf::SHF_EXECINSTR) as u64;
|
|
section.sh_addralign = 16;
|
|
section.data = build::elf::SectionData::Data(vec![0xcc; 100].into());
|
|
let text_id = section.id();
|
|
|
|
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_addralign = 8;
|
|
section.data = build::elf::SectionData::DynamicSymbol;
|
|
let dynsym_id = section.id();
|
|
|
|
let section = builder.sections.add();
|
|
section.name = b".dynstr"[..].into();
|
|
section.sh_type = elf::SHT_STRTAB;
|
|
section.sh_flags = elf::SHF_ALLOC as u64;
|
|
section.sh_addralign = 1;
|
|
section.data = build::elf::SectionData::DynamicString;
|
|
let dynstr_id = section.id();
|
|
|
|
let section = builder.sections.add();
|
|
section.name = b".gnu.hash"[..].into();
|
|
section.sh_type = elf::SHT_GNU_HASH;
|
|
section.sh_flags = elf::SHF_ALLOC as u64;
|
|
section.sh_addralign = 8;
|
|
section.data = build::elf::SectionData::GnuHash;
|
|
let gnu_hash_id = section.id();
|
|
builder.gnu_hash_bloom_shift = 1;
|
|
builder.gnu_hash_bloom_count = 1;
|
|
builder.gnu_hash_bucket_count = 1;
|
|
|
|
let symbol = builder.dynamic_symbols.add();
|
|
symbol.name = b"global"[..].into();
|
|
symbol.set_st_info(elf::STB_GLOBAL, elf::STT_FUNC);
|
|
symbol.section = Some(text_id);
|
|
|
|
let symbol = builder.dynamic_symbols.add();
|
|
symbol.name = b"undefined"[..].into();
|
|
symbol.set_st_info(elf::STB_GLOBAL, elf::STT_NOTYPE);
|
|
|
|
let symbol = builder.dynamic_symbols.add();
|
|
symbol.name = b"local"[..].into();
|
|
symbol.set_st_info(elf::STB_LOCAL, elf::STT_FUNC);
|
|
symbol.section = Some(text_id);
|
|
|
|
builder.set_section_sizes();
|
|
|
|
let segment = builder.segments.add();
|
|
segment.p_type = elf::PT_LOAD;
|
|
segment.p_flags = elf::PF_R;
|
|
segment.p_filesz = 0x1000;
|
|
segment.p_memsz = 0x1000;
|
|
segment.p_align = 8;
|
|
segment.append_section(builder.sections.get_mut(text_id));
|
|
segment.append_section(builder.sections.get_mut(dynsym_id));
|
|
segment.append_section(builder.sections.get_mut(dynstr_id));
|
|
segment.append_section(builder.sections.get_mut(gnu_hash_id));
|
|
|
|
let mut buf = Vec::new();
|
|
builder.write(&mut buf).unwrap();
|
|
|
|
let builder = build::elf::Builder::read(&*buf).unwrap();
|
|
assert_eq!(builder.sections.count(), 5);
|
|
assert_eq!(builder.dynamic_symbols.count(), 3);
|
|
// Check that the dynamic symbol table sorting handles
|
|
// local and undefined symbols correctly.
|
|
assert_eq!(
|
|
builder
|
|
.dynamic_symbols
|
|
.iter()
|
|
.map(|s| s.name.as_slice())
|
|
.collect::<Vec<_>>(),
|
|
vec![&b"local"[..], &b"undefined"[..], &b"global"[..]]
|
|
);
|
|
for section in &builder.sections {
|
|
if let build::elf::SectionData::DynamicSymbol = §ion.data {
|
|
// Check that sh_info includes the number of local symbols.
|
|
assert_eq!(section.sh_info, 2);
|
|
}
|
|
}
|
|
}
|