diff --git a/crates/examples/src/objdump.rs b/crates/examples/src/objdump.rs index 2f229456..a9a56d3c 100644 --- a/crates/examples/src/objdump.rs +++ b/crates/examples/src/objdump.rs @@ -125,6 +125,9 @@ fn dump_parsed_object(w: &mut W, e: &mut E, file: &object::F )?; writeln!(w, "Kind: {:?}", file.kind())?; writeln!(w, "Architecture: {:?}", file.architecture())?; + if let Some(sub_architecture) = file.sub_architecture() { + writeln!(w, "Sub-Architecture: {:?}", sub_architecture)?; + } writeln!(w, "Flags: {:x?}", file.flags())?; writeln!( w, @@ -268,6 +271,9 @@ fn dump_import(w: &mut W, e: &mut E, data: &[u8]) -> Result< writeln!(w, "Format: Short Import File")?; writeln!(w, "Architecture: {:?}", file.architecture())?; + if let Some(sub_architecture) = file.sub_architecture() { + writeln!(w, "Sub-Architecture: {:?}", sub_architecture)?; + } writeln!(w, "DLL: {:?}", String::from_utf8_lossy(file.dll()))?; writeln!(w, "Symbol: {:?}", String::from_utf8_lossy(file.symbol()))?; write!(w, "Import: ")?; diff --git a/crates/examples/src/readobj/pe.rs b/crates/examples/src/readobj/pe.rs index 8744e960..6004bd55 100644 --- a/crates/examples/src/readobj/pe.rs +++ b/crates/examples/src/readobj/pe.rs @@ -795,6 +795,7 @@ const FLAGS_IMAGE_FILE_MACHINE: &[Flag] = &flags!( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_M32R, IMAGE_FILE_MACHINE_ARM64, + IMAGE_FILE_MACHINE_ARM64EC, IMAGE_FILE_MACHINE_CEE, IMAGE_FILE_MACHINE_RISCV32, IMAGE_FILE_MACHINE_RISCV64, diff --git a/crates/examples/testfiles/coff/import_msvc.lib.objdump b/crates/examples/testfiles/coff/import_msvc.lib.objdump index 4a5d1a01..c94f90e6 100644 --- a/crates/examples/testfiles/coff/import_msvc.lib.objdump +++ b/crates/examples/testfiles/coff/import_msvc.lib.objdump @@ -198,7 +198,8 @@ Symbol map test_arm64ec.dll: Format: Short Import File -Architecture: Unknown +Architecture: Aarch64 +Sub-Architecture: Arm64EC DLL: "test_arm64ec.dll" Symbol: "#foo_arm64ec" Import: Name("foo_arm64ec") diff --git a/crates/examples/testfiles/coff/import_msvc.lib.readobj b/crates/examples/testfiles/coff/import_msvc.lib.readobj index 673aba5c..81593ed8 100644 --- a/crates/examples/testfiles/coff/import_msvc.lib.readobj +++ b/crates/examples/testfiles/coff/import_msvc.lib.readobj @@ -727,7 +727,7 @@ ImportObjectHeader { Signature1: 0x0 Signature2: 0xFFFF Version: 0 - Machine: 0xA641 + Machine: IMAGE_FILE_MACHINE_ARM64EC (0xA641) TimeDateStamp: 1687268223 SizeOfData: 0x2A OrdinalOrHint: 0 diff --git a/src/common.rs b/src/common.rs index 37ccb4b9..427af1ad 100644 --- a/src/common.rs +++ b/src/common.rs @@ -33,6 +33,14 @@ pub enum Architecture { Xtensa, } +/// A CPU sub-architecture. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum SubArchitecture { + Arm64EC, +} + impl Architecture { /// The size of an address value for this architecture. /// diff --git a/src/pe.rs b/src/pe.rs index f274d227..64ccf069 100644 --- a/src/pe.rs +++ b/src/pe.rs @@ -359,6 +359,8 @@ pub const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664; pub const IMAGE_FILE_MACHINE_M32R: u16 = 0x9041; /// ARM64 Little-Endian pub const IMAGE_FILE_MACHINE_ARM64: u16 = 0xAA64; +/// ARM64EC ("Emulation Compatible") +pub const IMAGE_FILE_MACHINE_ARM64EC: u16 = 0xA641; pub const IMAGE_FILE_MACHINE_CEE: u16 = 0xC0EE; /// RISCV32 pub const IMAGE_FILE_MACHINE_RISCV32: u16 = 0x5032; diff --git a/src/read/any.rs b/src/read/any.rs index 2e147c67..254d7bd9 100644 --- a/src/read/any.rs +++ b/src/read/any.rs @@ -22,7 +22,7 @@ use crate::read::{ SymbolMap, SymbolMapName, SymbolScope, SymbolSection, }; #[allow(unused_imports)] -use crate::{AddressSize, Endian, Endianness}; +use crate::{AddressSize, Endian, Endianness, SubArchitecture}; /// Evaluate an expression on the contents of a file format enum. /// @@ -323,6 +323,10 @@ where with_inner!(self, File, |x| x.architecture()) } + fn sub_architecture(&self) -> Option { + with_inner!(self, File, |x| x.sub_architecture()) + } + fn is_little_endian(&self) -> bool { with_inner!(self, File, |x| x.is_little_endian()) } diff --git a/src/read/coff/file.rs b/src/read/coff/file.rs index 4219f8f0..a82e3105 100644 --- a/src/read/coff/file.rs +++ b/src/read/coff/file.rs @@ -3,7 +3,7 @@ use core::fmt::Debug; use crate::read::{ self, Architecture, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectKind, - ObjectSection, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, + ObjectSection, ReadError, ReadRef, Result, SectionIndex, SubArchitecture, SymbolIndex, }; use crate::{pe, LittleEndian as LE, Pod}; @@ -78,13 +78,20 @@ where fn architecture(&self) -> Architecture { match self.header.machine() { pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, - pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64, + pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, _ => Architecture::Unknown, } } + fn sub_architecture(&self) -> Option { + match self.header.machine() { + pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), + _ => None, + } + } + #[inline] fn is_little_endian(&self) -> bool { true diff --git a/src/read/coff/import.rs b/src/read/coff/import.rs index d635e759..e4c64004 100644 --- a/src/read/coff/import.rs +++ b/src/read/coff/import.rs @@ -4,7 +4,7 @@ //! dynamically imported symbols. use crate::read::{Architecture, Error, ReadError, ReadRef, Result}; -use crate::{pe, ByteString, Bytes, LittleEndian as LE}; +use crate::{pe, ByteString, Bytes, LittleEndian as LE, SubArchitecture}; /// A Windows short form description of a symbol to import. /// @@ -64,13 +64,21 @@ impl<'data> ImportFile<'data> { pub fn architecture(&self) -> Architecture { match self.header.machine.get(LE) { pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, - pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64, + pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, _ => Architecture::Unknown, } } + /// Get the sub machine type, if available. + pub fn sub_architecture(&self) -> Option { + match self.header.machine.get(LE) { + pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), + _ => None, + } + } + /// The public symbol name. pub fn symbol(&self) -> &'data [u8] { self.symbol.0 diff --git a/src/read/coff/relocation.rs b/src/read/coff/relocation.rs index 44d2c68d..85f769d0 100644 --- a/src/read/coff/relocation.rs +++ b/src/read/coff/relocation.rs @@ -40,15 +40,17 @@ impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator pe::IMAGE_REL_ARM_SECREL => (RelocationKind::SectionOffset, 32, 0), typ => (RelocationKind::Coff(typ), 0, 0), }, - pe::IMAGE_FILE_MACHINE_ARM64 => match relocation.typ.get(LE) { - pe::IMAGE_REL_ARM64_ADDR32 => (RelocationKind::Absolute, 32, 0), - pe::IMAGE_REL_ARM64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0), - pe::IMAGE_REL_ARM64_SECREL => (RelocationKind::SectionOffset, 32, 0), - pe::IMAGE_REL_ARM64_SECTION => (RelocationKind::SectionIndex, 16, 0), - pe::IMAGE_REL_ARM64_ADDR64 => (RelocationKind::Absolute, 64, 0), - pe::IMAGE_REL_ARM64_REL32 => (RelocationKind::Relative, 32, -4), - typ => (RelocationKind::Coff(typ), 0, 0), - }, + pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => { + match relocation.typ.get(LE) { + pe::IMAGE_REL_ARM64_ADDR32 => (RelocationKind::Absolute, 32, 0), + pe::IMAGE_REL_ARM64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0), + pe::IMAGE_REL_ARM64_SECREL => (RelocationKind::SectionOffset, 32, 0), + pe::IMAGE_REL_ARM64_SECTION => (RelocationKind::SectionIndex, 16, 0), + pe::IMAGE_REL_ARM64_ADDR64 => (RelocationKind::Absolute, 64, 0), + pe::IMAGE_REL_ARM64_REL32 => (RelocationKind::Relative, 32, -4), + typ => (RelocationKind::Coff(typ), 0, 0), + } + } pe::IMAGE_FILE_MACHINE_I386 => match relocation.typ.get(LE) { pe::IMAGE_REL_I386_DIR16 => (RelocationKind::Absolute, 16, 0), pe::IMAGE_REL_I386_REL16 => (RelocationKind::Relative, 16, 0), diff --git a/src/read/mod.rs b/src/read/mod.rs index cd887af1..809d5f73 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -252,6 +252,8 @@ impl FileKind { [0xc4, 0x01, ..] // COFF arm64 | [0x64, 0xaa, ..] + // COFF arm64ec + | [0x41, 0xa6, ..] // COFF x86 | [0x4c, 0x01, ..] // COFF x86-64 diff --git a/src/read/pe/file.rs b/src/read/pe/file.rs index 0f8ce9f2..fe234aa1 100644 --- a/src/read/pe/file.rs +++ b/src/read/pe/file.rs @@ -9,7 +9,7 @@ use crate::read::{ self, Architecture, ComdatKind, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectKind, ReadError, ReadRef, Result, SectionIndex, SymbolIndex, }; -use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, U32}; +use crate::{pe, ByteString, Bytes, CodeView, LittleEndian as LE, Pod, SubArchitecture, U32}; use super::{ DataDirectories, ExportTable, ImageThunkData, ImportTable, PeSection, PeSectionIterator, @@ -147,13 +147,20 @@ where fn architecture(&self) -> Architecture { match self.nt_headers.file_header().machine.get(LE) { pe::IMAGE_FILE_MACHINE_ARMNT => Architecture::Arm, - pe::IMAGE_FILE_MACHINE_ARM64 => Architecture::Aarch64, + pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => Architecture::Aarch64, pe::IMAGE_FILE_MACHINE_I386 => Architecture::I386, pe::IMAGE_FILE_MACHINE_AMD64 => Architecture::X86_64, _ => Architecture::Unknown, } } + fn sub_architecture(&self) -> Option { + match self.nt_headers.file_header().machine.get(LE) { + pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC), + _ => None, + } + } + #[inline] fn is_little_endian(&self) -> bool { // Only little endian is supported. diff --git a/src/read/traits.rs b/src/read/traits.rs index 36ab3e31..d2d0a2b2 100644 --- a/src/read/traits.rs +++ b/src/read/traits.rs @@ -4,8 +4,8 @@ use alloc::vec::Vec; use crate::read::{ self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export, FileFlags, Import, ObjectKind, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, - SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, - SymbolScope, SymbolSection, + SectionKind, SegmentFlags, SubArchitecture, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, + SymbolMapName, SymbolScope, SymbolSection, }; use crate::Endianness; @@ -51,6 +51,11 @@ pub trait Object<'data: 'file, 'file>: read::private::Sealed { /// Get the architecture type of the file. fn architecture(&self) -> Architecture; + /// Get the sub-architecture type of the file. + fn sub_architecture(&self) -> Option { + None + } + /// Get the endianness of the file. #[inline] fn endianness(&self) -> Endianness { diff --git a/src/write/coff/object.rs b/src/write/coff/object.rs index 225310ec..52296659 100644 --- a/src/write/coff/object.rs +++ b/src/write/coff/object.rs @@ -268,15 +268,18 @@ impl<'a> Object<'a> { // Start writing. writer.write_file_header(writer::FileHeader { - machine: match self.architecture { - Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT, - Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64, - Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386, - Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64, + machine: match (self.architecture, self.sub_architecture) { + (Architecture::Arm, None) => coff::IMAGE_FILE_MACHINE_ARMNT, + (Architecture::Aarch64, None) => coff::IMAGE_FILE_MACHINE_ARM64, + (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) => { + coff::IMAGE_FILE_MACHINE_ARM64EC + } + (Architecture::I386, None) => coff::IMAGE_FILE_MACHINE_I386, + (Architecture::X86_64, None) => coff::IMAGE_FILE_MACHINE_AMD64, _ => { return Err(Error(format!( - "unimplemented architecture {:?}", - self.architecture + "unimplemented architecture {:?} with sub-architecture {:?}", + self.architecture, self.sub_architecture ))); } }, diff --git a/src/write/elf/object.rs b/src/write/elf/object.rs index 02910cff..5d7a93e5 100644 --- a/src/write/elf/object.rs +++ b/src/write/elf/object.rs @@ -281,34 +281,34 @@ impl<'a> Object<'a> { // Start writing. let e_type = elf::ET_REL; - let e_machine = match self.architecture { - Architecture::Aarch64 => elf::EM_AARCH64, - Architecture::Aarch64_Ilp32 => elf::EM_AARCH64, - Architecture::Arm => elf::EM_ARM, - Architecture::Avr => elf::EM_AVR, - Architecture::Bpf => elf::EM_BPF, - Architecture::Csky => elf::EM_CSKY, - Architecture::I386 => elf::EM_386, - Architecture::X86_64 => elf::EM_X86_64, - Architecture::X86_64_X32 => elf::EM_X86_64, - Architecture::Hexagon => elf::EM_HEXAGON, - Architecture::LoongArch64 => elf::EM_LOONGARCH, - Architecture::Mips => elf::EM_MIPS, - Architecture::Mips64 => elf::EM_MIPS, - Architecture::Msp430 => elf::EM_MSP430, - Architecture::PowerPc => elf::EM_PPC, - Architecture::PowerPc64 => elf::EM_PPC64, - Architecture::Riscv32 => elf::EM_RISCV, - Architecture::Riscv64 => elf::EM_RISCV, - Architecture::S390x => elf::EM_S390, - Architecture::Sbf => elf::EM_SBF, - Architecture::Sharc => elf::EM_SHARC, - Architecture::Sparc64 => elf::EM_SPARCV9, - Architecture::Xtensa => elf::EM_XTENSA, + let e_machine = match (self.architecture, self.sub_architecture) { + (Architecture::Aarch64, None) => elf::EM_AARCH64, + (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, + (Architecture::Arm, None) => elf::EM_ARM, + (Architecture::Avr, None) => elf::EM_AVR, + (Architecture::Bpf, None) => elf::EM_BPF, + (Architecture::Csky, None) => elf::EM_CSKY, + (Architecture::I386, None) => elf::EM_386, + (Architecture::X86_64, None) => elf::EM_X86_64, + (Architecture::X86_64_X32, None) => elf::EM_X86_64, + (Architecture::Hexagon, None) => elf::EM_HEXAGON, + (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, + (Architecture::Mips, None) => elf::EM_MIPS, + (Architecture::Mips64, None) => elf::EM_MIPS, + (Architecture::Msp430, None) => elf::EM_MSP430, + (Architecture::PowerPc, None) => elf::EM_PPC, + (Architecture::PowerPc64, None) => elf::EM_PPC64, + (Architecture::Riscv32, None) => elf::EM_RISCV, + (Architecture::Riscv64, None) => elf::EM_RISCV, + (Architecture::S390x, None) => elf::EM_S390, + (Architecture::Sbf, None) => elf::EM_SBF, + (Architecture::Sharc, None) => elf::EM_SHARC, + (Architecture::Sparc64, None) => elf::EM_SPARCV9, + (Architecture::Xtensa, None) => elf::EM_XTENSA, _ => { return Err(Error(format!( - "unimplemented architecture {:?}", - self.architecture + "unimplemented architecture {:?} with sub-architecture {:?}", + self.architecture, self.sub_architecture ))); } }; diff --git a/src/write/macho.rs b/src/write/macho.rs index ccc88bd9..7942535a 100644 --- a/src/write/macho.rs +++ b/src/write/macho.rs @@ -470,20 +470,24 @@ impl<'a> Object<'a> { .map_err(|_| Error(String::from("Cannot allocate buffer")))?; // Write file header. - let (cputype, mut cpusubtype) = match self.architecture { - Architecture::Arm => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), - Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), - Architecture::Aarch64_Ilp32 => { + let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) { + (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), + (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), + (Architecture::Aarch64_Ilp32, None) => { (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8) } - Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), - Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), - Architecture::PowerPc => (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL), - Architecture::PowerPc64 => (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL), + (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), + (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), + (Architecture::PowerPc, None) => { + (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL) + } + (Architecture::PowerPc64, None) => { + (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL) + } _ => { return Err(Error(format!( - "unimplemented architecture {:?}", - self.architecture + "unimplemented architecture {:?} with sub-architecture {:?}", + self.architecture, self.sub_architecture ))); } }; diff --git a/src/write/mod.rs b/src/write/mod.rs index 8d3ef17e..cea4d2e7 100644 --- a/src/write/mod.rs +++ b/src/write/mod.rs @@ -12,7 +12,7 @@ use std::{boxed::Box, collections::HashMap, error, io}; use crate::endian::{Endianness, U32, U64}; use crate::{ Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind, - SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, + SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, }; #[cfg(feature = "coff")] @@ -62,6 +62,7 @@ pub type Result = result::Result; pub struct Object<'a> { format: BinaryFormat, architecture: Architecture, + sub_architecture: Option, endian: Endianness, sections: Vec>, standard_sections: HashMap, @@ -88,6 +89,7 @@ impl<'a> Object<'a> { Object { format, architecture, + sub_architecture: None, endian, sections: Vec::new(), standard_sections: HashMap::new(), @@ -117,6 +119,17 @@ impl<'a> Object<'a> { self.architecture } + /// Return the sub-architecture. + #[inline] + pub fn sub_architecture(&self) -> Option { + self.sub_architecture + } + + /// Specify the sub-architecture. + pub fn set_sub_architecture(&mut self, sub_architecture: Option) { + self.sub_architecture = sub_architecture; + } + /// Return the current mangling setting. #[inline] pub fn mangling(&self) -> Mangling { diff --git a/tests/round_trip/mod.rs b/tests/round_trip/mod.rs index 17b90608..91070b83 100644 --- a/tests/round_trip/mod.rs +++ b/tests/round_trip/mod.rs @@ -1,7 +1,7 @@ #![cfg(all(feature = "read", feature = "write"))] use object::read::{Object, ObjectSection, ObjectSymbol}; -use object::{read, write, SectionIndex}; +use object::{read, write, SectionIndex, SubArchitecture}; use object::{ Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope, SymbolSection, @@ -17,122 +17,142 @@ mod section_flags; mod tls; #[test] -fn coff_x86_64() { - let mut object = - write::Object::new(BinaryFormat::Coff, Architecture::X86_64, Endianness::Little); +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()); + 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 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, - size: 64, - kind: RelocationKind::Absolute, - encoding: RelocationEncoding::Generic, - symbol: func1_symbol, - addend: 0, - }, - ) - .unwrap(); + 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, + size: arch.address_size().unwrap().bytes() * 8, + kind: RelocationKind::Absolute, + encoding: RelocationEncoding::Generic, + symbol: func1_symbol, + addend: 0, + }, + ) + .unwrap(); - 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); - assert_eq!(object.endianness(), Endianness::Little); + 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 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 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 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_eq!(symbol.is_weak(), false); + 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_eq!(symbol.is_weak(), false); - 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_eq!(symbol.is_weak(), false); - assert_eq!(symbol.is_undefined(), false); + let decorated_name = |name: &str| { + if arch == Architecture::I386 { + format!("_{name}") + } else { + name.to_owned() + } + }; - let symbol = symbols.next().unwrap(); - println!("{:?}", symbol); - assert_eq!(symbol.name(), Ok("func2_long")); - 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_eq!(symbol.is_weak(), false); - assert_eq!(symbol.is_undefined(), false); + 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_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); - let mut relocations = text.relocations(); + 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_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); - 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 mut relocations = text.relocations(); - 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); + 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]