diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-02 18:36:06 -0600 |
| commit | 8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch) | |
| tree | 22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/object/tests | |
| parent | 4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff) | |
chore: add vendor directory
Diffstat (limited to 'vendor/object/tests')
| -rw-r--r-- | vendor/object/tests/build/elf.rs | 254 | ||||
| -rw-r--r-- | vendor/object/tests/build/mod.rs | 3 | ||||
| -rw-r--r-- | vendor/object/tests/integration.rs | 3 | ||||
| -rw-r--r-- | vendor/object/tests/parse_self.rs | 25 | ||||
| -rw-r--r-- | vendor/object/tests/read/coff.rs | 23 | ||||
| -rw-r--r-- | vendor/object/tests/read/elf.rs | 47 | ||||
| -rw-r--r-- | vendor/object/tests/read/macho.rs | 49 | ||||
| -rw-r--r-- | vendor/object/tests/read/mod.rs | 5 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/bss.rs | 256 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/coff.rs | 58 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/comdat.rs | 217 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/common.rs | 241 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/elf.rs | 302 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/macho.rs | 64 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/mod.rs | 686 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/section_flags.rs | 89 | ||||
| -rw-r--r-- | vendor/object/tests/round_trip/tls.rs | 308 |
17 files changed, 2630 insertions, 0 deletions
diff --git a/vendor/object/tests/build/elf.rs b/vendor/object/tests/build/elf.rs new file mode 100644 index 00000000..53979ee1 --- /dev/null +++ b/vendor/object/tests/build/elf.rs @@ -0,0 +1,254 @@ +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); + } + } +} diff --git a/vendor/object/tests/build/mod.rs b/vendor/object/tests/build/mod.rs new file mode 100644 index 00000000..6a777367 --- /dev/null +++ b/vendor/object/tests/build/mod.rs @@ -0,0 +1,3 @@ +#![cfg(feature = "build")] + +mod elf; diff --git a/vendor/object/tests/integration.rs b/vendor/object/tests/integration.rs new file mode 100644 index 00000000..560ba626 --- /dev/null +++ b/vendor/object/tests/integration.rs @@ -0,0 +1,3 @@ +mod build; +mod read; +mod round_trip; diff --git a/vendor/object/tests/parse_self.rs b/vendor/object/tests/parse_self.rs new file mode 100644 index 00000000..1e7df671 --- /dev/null +++ b/vendor/object/tests/parse_self.rs @@ -0,0 +1,25 @@ +#![cfg(feature = "read")] +use object::{File, Object}; +use std::{env, fs}; + +#[test] +fn parse_self() { + let exe = env::current_exe().unwrap(); + let data = fs::read(exe).unwrap(); + let object = File::parse(&*data).unwrap(); + assert!(object.entry() != 0); + assert!(object.sections().count() != 0); +} + +#[cfg(feature = "std")] +#[test] +fn parse_self_cache() { + use object::read::{ReadCache, ReadRef}; + let exe = env::current_exe().unwrap(); + let file = fs::File::open(exe).unwrap(); + let cache = ReadCache::new(file); + let data = cache.range(0, cache.len().unwrap()); + let object = File::parse(data).unwrap(); + assert!(object.entry() != 0); + assert!(object.sections().count() != 0); +} diff --git a/vendor/object/tests/read/coff.rs b/vendor/object/tests/read/coff.rs new file mode 100644 index 00000000..959e317a --- /dev/null +++ b/vendor/object/tests/read/coff.rs @@ -0,0 +1,23 @@ +use object::{pe, read, Object, ObjectSection}; +use std::fs; +use std::path::PathBuf; + +#[cfg(feature = "coff")] +#[test] +fn coff_extended_relocations() { + let path_to_obj: PathBuf = ["testfiles", "coff", "relocs_overflow.o"].iter().collect(); + let contents = fs::read(path_to_obj).expect("Could not read relocs_overflow.o"); + let file = + read::coff::CoffFile::<_>::parse(&contents[..]).expect("Could not parse relocs_overflow.o"); + let code_section = file + .section_by_name(".text") + .expect("Could not find .text section in relocs_overflow.o"); + match code_section.flags() { + object::SectionFlags::Coff { characteristics } => { + assert!(characteristics & pe::IMAGE_SCN_LNK_NRELOC_OVFL != 0) + } + _ => panic!("Invalid section flags flavour."), + }; + let relocations = code_section.relocations().collect::<Vec<_>>(); + assert_eq!(relocations.len(), 65536); +} diff --git a/vendor/object/tests/read/elf.rs b/vendor/object/tests/read/elf.rs new file mode 100644 index 00000000..e42cd516 --- /dev/null +++ b/vendor/object/tests/read/elf.rs @@ -0,0 +1,47 @@ +#[cfg(feature = "std")] +use std::path::{Path, PathBuf}; + +#[cfg(feature = "std")] +fn get_buildid(path: &Path) -> Result<Option<Vec<u8>>, object::read::Error> { + use object::Object; + let file = std::fs::File::open(path).unwrap(); + let reader = object::read::ReadCache::new(file); + let object = object::read::File::parse(&reader)?; + object + .build_id() + .map(|option| option.map(ToOwned::to_owned)) +} + +#[cfg(feature = "std")] +#[test] +/// Regression test: used to attempt to allocate 5644418395173552131 bytes +fn get_buildid_bad_elf() { + let path: PathBuf = [ + "testfiles", + "elf", + "yara-fuzzing", + "crash-7dc27920ae1cb85333e7f2735a45014488134673", + ] + .iter() + .collect(); + let _ = get_buildid(&path); +} + +#[cfg(feature = "std")] +#[test] +fn get_buildid_less_bad_elf() { + let path: PathBuf = [ + "testfiles", + "elf", + "yara-fuzzing", + "crash-f1fd008da535b110853885221ebfaac3f262a1c1e280f10929f7b353c44996c8", + ] + .iter() + .collect(); + let buildid = get_buildid(&path).unwrap().unwrap(); + // ground truth obtained from GNU binutils's readelf + assert_eq!( + buildid, + b"\xf9\xc0\xc6\x05\xd3\x76\xbb\xa5\x7e\x02\xf5\x74\x50\x9d\x16\xcc\xe9\x9c\x1b\xf1" + ); +} diff --git a/vendor/object/tests/read/macho.rs b/vendor/object/tests/read/macho.rs new file mode 100644 index 00000000..59f314be --- /dev/null +++ b/vendor/object/tests/read/macho.rs @@ -0,0 +1,49 @@ +#[cfg(feature = "std")] +use object::{Object, ObjectSection as _}; + +// Test that we can read compressed sections in Mach-O files as produced +// by the Go compiler. +#[cfg(feature = "std")] +#[test] +fn test_go_macho() { + let macho_testfiles = std::path::Path::new("testfiles/macho"); + + // Section names we expect to find, whether they should be + // compressed, and the actual name of the section in the file. + const EXPECTED: &[(&str, bool, &str)] = &[ + (".debug_abbrev", true, "__zdebug_abbrev"), + (".debug_gdb_scripts", false, "__debug_gdb_scri"), + (".debug_ranges", true, "__zdebug_ranges"), + ("__data", false, "__data"), + ]; + + for file in &["go-aarch64", "go-x86_64"] { + let path = macho_testfiles.join(file); + let file = std::fs::File::open(path).unwrap(); + let reader = object::read::ReadCache::new(file); + let object = object::read::File::parse(&reader).unwrap(); + for &(name, compressed, actual_name) in EXPECTED { + let section = object.section_by_name(name).unwrap(); + assert_eq!(section.name(), Ok(actual_name)); + let compressed_file_range = section.compressed_file_range().unwrap(); + let size = section.size(); + if compressed { + assert_eq!( + compressed_file_range.format, + object::CompressionFormat::Zlib + ); + assert_eq!(compressed_file_range.compressed_size, size - 12); + assert!( + compressed_file_range.uncompressed_size > compressed_file_range.compressed_size, + "decompressed size is greater than compressed size" + ); + } else { + assert_eq!( + compressed_file_range.format, + object::CompressionFormat::None + ); + assert_eq!(compressed_file_range.compressed_size, size); + } + } + } +} diff --git a/vendor/object/tests/read/mod.rs b/vendor/object/tests/read/mod.rs new file mode 100644 index 00000000..48e005ee --- /dev/null +++ b/vendor/object/tests/read/mod.rs @@ -0,0 +1,5 @@ +#![cfg(feature = "read")] + +mod coff; +mod elf; +mod macho; diff --git a/vendor/object/tests/round_trip/bss.rs b/vendor/object/tests/round_trip/bss.rs new file mode 100644 index 00000000..e13003d5 --- /dev/null +++ b/vendor/object/tests/round_trip/bss.rs @@ -0,0 +1,256 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection, ObjectSymbol}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, +}; + +#[test] +fn coff_x86_64_bss() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let _bss_section_symbol = object.section_symbol(section); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Ok(".bss")); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(bss.data(), Ok(&[][..])); + + let section = sections.next(); + assert!(section.is_none(), "unexpected section {:?}", section); + + let mut symbols = object.symbols(); + + let section_symbol = symbols.next().unwrap(); + println!("{:?}", section_symbol); + assert_eq!(section_symbol.name(), Ok(".bss")); + assert_eq!(section_symbol.kind(), SymbolKind::Section); + assert_eq!(section_symbol.section_index(), Some(bss_index)); + assert_eq!(section_symbol.scope(), SymbolScope::Compilation); + assert!(!section_symbol.is_weak()); + assert!(!section_symbol.is_undefined()); + assert_eq!(section_symbol.address(), 0); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 24); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} + +#[test] +fn elf_x86_64_bss() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Ok(".bss")); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(bss.data(), Ok(&[][..])); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 18); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 24); + assert_eq!(symbol.size(), 34); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} + +#[test] +fn macho_x86_64_bss() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Ok("__bss")); + assert_eq!(bss.segment_name(), Ok(Some("__DATA"))); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(bss.data(), Ok(&[][..])); + + let section = sections.next(); + assert!(section.is_none(), "unexpected section {:?}", section); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 24); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} diff --git a/vendor/object/tests/round_trip/coff.rs b/vendor/object/tests/round_trip/coff.rs new file mode 100644 index 00000000..2b55788a --- /dev/null +++ b/vendor/object/tests/round_trip/coff.rs @@ -0,0 +1,58 @@ +use object::read::{Object, ObjectSection}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationFlags, RelocationKind, + SymbolFlags, SymbolKind, SymbolScope, +}; + +#[test] +fn reloc_overflow() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[0; 4], 4); + let symbol = object.add_symbol(write::Symbol { + name: b"f".to_vec(), + value: 0, + size: 4, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + for i in 0..0x10000 { + object + .add_relocation( + text, + write::Relocation { + offset: i, + symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + } + let bytes = object.write().unwrap(); + + //std::fs::write(&"reloc_overflow.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let section = object.sections().next().unwrap(); + assert_eq!(section.name(), Ok(".text")); + + let mut i = 0; + for (offset, _relocation) in section.relocations() { + assert_eq!(offset, i); + i += 1; + } + assert_eq!(i, 0x10000); +} diff --git a/vendor/object/tests/round_trip/comdat.rs b/vendor/object/tests/round_trip/comdat.rs new file mode 100644 index 00000000..88a2e79d --- /dev/null +++ b/vendor/object/tests/round_trip/comdat.rs @@ -0,0 +1,217 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::pe; +use object::read::{Object, ObjectComdat, ObjectSection, ObjectSymbol}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, ComdatKind, Endianness, SectionKind, SymbolFlags, SymbolKind, + SymbolScope, +}; + +#[test] +fn coff_x86_64_comdat() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let section1 = object.add_subsection(write::StandardSection::Text, b"s1"); + let offset = object.append_section_data(section1, &[0, 1, 2, 3], 4); + object.section_symbol(section1); + let section2 = object.add_subsection(write::StandardSection::Data, b"s1"); + object.append_section_data(section2, &[0, 1, 2, 3], 4); + object.section_symbol(section2); + + let symbol = object.add_symbol(write::Symbol { + name: b"s1".to_vec(), + value: offset, + size: 4, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(section1), + flags: SymbolFlags::None, + }); + + object.add_comdat(write::Comdat { + kind: ComdatKind::NoDuplicates, + symbol, + sections: vec![section1, section2], + }); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"comdat.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section1 = sections.next().unwrap(); + println!("{:?}", section1); + let section1_index = section1.index(); + assert_eq!(section1.name(), Ok(".text$s1")); + assert_eq!(section1.kind(), SectionKind::Text); + assert_eq!(section1.address(), 0); + assert_eq!(section1.size(), 4); + + let section2 = sections.next().unwrap(); + println!("{:?}", section2); + let section2_index = section2.index(); + assert_eq!(section2.name(), Ok(".data$s1")); + assert_eq!(section2.kind(), SectionKind::Data); + assert_eq!(section2.address(), 0); + assert_eq!(section2.size(), 4); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok(".text$s1")); + assert_eq!(symbol.kind(), SymbolKind::Section); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!( + symbol.flags(), + SymbolFlags::CoffSection { + selection: pe::IMAGE_COMDAT_SELECT_NODUPLICATES, + associative_section: None + } + ); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok(".data$s1")); + assert_eq!(symbol.kind(), SymbolKind::Section); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section2.index()) + ); + assert_eq!( + symbol.flags(), + SymbolFlags::CoffSection { + selection: pe::IMAGE_COMDAT_SELECT_ASSOCIATIVE, + associative_section: Some(section1_index) + } + ); + + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("s1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); + + let mut comdats = object.comdats(); + + let comdat = comdats.next().unwrap(); + println!("{:?}", comdat); + assert_eq!(comdat.kind(), ComdatKind::NoDuplicates); + assert_eq!(comdat.symbol(), symbol_index); + + let mut comdat_sections = comdat.sections(); + assert_eq!(comdat_sections.next(), Some(section1_index)); + assert_eq!(comdat_sections.next(), Some(section2_index)); + assert_eq!(comdat_sections.next(), None); +} + +#[test] +fn elf_x86_64_comdat() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let section1 = object.add_subsection(write::StandardSection::Text, b"s1"); + let offset = object.append_section_data(section1, &[0, 1, 2, 3], 4); + let section2 = object.add_subsection(write::StandardSection::Data, b"s1"); + object.append_section_data(section2, &[0, 1, 2, 3], 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"s1".to_vec(), + value: offset, + size: 4, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(section1), + flags: SymbolFlags::None, + }); + + object.add_comdat(write::Comdat { + kind: ComdatKind::Any, + symbol, + sections: vec![section1, section2], + }); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"comdat.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + assert_eq!(section.name(), Ok(".group")); + + let section1 = sections.next().unwrap(); + println!("{:?}", section1); + let section1_index = section1.index(); + assert_eq!(section1.name(), Ok(".text.s1")); + assert_eq!(section1.kind(), SectionKind::Text); + assert_eq!(section1.address(), 0); + assert_eq!(section1.size(), 4); + + let section2 = sections.next().unwrap(); + println!("{:?}", section2); + let section2_index = section2.index(); + assert_eq!(section2.name(), Ok(".data.s1")); + assert_eq!(section2.kind(), SectionKind::Data); + assert_eq!(section2.address(), 0); + assert_eq!(section2.size(), 4); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + let symbol_index = symbol.index(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("s1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!( + symbol.section(), + read::SymbolSection::Section(section1.index()) + ); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); + + let mut comdats = object.comdats(); + + let comdat = comdats.next().unwrap(); + println!("{:?}", comdat); + assert_eq!(comdat.kind(), ComdatKind::Any); + assert_eq!(comdat.symbol(), symbol_index); + + let mut comdat_sections = comdat.sections(); + assert_eq!(comdat_sections.next(), Some(section1_index)); + assert_eq!(comdat_sections.next(), Some(section2_index)); + assert_eq!(comdat_sections.next(), None); +} diff --git a/vendor/object/tests/round_trip/common.rs b/vendor/object/tests/round_trip/common.rs new file mode 100644 index 00000000..051688be --- /dev/null +++ b/vendor/object/tests/round_trip/common.rs @@ -0,0 +1,241 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection, ObjectSymbol}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, Endianness, SectionKind, SymbolFlags, SymbolKind, SymbolScope, +}; + +#[test] +fn coff_x86_64_common() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let symbol = write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 4, 4); + + let symbol = write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 8, 8); + + // Also check undefined symbols, which are very similar. + let symbol = write::Symbol { + name: b"v3".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_symbol(symbol); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"common.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section(), read::SymbolSection::Common); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 4); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section(), read::SymbolSection::Common); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 8); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v3")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section(), read::SymbolSection::Undefined); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 0); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} + +#[test] +fn elf_x86_64_common() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let symbol = write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 4, 4); + + let symbol = write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 8, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"common.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section(), read::SymbolSection::Common); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 4); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section(), read::SymbolSection::Common); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 8); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} + +#[test] +fn macho_x86_64_common() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + let symbol = write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 4, 4); + + let symbol = write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }; + object.add_common_symbol(symbol, 8, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"common.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let common = sections.next().unwrap(); + println!("{:?}", common); + let common_index = common.index(); + assert_eq!(common.name(), Ok("__common")); + assert_eq!(common.segment_name(), Ok(Some("__DATA"))); + assert_eq!(common.kind(), SectionKind::Common); + assert_eq!(common.size(), 16); + assert_eq!(common.data(), Ok(&[][..])); + + let section = sections.next(); + assert!(section.is_none(), "unexpected section {:?}", section); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(common_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 0); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(common_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.address(), 8); + + let symbol = symbols.next(); + assert!(symbol.is_none(), "unexpected symbol {:?}", symbol); +} diff --git a/vendor/object/tests/round_trip/elf.rs b/vendor/object/tests/round_trip/elf.rs new file mode 100644 index 00000000..2f3351ff --- /dev/null +++ b/vendor/object/tests/round_trip/elf.rs @@ -0,0 +1,302 @@ +use object::read::elf::{FileHeader, SectionHeader}; +use object::read::{Object, ObjectSection, ObjectSymbol}; +use object::{ + elf, read, write, Architecture, BinaryFormat, Endianness, LittleEndian, SectionIndex, + SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, U32, +}; +use std::io::Write; + +#[test] +fn symtab_shndx() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + for i in 0..0x10000 { + let name = format!("func{}", i).into_bytes(); + let section = object.add_subsection(write::StandardSection::Text, &name); + let offset = object.append_section_data(section, &[0xcc], 1); + object.add_symbol(write::Symbol { + name, + value: offset, + size: 1, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(section), + flags: SymbolFlags::None, + }); + } + let bytes = object.write().unwrap(); + + //std::fs::write(&"symtab_shndx.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + for symbol in object.symbols() { + assert_eq!( + symbol.section(), + SymbolSection::Section(SectionIndex(symbol.index().0)) + ); + } +} + +#[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 = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let text_section_id = object.add_section(vec![], b".text".to_vec(), SectionKind::Text); + let text_section = object.section_mut(text_section_id); + text_section.set_data(&[][..], 4096); + + let data_section_id = object.add_section(vec![], b".data".to_vec(), SectionKind::Data); + let data_section = object.section_mut(data_section_id); + data_section.set_data(&b"1234"[..], 16); + + 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 mut sections = object.sections(); + + let section = sections.next().unwrap(); + assert_eq!(section.name(), Ok(".text")); + assert_eq!(section.file_range(), Some((4096, 0))); + + let section = sections.next().unwrap(); + assert_eq!(section.name(), Ok(".data")); + assert_eq!(section.file_range(), Some((4096, 4))); +} + +#[cfg(feature = "compression")] +#[test] +fn compression_zlib() { + use object::read::ObjectSection; + use object::LittleEndian as LE; + + let data = b"test data data data"; + let len = data.len() as u64; + + let mut ch = object::elf::CompressionHeader64::<LE>::default(); + ch.ch_type.set(LE, object::elf::ELFCOMPRESS_ZLIB); + ch.ch_size.set(LE, len); + ch.ch_addralign.set(LE, 1); + + let mut buf = Vec::new(); + buf.write_all(object::bytes_of(&ch)).unwrap(); + let mut encoder = flate2::write::ZlibEncoder::new(buf, flate2::Compression::default()); + encoder.write_all(data).unwrap(); + let compressed = encoder.finish().unwrap(); + + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + let section = object.add_section( + Vec::new(), + b".debug_info".to_vec(), + object::SectionKind::Other, + ); + object.section_mut(section).set_data(compressed, 1); + object.section_mut(section).flags = object::SectionFlags::Elf { + sh_flags: object::elf::SHF_COMPRESSED.into(), + }; + let bytes = object.write().unwrap(); + + //std::fs::write(&"compression.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let section = object.section_by_name(".debug_info").unwrap(); + let uncompressed = section.uncompressed_data().unwrap(); + assert_eq!(data, &*uncompressed); +} + +#[cfg(feature = "compression")] +#[test] +fn compression_gnu() { + use object::read::ObjectSection; + use std::io::Write; + + let data = b"test data data data"; + let len = data.len() as u32; + + let mut buf = Vec::new(); + buf.write_all(b"ZLIB\0\0\0\0").unwrap(); + buf.write_all(&len.to_be_bytes()).unwrap(); + let mut encoder = flate2::write::ZlibEncoder::new(buf, flate2::Compression::default()); + encoder.write_all(data).unwrap(); + let compressed = encoder.finish().unwrap(); + + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + let section = object.add_section( + Vec::new(), + b".zdebug_info".to_vec(), + object::SectionKind::Other, + ); + object.section_mut(section).set_data(compressed, 1); + let bytes = object.write().unwrap(); + + //std::fs::write(&"compression.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let section = object.section_by_name(".zdebug_info").unwrap(); + let uncompressed = section.uncompressed_data().unwrap(); + assert_eq!(data, &*uncompressed); +} + +#[test] +fn note() { + let endian = Endianness::Little; + let mut object = write::Object::new(BinaryFormat::Elf, Architecture::X86_64, endian); + + // Add note section with align = 4. + let mut buffer = Vec::new(); + + buffer + .write_all(object::bytes_of(&elf::NoteHeader32 { + n_namesz: U32::new(endian, 6), + n_descsz: U32::new(endian, 11), + n_type: U32::new(endian, 1), + })) + .unwrap(); + buffer.write_all(b"name1\0\0\0").unwrap(); + buffer.write_all(b"descriptor\0\0").unwrap(); + + buffer + .write_all(object::bytes_of(&elf::NoteHeader32 { + n_namesz: U32::new(endian, 6), + n_descsz: U32::new(endian, 11), + n_type: U32::new(endian, 2), + })) + .unwrap(); + buffer.write_all(b"name2\0\0\0").unwrap(); + buffer.write_all(b"descriptor\0\0").unwrap(); + + let section = object.add_section(Vec::new(), b".note4".to_vec(), SectionKind::Note); + object.section_mut(section).set_data(buffer, 4); + + // Add note section with align = 8. + let mut buffer = Vec::new(); + + buffer + .write_all(object::bytes_of(&elf::NoteHeader32 { + n_namesz: U32::new(endian, 6), + n_descsz: U32::new(endian, 11), + n_type: U32::new(endian, 1), + })) + .unwrap(); + buffer.write_all(b"name1\0\0\0\0\0\0\0").unwrap(); + buffer.write_all(b"descriptor\0\0\0\0\0\0").unwrap(); + + buffer + .write_all(object::bytes_of(&elf::NoteHeader32 { + n_namesz: U32::new(endian, 4), + n_descsz: U32::new(endian, 11), + n_type: U32::new(endian, 2), + })) + .unwrap(); + buffer.write_all(b"abc\0").unwrap(); + buffer.write_all(b"descriptor\0\0\0\0\0\0").unwrap(); + + let section = object.add_section(Vec::new(), b".note8".to_vec(), SectionKind::Note); + object.section_mut(section).set_data(buffer, 8); + + let bytes = &*object.write().unwrap(); + + //std::fs::write(&"note.o", &bytes).unwrap(); + + let header = elf::FileHeader64::parse(bytes).unwrap(); + let endian: LittleEndian = header.endian().unwrap(); + let sections = header.sections(endian, bytes).unwrap(); + + let section = sections.section(SectionIndex(1)).unwrap(); + assert_eq!(sections.section_name(endian, section).unwrap(), b".note4"); + assert_eq!(section.sh_addralign(endian), 4); + let mut notes = section.notes(endian, bytes).unwrap().unwrap(); + let note = notes.next().unwrap().unwrap(); + assert_eq!(note.name(), b"name1"); + assert_eq!(note.desc(), b"descriptor\0"); + assert_eq!(note.n_type(endian), 1); + let note = notes.next().unwrap().unwrap(); + assert_eq!(note.name(), b"name2"); + assert_eq!(note.desc(), b"descriptor\0"); + assert_eq!(note.n_type(endian), 2); + assert!(notes.next().unwrap().is_none()); + + let section = sections.section(SectionIndex(2)).unwrap(); + assert_eq!(sections.section_name(endian, section).unwrap(), b".note8"); + assert_eq!(section.sh_addralign(endian), 8); + let mut notes = section.notes(endian, bytes).unwrap().unwrap(); + let note = notes.next().unwrap().unwrap(); + assert_eq!(note.name(), b"name1"); + assert_eq!(note.desc(), b"descriptor\0"); + assert_eq!(note.n_type(endian), 1); + let note = notes.next().unwrap().unwrap(); + assert_eq!(note.name(), b"abc"); + assert_eq!(note.desc(), b"descriptor\0"); + assert_eq!(note.n_type(endian), 2); + assert!(notes.next().unwrap().is_none()); +} + +#[test] +fn gnu_property() { + gnu_property_inner::<elf::FileHeader32<Endianness>>(Architecture::I386); + gnu_property_inner::<elf::FileHeader64<Endianness>>(Architecture::X86_64); +} + +fn gnu_property_inner<Elf: FileHeader<Endian = Endianness>>(architecture: Architecture) { + let endian = Endianness::Little; + let mut object = write::Object::new(BinaryFormat::Elf, architecture, endian); + object.add_elf_gnu_property_u32( + elf::GNU_PROPERTY_X86_FEATURE_1_AND, + elf::GNU_PROPERTY_X86_FEATURE_1_IBT | elf::GNU_PROPERTY_X86_FEATURE_1_SHSTK, + ); + + let bytes = &*object.write().unwrap(); + + //std::fs::write(&"note.o", &bytes).unwrap(); + + let header = Elf::parse(bytes).unwrap(); + assert_eq!(header.endian().unwrap(), endian); + let sections = header.sections(endian, bytes).unwrap(); + let section = sections.section(SectionIndex(1)).unwrap(); + assert_eq!( + sections.section_name(endian, section).unwrap(), + b".note.gnu.property" + ); + assert_eq!(section.sh_flags(endian).into(), u64::from(elf::SHF_ALLOC)); + let mut notes = section.notes(endian, bytes).unwrap().unwrap(); + let note = notes.next().unwrap().unwrap(); + let mut props = note.gnu_properties(endian).unwrap(); + let prop = props.next().unwrap().unwrap(); + assert_eq!(prop.pr_type(), elf::GNU_PROPERTY_X86_FEATURE_1_AND); + assert_eq!( + prop.data_u32(endian).unwrap(), + elf::GNU_PROPERTY_X86_FEATURE_1_IBT | elf::GNU_PROPERTY_X86_FEATURE_1_SHSTK + ); + assert!(props.next().unwrap().is_none()); + assert!(notes.next().unwrap().is_none()); +} diff --git a/vendor/object/tests/round_trip/macho.rs b/vendor/object/tests/round_trip/macho.rs new file mode 100644 index 00000000..d8ed0f89 --- /dev/null +++ b/vendor/object/tests/round_trip/macho.rs @@ -0,0 +1,64 @@ +use object::read::macho::MachHeader; +use object::read::{Object, ObjectSection}; +use object::{macho, read, write, Architecture, BinaryFormat, Endianness}; + +// Test that segment size is valid when the first section needs alignment. +#[test] +fn issue_286_segment_file_size() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[1; 30], 0x1000); + + let bytes = &*object.write().unwrap(); + let header = macho::MachHeader64::parse(bytes, 0).unwrap(); + let endian: Endianness = header.endian().unwrap(); + let mut commands = header.load_commands(endian, bytes, 0).unwrap(); + let command = commands.next().unwrap().unwrap(); + let (segment, _) = command.segment_64().unwrap().unwrap(); + assert_eq!(segment.vmsize.get(endian), 30); + assert_eq!(segment.filesize.get(endian), 30); +} + +// We were emitting section file alignment padding that didn't match the address alignment padding. +#[test] +fn issue_552_section_file_alignment() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + // The starting file offset is not a multiple of 32 (checked later). + // Length of 32 ensures that the file offset of the end of this section is still not a + // multiple of 32. + let section = object.add_section(vec![], vec![], object::SectionKind::ReadOnlyDataWithRel); + object.append_section_data(section, &[0u8; 32], 1); + + // Address is already aligned correctly, so there must not any padding, + // even though file offset is not aligned. + let section = object.add_section(vec![], vec![], object::SectionKind::ReadOnlyData); + object.append_section_data(section, &[0u8; 1], 32); + + let bytes = &*object.write().unwrap(); + //std::fs::write(&"align.o", &bytes).unwrap(); + let object = read::File::parse(bytes).unwrap(); + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + let offset = section.file_range().unwrap().0; + // Check file offset is not aligned to 32. + assert_ne!(offset % 32, 0); + assert_eq!(section.address(), 0); + assert_eq!(section.size(), 32); + + let section = sections.next().unwrap(); + // Check there is no padding. + assert_eq!(section.file_range(), Some((offset + 32, 1))); + assert_eq!(section.address(), 32); + assert_eq!(section.size(), 1); +} diff --git a/vendor/object/tests/round_trip/mod.rs b/vendor/object/tests/round_trip/mod.rs new file mode 100644 index 00000000..91f3ce6d --- /dev/null +++ b/vendor/object/tests/round_trip/mod.rs @@ -0,0 +1,686 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection, ObjectSymbol}; +use object::{read, write, SectionIndex, SubArchitecture}; +use object::{ + Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationFlags, RelocationKind, + SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, +}; + +mod bss; +mod coff; +mod comdat; +mod common; +mod elf; +mod macho; +mod section_flags; +mod tls; + +#[test] +fn coff_any() { + for (arch, sub_arch) in [ + (Architecture::Aarch64, None), + (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)), + (Architecture::Arm, None), + (Architecture::I386, None), + (Architecture::X86_64, None), + ] + .iter() + .copied() + { + let mut object = write::Object::new(BinaryFormat::Coff, arch, Endianness::Little); + object.set_sub_architecture(sub_arch); + + object.add_file_symbol(b"file.c".to_vec()); + + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[1; 30], 4); + + let func1_offset = object.append_section_data(text, &[1; 30], 4); + assert_eq!(func1_offset, 32); + let func1_symbol = object.add_symbol(write::Symbol { + name: b"func1".to_vec(), + value: func1_offset, + size: 32, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + let func2_offset = object.append_section_data(text, &[1; 30], 4); + assert_eq!(func2_offset, 64); + object.add_symbol(write::Symbol { + name: b"func2_long".to_vec(), + value: func2_offset, + size: 32, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + object + .add_relocation( + text, + write::Relocation { + offset: 8, + symbol: func1_symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: arch.address_size().unwrap().bytes() * 8, + }, + }, + ) + .unwrap(); + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), arch); + assert_eq!(object.sub_architecture(), sub_arch); + assert_eq!(object.endianness(), Endianness::Little); + + let mut sections = object.sections(); + + let text = sections.next().unwrap(); + println!("{:?}", text); + let text_index = text.index(); + assert_eq!(text.name(), Ok(".text")); + assert_eq!(text.kind(), SectionKind::Text); + assert_eq!(text.address(), 0); + assert_eq!(text.size(), 94); + assert_eq!(&text.data().unwrap()[..30], &[1; 30]); + assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("file.c")); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.kind(), SymbolKind::File); + assert_eq!(symbol.section(), SymbolSection::None); + assert_eq!(symbol.scope(), SymbolScope::Compilation); + assert!(!symbol.is_weak()); + + let decorated_name = |name: &str| { + if arch == Architecture::I386 { + format!("_{name}") + } else { + name.to_owned() + } + }; + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok(decorated_name("func1").as_str())); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.kind(), SymbolKind::Text); + assert_eq!(symbol.section_index(), Some(text_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok(decorated_name("func2_long").as_str())); + assert_eq!(symbol.address(), func2_offset); + assert_eq!(symbol.kind(), SymbolKind::Text); + assert_eq!(symbol.section_index(), Some(text_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let mut relocations = text.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), arch.address_size().unwrap().bytes() * 8); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(func1_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), decorated_name("func1")); + assert_eq!(map.get(func1_offset - 1), None); + } +} + +#[test] +fn elf_x86_64() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + object.add_file_symbol(b"file.c".to_vec()); + + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[1; 30], 4); + + let func1_offset = object.append_section_data(text, &[1; 30], 4); + assert_eq!(func1_offset, 32); + let func1_symbol = object.add_symbol(write::Symbol { + name: b"func1".to_vec(), + value: func1_offset, + size: 32, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + object + .add_relocation( + text, + write::Relocation { + offset: 8, + symbol: func1_symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + + 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); + assert_eq!(object.endianness(), Endianness::Little); + + let mut sections = object.sections(); + + let text = sections.next().unwrap(); + println!("{:?}", text); + let text_index = text.index(); + assert_eq!(text.name(), Ok(".text")); + assert_eq!(text.kind(), SectionKind::Text); + assert_eq!(text.address(), 0); + assert_eq!(text.size(), 62); + assert_eq!(&text.data().unwrap()[..30], &[1; 30]); + assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("file.c")); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.kind(), SymbolKind::File); + assert_eq!(symbol.section(), SymbolSection::None); + assert_eq!(symbol.scope(), SymbolScope::Compilation); + assert!(!symbol.is_weak()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.kind(), SymbolKind::Text); + assert_eq!(symbol.section_index(), Some(text_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let mut relocations = text.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(func1_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "func1"); + assert_eq!(map.get(func1_offset - 1), None); +} + +#[test] +fn elf_any() { + for (arch, endian) in [ + (Architecture::Aarch64, Endianness::Little), + (Architecture::Aarch64_Ilp32, Endianness::Little), + (Architecture::Arm, Endianness::Little), + (Architecture::Avr, Endianness::Little), + (Architecture::Bpf, Endianness::Little), + (Architecture::Csky, Endianness::Little), + (Architecture::E2K32, Endianness::Little), + (Architecture::E2K64, Endianness::Little), + (Architecture::I386, Endianness::Little), + (Architecture::X86_64, Endianness::Little), + (Architecture::X86_64_X32, Endianness::Little), + (Architecture::Hexagon, Endianness::Little), + (Architecture::LoongArch64, Endianness::Little), + (Architecture::M68k, Endianness::Big), + (Architecture::Mips, Endianness::Little), + (Architecture::Mips64, Endianness::Little), + (Architecture::Mips64_N32, Endianness::Little), + (Architecture::Msp430, Endianness::Little), + (Architecture::PowerPc, Endianness::Big), + (Architecture::PowerPc64, Endianness::Big), + (Architecture::Riscv32, Endianness::Little), + (Architecture::Riscv64, Endianness::Little), + (Architecture::S390x, Endianness::Big), + (Architecture::Sbf, Endianness::Little), + (Architecture::Sparc, Endianness::Big), + (Architecture::Sparc32Plus, Endianness::Big), + (Architecture::Sparc64, Endianness::Big), + (Architecture::Xtensa, Endianness::Little), + ] + .iter() + .copied() + { + let mut object = write::Object::new(BinaryFormat::Elf, arch, endian); + + let section = object.section_id(write::StandardSection::Data); + object.append_section_data(section, &[1; 30], 4); + let symbol = object.section_symbol(section); + + object + .add_relocation( + section, + write::Relocation { + offset: 8, + symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 32, + }, + }, + ) + .unwrap(); + if arch.address_size().unwrap().bytes() >= 8 { + object + .add_relocation( + section, + write::Relocation { + offset: 16, + symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + } + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + println!("{:?}", object.architecture()); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), arch); + assert_eq!(object.endianness(), endian); + + let mut sections = object.sections(); + + let data = sections.next().unwrap(); + println!("{:?}", data); + assert_eq!(data.name(), Ok(".data")); + assert_eq!(data.kind(), SectionKind::Data); + + let mut relocations = data.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 32); + assert_eq!(relocation.addend(), 0); + + if arch.address_size().unwrap().bytes() >= 8 { + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 16); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!(relocation.addend(), 0); + } + } +} + +#[test] +fn macho_x86_64() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + object.add_file_symbol(b"file.c".to_vec()); + + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[1; 30], 4); + + let func1_offset = object.append_section_data(text, &[1; 30], 4); + assert_eq!(func1_offset, 32); + let func1_symbol = object.add_symbol(write::Symbol { + name: b"func1".to_vec(), + value: func1_offset, + size: 32, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + object + .add_relocation( + text, + write::Relocation { + offset: 8, + symbol: func1_symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + object + .add_relocation( + text, + write::Relocation { + offset: 16, + symbol: func1_symbol, + addend: -4, + flags: RelocationFlags::Generic { + kind: RelocationKind::Relative, + encoding: RelocationEncoding::Generic, + size: 32, + }, + }, + ) + .unwrap(); + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), Architecture::X86_64); + assert_eq!(object.endianness(), Endianness::Little); + + let mut sections = object.sections(); + + let text = sections.next().unwrap(); + println!("{:?}", text); + let text_index = text.index(); + assert_eq!(text.name(), Ok("__text")); + assert_eq!(text.segment_name(), Ok(Some("__TEXT"))); + assert_eq!(text.kind(), SectionKind::Text); + assert_eq!(text.address(), 0); + assert_eq!(text.size(), 62); + assert_eq!(&text.data().unwrap()[..30], &[1; 30]); + assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_func1")); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.kind(), SymbolKind::Text); + assert_eq!(symbol.section_index(), Some(text_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let mut relocations = text.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 16); + assert_eq!(relocation.kind(), RelocationKind::Relative); + assert_eq!(relocation.encoding(), RelocationEncoding::X86RipRelative); + assert_eq!(relocation.size(), 32); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(func1_symbol) + ); + assert_eq!(relocation.addend(), -4); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(func1_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let map = object.symbol_map(); + let symbol = map.get(func1_offset + 1).unwrap(); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.name(), "_func1"); + assert_eq!(map.get(func1_offset - 1), None); +} + +#[test] +fn macho_any() { + for (arch, subarch, endian) in [ + (Architecture::Aarch64, None, Endianness::Little), + ( + Architecture::Aarch64, + Some(SubArchitecture::Arm64E), + Endianness::Little, + ), + (Architecture::Aarch64_Ilp32, None, Endianness::Little), + /* TODO: + (Architecture::Arm, None, Endianness::Little), + */ + (Architecture::I386, None, Endianness::Little), + (Architecture::X86_64, None, Endianness::Little), + /* TODO: + (Architecture::PowerPc, None, Endianness::Big), + (Architecture::PowerPc64, None, Endianness::Big), + */ + ] + .iter() + .copied() + { + let mut object = write::Object::new(BinaryFormat::MachO, arch, endian); + object.set_sub_architecture(subarch); + + let section = object.section_id(write::StandardSection::Data); + object.append_section_data(section, &[1; 30], 4); + let symbol = object.section_symbol(section); + + object + .add_relocation( + section, + write::Relocation { + offset: 8, + symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 32, + }, + }, + ) + .unwrap(); + if arch.address_size().unwrap().bytes() >= 8 { + object + .add_relocation( + section, + write::Relocation { + offset: 16, + symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + } + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + println!("{:?}", object.architecture()); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), arch); + assert_eq!(object.sub_architecture(), subarch); + assert_eq!(object.endianness(), endian); + + let mut sections = object.sections(); + + let data = sections.next().unwrap(); + println!("{:?}", data); + assert_eq!(data.segment_name(), Ok(Some("__DATA"))); + assert_eq!(data.name(), Ok("__data")); + assert_eq!(data.kind(), SectionKind::Data); + + let mut relocations = data.relocations(); + + if arch.address_size().unwrap().bytes() >= 8 { + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 16); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!(relocation.addend(), 0); + } + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 32); + assert_eq!(relocation.addend(), 0); + } +} + +#[cfg(feature = "xcoff")] +#[test] +fn xcoff_powerpc() { + for arch in [Architecture::PowerPc, Architecture::PowerPc64] { + let mut object = write::Object::new(BinaryFormat::Xcoff, arch, Endianness::Big); + + object.add_file_symbol(b"file.c".to_vec()); + + let text = object.section_id(write::StandardSection::Text); + object.append_section_data(text, &[1; 30], 4); + + let func1_offset = object.append_section_data(text, &[1; 30], 4); + assert_eq!(func1_offset, 32); + let func1_symbol = object.add_symbol(write::Symbol { + name: b"func1".to_vec(), + value: func1_offset, + size: 32, + kind: SymbolKind::Text, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, + }); + + object + .add_relocation( + text, + write::Relocation { + offset: 8, + symbol: func1_symbol, + addend: 0, + flags: RelocationFlags::Generic { + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + size: 64, + }, + }, + ) + .unwrap(); + + let bytes = object.write().unwrap(); + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Xcoff); + assert_eq!(object.architecture(), arch); + assert_eq!(object.endianness(), Endianness::Big); + + let mut sections = object.sections(); + + let text = sections.next().unwrap(); + println!("{:?}", text); + let text_index = text.index().0; + assert_eq!(text.name(), Ok(".text")); + assert_eq!(text.kind(), SectionKind::Text); + assert_eq!(text.address(), 0); + assert_eq!(text.size(), 62); + assert_eq!(&text.data().unwrap()[..30], &[1; 30]); + assert_eq!(&text.data().unwrap()[32..62], &[1; 30]); + + let mut symbols = object.symbols(); + + let mut symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("file.c")); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.kind(), SymbolKind::File); + assert_eq!(symbol.section_index(), None); + assert_eq!(symbol.scope(), SymbolScope::Compilation); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let func1_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("func1")); + assert_eq!(symbol.address(), func1_offset); + assert_eq!(symbol.kind(), SymbolKind::Text); + assert_eq!(symbol.section_index(), Some(SectionIndex(text_index))); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let mut relocations = text.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 8); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(func1_symbol) + ); + assert_eq!(relocation.addend(), 0); + } +} diff --git a/vendor/object/tests/round_trip/section_flags.rs b/vendor/object/tests/round_trip/section_flags.rs new file mode 100644 index 00000000..791ba8f5 --- /dev/null +++ b/vendor/object/tests/round_trip/section_flags.rs @@ -0,0 +1,89 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection}; +use object::{read, write}; +use object::{Architecture, BinaryFormat, Endianness, SectionFlags, SectionKind}; + +#[test] +fn coff_x86_64_section_flags() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let section = object.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); + object.section_mut(section).flags = SectionFlags::Coff { + characteristics: object::pe::IMAGE_SCN_MEM_WRITE, + }; + + let bytes = object.write().unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + let section = sections.next().unwrap(); + assert_eq!(section.name(), Ok(".text")); + assert_eq!( + section.flags(), + SectionFlags::Coff { + characteristics: object::pe::IMAGE_SCN_MEM_WRITE | object::pe::IMAGE_SCN_ALIGN_1BYTES, + } + ); +} + +#[test] +fn elf_x86_64_section_flags() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let section = object.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); + object.section_mut(section).flags = SectionFlags::Elf { + sh_flags: object::elf::SHF_WRITE.into(), + }; + + 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 mut sections = object.sections(); + let section = sections.next().unwrap(); + assert_eq!(section.name(), Ok(".text")); + assert_eq!( + section.flags(), + SectionFlags::Elf { + sh_flags: object::elf::SHF_WRITE.into(), + } + ); +} + +#[test] +fn macho_x86_64_section_flags() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + let section = object.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); + object.section_mut(section).flags = SectionFlags::MachO { + flags: object::macho::S_ATTR_SELF_MODIFYING_CODE, + }; + + let bytes = object.write().unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + let section = sections.next().unwrap(); + assert_eq!(section.name(), Ok(".text")); + assert_eq!( + section.flags(), + SectionFlags::MachO { + flags: object::macho::S_ATTR_SELF_MODIFYING_CODE, + } + ); +} diff --git a/vendor/object/tests/round_trip/tls.rs b/vendor/object/tests/round_trip/tls.rs new file mode 100644 index 00000000..fa410967 --- /dev/null +++ b/vendor/object/tests/round_trip/tls.rs @@ -0,0 +1,308 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection, ObjectSymbol}; +use object::{read, write}; +use object::{ + Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, + SymbolFlags, SymbolKind, SymbolScope, +}; + +#[test] +fn coff_x86_64_tls() { + let mut object = + write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); + + let section = object.section_id(write::StandardSection::Tls); + let symbol = object.add_symbol(write::Symbol { + name: b"tls1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Tls, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_data(symbol, section, &[1; 30], 4); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"tls.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + let tls_index = section.index(); + assert_eq!(section.name(), Ok(".tls$")); + assert_eq!(section.kind(), SectionKind::Data); + assert_eq!(section.size(), 30); + assert_eq!(section.data().unwrap(), &[1; 30]); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("tls1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(tls_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); +} + +#[test] +fn elf_x86_64_tls() { + let mut object = + write::Object::new(BinaryFormat::Elf, Architecture::X86_64, Endianness::Little); + + let section = object.section_id(write::StandardSection::Tls); + let symbol = object.add_symbol(write::Symbol { + name: b"tls1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Tls, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_data(symbol, section, &[1; 30], 4); + + let section = object.section_id(write::StandardSection::UninitializedTls); + let symbol = object.add_symbol(write::Symbol { + name: b"tls2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Tls, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 31, 4); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"tls.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + let tdata_index = section.index(); + assert_eq!(section.name(), Ok(".tdata")); + assert_eq!(section.kind(), SectionKind::Tls); + assert_eq!(section.size(), 30); + assert_eq!(section.data().unwrap(), &[1; 30]); + + let section = sections.next().unwrap(); + println!("{:?}", section); + let tbss_index = section.index(); + assert_eq!(section.name(), Ok(".tbss")); + assert_eq!(section.kind(), SectionKind::UninitializedTls); + assert_eq!(section.size(), 31); + assert_eq!(section.data().unwrap(), &[]); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("tls1")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(tdata_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.size(), 30); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("tls2")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(tbss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + assert_eq!(symbol.size(), 31); +} + +#[test] +fn macho_x86_64_tls() { + let mut object = write::Object::new( + BinaryFormat::MachO, + Architecture::X86_64, + Endianness::Little, + ); + + let section = object.section_id(write::StandardSection::Tls); + let symbol = object.add_symbol(write::Symbol { + name: b"tls1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Tls, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_data(symbol, section, &[1; 30], 4); + + let section = object.section_id(write::StandardSection::UninitializedTls); + let symbol = object.add_symbol(write::Symbol { + name: b"tls2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Tls, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 31, 4); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"tls.o", &bytes).unwrap(); + + let object = read::File::parse(&*bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::MachO); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let thread_data = sections.next().unwrap(); + println!("{:?}", thread_data); + let thread_data_index = thread_data.index(); + assert_eq!(thread_data.name(), Ok("__thread_data")); + assert_eq!(thread_data.segment_name(), Ok(Some("__DATA"))); + assert_eq!(thread_data.kind(), SectionKind::Tls); + assert_eq!(thread_data.size(), 30); + assert_eq!(thread_data.data().unwrap(), &[1; 30]); + + let thread_vars = sections.next().unwrap(); + println!("{:?}", thread_vars); + let thread_vars_index = thread_vars.index(); + assert_eq!(thread_vars.name(), Ok("__thread_vars")); + assert_eq!(thread_vars.segment_name(), Ok(Some("__DATA"))); + assert_eq!(thread_vars.kind(), SectionKind::TlsVariables); + assert_eq!(thread_vars.size(), 2 * 3 * 8); + assert_eq!(thread_vars.data().unwrap(), &[0; 48]); + + let thread_bss = sections.next().unwrap(); + println!("{:?}", thread_bss); + let thread_bss_index = thread_bss.index(); + assert_eq!(thread_bss.name(), Ok("__thread_bss")); + assert_eq!(thread_bss.segment_name(), Ok(Some("__DATA"))); + assert_eq!(thread_bss.kind(), SectionKind::UninitializedTls); + assert_eq!(thread_bss.size(), 31); + assert_eq!(thread_bss.data(), Ok(&[][..])); + + let mut symbols = object.symbols(); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let tls1_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls1$tlv$init")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(thread_data_index)); + assert_eq!(symbol.scope(), SymbolScope::Compilation); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let tls2_init_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("_tls2$tlv$init")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(thread_bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Compilation); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_tls1")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(thread_vars_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Ok("_tls2")); + assert_eq!(symbol.kind(), SymbolKind::Tls); + assert_eq!(symbol.section_index(), Some(thread_vars_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert!(!symbol.is_weak()); + assert!(!symbol.is_undefined()); + + let symbol = symbols.next().unwrap(); + println!("{:?}", symbol); + let tlv_bootstrap_symbol = symbol.index(); + assert_eq!(symbol.name(), Ok("__tlv_bootstrap")); + assert_eq!(symbol.kind(), SymbolKind::Unknown); + assert_eq!(symbol.section_index(), None); + assert_eq!(symbol.scope(), SymbolScope::Unknown); + assert!(!symbol.is_weak()); + assert!(symbol.is_undefined()); + + let mut relocations = thread_vars.relocations(); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 40); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(tls2_init_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 24); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(tlv_bootstrap_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 16); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(tls1_init_symbol) + ); + assert_eq!(relocation.addend(), 0); + + let (offset, relocation) = relocations.next().unwrap(); + println!("{:?}", relocation); + assert_eq!(offset, 0); + assert_eq!(relocation.kind(), RelocationKind::Absolute); + assert_eq!(relocation.encoding(), RelocationEncoding::Generic); + assert_eq!(relocation.size(), 64); + assert_eq!( + relocation.target(), + read::RelocationTarget::Symbol(tlv_bootstrap_symbol) + ); + assert_eq!(relocation.addend(), 0); +} |
