Skip to content

Commit

Permalink
pe/coff: Add support for ARM64EC (#607)
Browse files Browse the repository at this point in the history
  • Loading branch information
dpaoliello authored Dec 12, 2023
1 parent a9322df commit f242fe7
Show file tree
Hide file tree
Showing 18 changed files with 261 additions and 168 deletions.
6 changes: 6 additions & 0 deletions crates/examples/src/objdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ fn dump_parsed_object<W: Write, E: Write>(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,
Expand Down Expand Up @@ -268,6 +271,9 @@ fn dump_import<W: Write, E: Write>(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: ")?;
Expand Down
1 change: 1 addition & 0 deletions crates/examples/src/readobj/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ const FLAGS_IMAGE_FILE_MACHINE: &[Flag<u16>] = &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,
Expand Down
3 changes: 2 additions & 1 deletion crates/examples/testfiles/coff/import_msvc.lib.objdump
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion crates/examples/testfiles/coff/import_msvc.lib.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
2 changes: 2 additions & 0 deletions src/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/read/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -323,6 +323,10 @@ where
with_inner!(self, File, |x| x.architecture())
}

fn sub_architecture(&self) -> Option<SubArchitecture> {
with_inner!(self, File, |x| x.sub_architecture())
}

fn is_little_endian(&self) -> bool {
with_inner!(self, File, |x| x.is_little_endian())
}
Expand Down
11 changes: 9 additions & 2 deletions src/read/coff/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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<SubArchitecture> {
match self.header.machine() {
pe::IMAGE_FILE_MACHINE_ARM64EC => Some(SubArchitecture::Arm64EC),
_ => None,
}
}

#[inline]
fn is_little_endian(&self) -> bool {
true
Expand Down
12 changes: 10 additions & 2 deletions src/read/coff/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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<SubArchitecture> {
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
Expand Down
20 changes: 11 additions & 9 deletions src/read/coff/relocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ impl FileKind {
[0xc4, 0x01, ..]
// COFF arm64
| [0x64, 0xaa, ..]
// COFF arm64ec
| [0x41, 0xa6, ..]
// COFF x86
| [0x4c, 0x01, ..]
// COFF x86-64
Expand Down
11 changes: 9 additions & 2 deletions src/read/pe/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<SubArchitecture> {
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.
Expand Down
9 changes: 7 additions & 2 deletions src/read/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<SubArchitecture> {
None
}

/// Get the endianness of the file.
#[inline]
fn endianness(&self) -> Endianness {
Expand Down
17 changes: 10 additions & 7 deletions src/write/coff/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
)));
}
},
Expand Down
52 changes: 26 additions & 26 deletions src/write/elf/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
)));
}
};
Expand Down
24 changes: 14 additions & 10 deletions src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
)));
}
};
Expand Down
Loading

0 comments on commit f242fe7

Please sign in to comment.