Codebase list arch-test / HEAD elf-arch
HEAD

Tree @HEAD (Download .tar.gz)

elf-arch @HEADraw · history · blame

#!/usr/bin/perl -w

my $a;
if ($#ARGV==2 && $ARGV[0] eq '-a')
{
    shift;
    $a=shift
}

!$#ARGV or die "Usage: $0 [-a] <file>\n";
open F, '<', $ARGV[0] or die "$0: can't read $ARGV[0]: $!\n";
my $header;
my $hlen = sysread F, $header, 56;
defined $hlen or die "$0: can't read $ARGV[0]: $!\n";
$hlen==56 or die "$0: $ARGV[0] not an ELF: only $hlen bytes long\n";

sub elf()
{
    my ($word, $end, $version, $os, $abi, $isa) = unpack('xxxxCCCCCxxxxxxxxxv', $header);
    $version==1 or return "invalid";
    my $id=sprintf("%d:%s:%x", 16*(1<<$word), substr("-lb",$end,1), $isa);
    my $wo32=substr("xVN",$end,1);
    my $flags_offset=0x18+(6<<$word);
    my $flags=unpack("x$flags_offset$wo32",$header);
    my %elf_arch=(
        "64:l:9026" => "alpha",
        "64:l:3e" => "amd64",
        "32:l:28" => "arm",
        "64:l:b7" => "arm64",
        "32:l:b7" => "arm64ilp32",
        "32:b:f00" => "hppa",
        "64:b:f00" => "hppa64",
        "32:l:3" => "i386",
        "64:l:32" => "ia64",
        "32:b:400" => "m68k",
        "32:b:800" => "mips",
        "64:b:800" => "mips64",
        "64:l:8" => "mips64el",
        "32:l:8" => "mipsel",
        "32:b:800" => "mips",
        "32:l:71" => "nios2",
        "32:b:5c00" => "or1k",
        "32:b:1400" => "powerpc",
        "64:b:1500" => "ppc64",
        "64:l:15" => "ppc64el",
        "64:l:f3" => "riscv64",
        "64:b:1600" => "s390x",
        "32:l:2a" => "sh4",
        "32:b:200" => "sparc",
        "64:b:2b00" => "sparc64",
        "32:l:3e" => "x32",
    );
    $_=$elf_arch{$id}//"unknown";
    if (/^mips/)
    {
        my $rel=$flags>>28&0xf;
        if ($rel==10)
            { s/mips64/mips64r6/}
        elsif ($rel==9)
            { s/mips/mipsr6/}
        elsif ($rel==2 && $word==1)
            { s/mips/mipsn32/}
    }
    if ($os==9)
        { $_="kfreebsd-$_" }
    elsif ($os==4)
        { $_="hurd-$_" }
    elsif ($os && $os!=3) # Linux is 3 in theory but almost always 0
        { return "unknown" };
    $_
}

sub pe()
{
    sysseek F, 0x3c, 0;
    $hlen = sysread F, $_, 4;
    defined $hlen or return die "$0: can't read $ARGV[0]: $!\n";
    $_=unpack 'V';
    $_>0
    and sysseek(F, $_, 0)
    and sysread(F, $_, 4)==4
    and $_ eq "PE\0\0"
    and sysread(F, $_, 2)==2
        or return 'invalid';
    $_=unpack 'v';

    my %pe_arch=(
        0x0 => 'pe-universal',
        0x1d3 => 'win-am33',
	0x8664 => 'win64',
	0x1c0 => 'win-arm',
	0xaa64 => 'win-arm64',
	0x1c4 => 'win-armnt', #	ARM Thumb-2 little endian
	0xebc => 'ebc', # EFI byte code
	0x14c => 'win32',
	0x200 => 'win-ia64',
	0x9041 => 'win-m32r',
	0x266 => 'win-mips16',
	0x366 => 'win-mipsfpu',
	0x466 => 'win-mipsfpu16',
	0x1f0 => 'win-powerpc',
	0x1f1 => 'win-powerpcfp',
	0x166 => 'win-r4000',
	0x5032 => 'win-riscv32',
	0x5064 => 'win-riscv64',
	0x5128 => 'win-riscv128',
	0x1a2 => 'win-sh3',
	0x1a3 => 'win-sh3dsp',
	0x1a6 => 'win-sh4',
	0x1a8 => 'win-sh4',
	0x1c2 => 'win-thumb',
	0x169 => 'win-wcemipsv2',
    );

    return $pe_arch{$_}//'pe-unknown';
}

my $ea = (unpack('N', $header)==0x7f454c46) ? elf :
         (substr($header,0,2) eq 'MZ') ? pe :
         "invalid";

defined($a) or print("$ea\n"), exit 0;

exit 0 if $ea eq $a; # Try unmangled first.
$a=~s/^musl-//;
# These usually have unmarked binaries.
$a=~s/^hurd-//;
$a=~s/^illumos-//;
$a=~s/^solaris-//;
$a=~s/^linux-//;

my %aliases=(
    'arm' => ['armel', 'armhf'],
    'powerpc' => ['powerpcspe'],
    'sh4' => ['sh3'],
);

exit 0 if $ea eq $a;
exit 1 unless defined $aliases{$ea};
exit !grep { $_ eq $a } @{$aliases{$ea}}