diff --git a/src/Abstract/ObjectHandle.jl b/src/Abstract/ObjectHandle.jl index 3331628..2f01662 100644 --- a/src/Abstract/ObjectHandle.jl +++ b/src/Abstract/ObjectHandle.jl @@ -44,6 +44,7 @@ where `oh <: COFFHandle`). - unpack() ### Format-specific properties + - *Platform()* - *endianness()* - *is64bit()* - *isrelocatable()* @@ -189,6 +190,12 @@ for f in [:skip, :seekstart, :eof, :read, :readuntil, :readbytes, :write] @eval $(f)(oh::H, args...) where {H<:ObjectHandle} = $(f)(iostream(oh), args...) end +""" + Platform(oh::ObjectHandle) + +Returns a `Platform` object representing the binary platform this object is built for. +""" +@mustimplement Platform(oh::ObjectHandle) """ endianness(oh::ObjectHandle) diff --git a/src/COFF/COFF.jl b/src/COFF/COFF.jl index 8b6edd3..68221d9 100644 --- a/src/COFF/COFF.jl +++ b/src/COFF/COFF.jl @@ -1,6 +1,7 @@ module COFF -using StructIO +using StructIO, Base.BinaryPlatforms +import Base.BinaryPlatforms: Platform # Bring in ObjectFile definitions using ObjectFile diff --git a/src/COFF/COFFHandle.jl b/src/COFF/COFFHandle.jl index ac28f26..3290753 100644 --- a/src/COFF/COFFHandle.jl +++ b/src/COFF/COFFHandle.jl @@ -73,6 +73,7 @@ iostream(oh::COFFHandle) = oh.io ## Format-specific properties: header(oh::COFFHandle) = oh.header +Platform(oh::COFFHandle) = Platform(coff_machine_to_arch(oh.header.Machine), "windows") endianness(oh::COFFHandle) = coff_header_endianness(header(oh)) is64bit(oh::COFFHandle) = coff_header_is64bit(header(oh)) isrelocatable(oh::COFFHandle) = isrelocatable(header(oh)) diff --git a/src/COFF/constants.jl b/src/COFF/constants.jl index 2a2c741..d1569bd 100644 --- a/src/COFF/constants.jl +++ b/src/COFF/constants.jl @@ -24,6 +24,20 @@ const IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169 # MIPS little-endian WCE v2 end +function coff_machine_to_arch(machine::UInt16) + if machine ∈ (IMAGE_FILE_MACHINE_I386,) + return "i686" + elseif machine ∈ (IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64) + return "x86_64" + elseif machine ∈ (IMAGE_FILE_MACHINE_ARM, IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_THUMB) + return "armv7l" + elseif machine ∈ (IMAGE_FILE_MACHINE_ARM64,) + return "aarch64" + elseif machine ∈ (IMAGE_FILE_MACHINE_POWERPC,) + return "ppc64le" + end +end + # # # Characteristics @constants IMAGE_FILE_CHARACTERISTICS "IMAGE_FILE_" begin diff --git a/src/ELF/ELF.jl b/src/ELF/ELF.jl index 7f063b4..200998a 100644 --- a/src/ELF/ELF.jl +++ b/src/ELF/ELF.jl @@ -1,6 +1,7 @@ module ELF -using StructIO +using StructIO, Base.BinaryPlatforms +import Base.BinaryPlatforms: Platform # Bring in ObjectFile definitions using ObjectFile diff --git a/src/ELF/ELFHandle.jl b/src/ELF/ELFHandle.jl index afcfbea..2bebde6 100644 --- a/src/ELF/ELFHandle.jl +++ b/src/ELF/ELFHandle.jl @@ -64,9 +64,15 @@ end startaddr(oh::ELFHandle) = oh.start iostream(oh::ELFHandle) = oh.io +# We don't try to inspect dynamic libraries to figure out if this is a glibc or musl dynamic object +function strip_libc_tag(p::Platform) + delete!(tags(p), "libc") + return p +end ## Format-specific properties: header(oh::ELFHandle) = oh.header +Platform(oh::ELFHandle) = strip_libc_tag(Platform(elf_machine_to_arch(oh.header.e_machine), "linux")) endianness(oh::ELFHandle) = elf_internal_endianness(oh.ei) is64bit(oh::ELFHandle) = elf_internal_is64bit(oh.ei) isrelocatable(oh::ELFHandle) = header(oh).e_type == ET_REL diff --git a/src/ELF/ELFHeader.jl b/src/ELF/ELFHeader.jl index 14e63f0..cdfc808 100644 --- a/src/ELF/ELFHeader.jl +++ b/src/ELF/ELFHeader.jl @@ -56,6 +56,20 @@ function machinetype(e_machine) return string("Unknown (0x",string(e_machine, base=16),")") end +function elf_machine_to_arch(machine::UInt16) + if machine ∈ (EM_386,) + return "i686" + elseif machine ∈ (EM_IA_64, EM_X86_64) + return "x86_64" + elseif machine ∈ (EM_ARM,) + return "armv7l" + elseif machine ∈ (EM_AARCH64,) + return "aarch64" + elseif machine ∈ (EM_PPC64,) + return "ppc64le" + end +end + function show(io::IO, header::ELFHeader) println(io, "ELF Header") diff --git a/src/MachO/MachO.jl b/src/MachO/MachO.jl index 04d8c4e..92c9280 100644 --- a/src/MachO/MachO.jl +++ b/src/MachO/MachO.jl @@ -1,6 +1,7 @@ module MachO -using StructIO +using StructIO, Base.BinaryPlatforms +import Base.BinaryPlatforms: Platform # Bring in ObjectFile definitions using ObjectFile diff --git a/src/MachO/MachOHandle.jl b/src/MachO/MachOHandle.jl index 648a2dc..af9be45 100644 --- a/src/MachO/MachOHandle.jl +++ b/src/MachO/MachOHandle.jl @@ -46,6 +46,7 @@ iostream(oh::AbstractMachOHandle) = oh.io ## Format-specific properties: header(oh::AbstractMachOHandle) = oh.header endianness(oh::AbstractMachOHandle) = macho_endianness(header(oh).magic) +Platform(oh::MachOHandle) = Platform(macho_cpu_to_arch(header(oh).cputype), "macos") is64bit(oh::MachOHandle) = macho_is64bit(header(oh).magic) isrelocatable(oh::MachOHandle) = header(oh).filetype == MH_OBJECT isexecutable(oh::MachOHandle) = header(oh).filetype == MH_EXECUTE diff --git a/src/MachO/constants.jl b/src/MachO/constants.jl index c32f7c6..7d2b62e 100644 --- a/src/MachO/constants.jl +++ b/src/MachO/constants.jl @@ -48,6 +48,21 @@ const CPU_ARCH_ABI64_32 = 0x02000000 const CPU_TYPE_ARM64_32 = CPU_TYPE_ARM | CPU_ARCH_ABI64_32 end +function macho_cpu_to_arch(cputype::UInt32) + if cputype ∈ (CPU_TYPE_X86,) + return "i686" + elseif cputype ∈ (CPU_TYPE_X86_64,) + return "x86_64" + elseif cputype ∈ (CPU_TYPE_ARM,) + return "armv7l" + elseif cputype ∈ (CPU_TYPE_POWERPC64,) + return "ppc64le" + elseif cputype ∈ (CPU_TYPE_ARM64,) + return "aarch64" + end +end + + # TODO subtype constants @constants NLISTTYPES "N_" begin const N_STAB = 0xe0 diff --git a/src/ObjectFile.jl b/src/ObjectFile.jl index ab07796..6ef1bb8 100644 --- a/src/ObjectFile.jl +++ b/src/ObjectFile.jl @@ -1,5 +1,6 @@ module ObjectFile using Reexport +import Base.BinaryPlatforms: Platform # Include base utilities include("utils.jl") diff --git a/test/runtests.jl b/test/runtests.jl index c9b0039..dbde158 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -using ObjectFile +using ObjectFile, Base.BinaryPlatforms using Test @testset "basic" begin @@ -29,6 +29,14 @@ function test_libfoo_and_fooifier(fooifier_path, libfoo_path) H = types[platform] bits = dir_path[end-1:end] + platforms = Dict( + "linux32" => Platform("i686", "linux"), + "linux64" => Platform("x86_64", "linux"), + "mac64" => Platform("x86_64", "macos"), + "win32" => Platform("i686", "windows"), + "win64" => Platform("x86_64", "windows"), + ) + @testset "$(dir_path)" begin @testset "General Properties" begin for oh in (oh_exe, oh_lib) @@ -37,6 +45,7 @@ function test_libfoo_and_fooifier(fooifier_path, libfoo_path) # Test that we got the right number of bits @test is64bit(oh) == (bits == "64") + @test platforms_match(Platform(oh), platforms[dir_path]) # Everything is always little endian @test endianness(oh) == :LittleEndian