Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ARM64EC #607

Merged
merged 3 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
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