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 2 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
19 changes: 13 additions & 6 deletions src/read/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ use crate::read::pe;
use crate::read::wasm;
#[cfg(feature = "xcoff")]
use crate::read::xcoff;
use crate::read::{
self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData, CompressedFileRange,
Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat, ObjectKind, ObjectMap,
ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadRef, Relocation, Result,
SectionFlags, SectionIndex, SectionKind, SegmentFlags, SymbolFlags, SymbolIndex, SymbolKind,
SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
use crate::{
read::{
self, Architecture, BinaryFormat, CodeView, ComdatKind, CompressedData,
CompressedFileRange, Error, Export, FileFlags, FileKind, Import, Object, ObjectComdat,
ObjectKind, ObjectMap, ObjectSection, ObjectSegment, ObjectSymbol, ObjectSymbolTable,
ReadRef, Relocation, Result, SectionFlags, SectionIndex, SectionKind, SegmentFlags,
SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
},
SubArchitecture,
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
};
#[allow(unused_imports)]
use crate::{AddressSize, Endian, Endianness};
Expand Down Expand Up @@ -323,6 +326,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
7 changes: 6 additions & 1 deletion src/write/coff/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,12 @@ impl<'a> Object<'a> {
writer.write_file_header(writer::FileHeader {
machine: match self.architecture {
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT,
Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64,
Architecture::Aarch64 => match self.sub_architecture {
None => coff::IMAGE_FILE_MACHINE_ARM64,
Some(SubArchitecture::Arm64EC) => coff::IMAGE_FILE_MACHINE_ARM64EC,
#[allow(unreachable_patterns)]
_ => unimplemented!(),
},
Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
_ => {
Expand Down
26 changes: 24 additions & 2 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Interface for writing object files.

use alloc::borrow::Cow;
use alloc::borrow::{Cow, ToOwned};
use alloc::string::String;
use alloc::vec::Vec;
use core::{fmt, result, str};
Expand All @@ -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")]
Expand Down Expand Up @@ -62,6 +62,7 @@ pub type Result<T> = result::Result<T, Error>;
pub struct Object<'a> {
format: BinaryFormat,
architecture: Architecture,
sub_architecture: Option<SubArchitecture>,
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
endian: Endianness,
sections: Vec<Section<'a>>,
standard_sections: HashMap<StandardSection, SectionId>,
Expand All @@ -88,6 +89,7 @@ impl<'a> Object<'a> {
Object {
format,
architecture,
sub_architecture: None,
endian,
sections: Vec::new(),
standard_sections: HashMap::new(),
Expand Down Expand Up @@ -117,6 +119,26 @@ impl<'a> Object<'a> {
self.architecture
}

/// Return the sub-architecture.
#[inline]
pub fn sub_architecture(&self) -> Option<SubArchitecture> {
self.sub_architecture
}

/// Specify the sub-architecture.
pub fn set_sub_architecture(
&mut self,
sub_architecture: Option<SubArchitecture>,
) -> Result<()> {
dpaoliello marked this conversation as resolved.
Show resolved Hide resolved
match (self.architecture, sub_architecture) {
(Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) | (_, None) => {
self.sub_architecture = sub_architecture;
Ok(())
}
_ => Err(Error("Unsupported sub-architecture".to_owned())),
}
}

/// Return the current mangling setting.
#[inline]
pub fn mangling(&self) -> Mangling {
Expand Down
Loading