pax_global_header00006660000000000000000000000064147611403320014513gustar00rootroot0000000000000052 comment=a14e749c3a09acc95fc486103e96516e0f02d187 arch-test-0.22/000077500000000000000000000000001476114033200133305ustar00rootroot00000000000000arch-test-0.22/.gitignore000066400000000000000000000000371476114033200153200ustar00rootroot00000000000000*~ *.o arch-test-* core config arch-test-0.22/LICENSE000066400000000000000000000020001476114033200143250ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. arch-test-0.22/Makefile000066400000000000000000000127061476114033200147760ustar00rootroot00000000000000VERSION=$(shell git describe) ARCHS=amd64 x32 i386 \ win32 win64 \ mips mipsel mipsn32 mipsn32el mips64 mips64el \ illumos-amd64 \ kfreebsd-amd64 kfreebsd-i386 \ powerpc ppc64 ppc64el powerpcspe \ s390x \ arm64 arm64ilp32 \ arm armel armhf \ sh4 \ m68k \ sparc sparc64 \ alpha \ hppa \ ia64 \ riscv32 riscv64 \ loong64 \ arc \ X86=x86_64-linux-gnu MIPS=mips-linux-gnu POWERPC=powerpc-linux-gnu ARM=arm-linux-gnueabihf SPARC=sparc64-linux-gnu -include config all: $(ARCHS:%=arch-test-%) clean: rm -f *.o arch-test-* core *.core distclean: clean rm -f config DESTDIR= PREFIX=/usr/local install: all mkdir -p $(DESTDIR)$(PREFIX)/bin mkdir -p $(DESTDIR)$(PREFIX)/libexec/arch-test/ sed -e "s|^HELPERS.*|HELPERS=$(PREFIX)/libexec/arch-test/|;s&..git describe.&$(VERSION)&" \ $(DESTDIR)$(PREFIX)/bin/arch-test chmod a+x $(DESTDIR)$(PREFIX)/bin/arch-test for x in $(ARCHS); do cp -p arch-test-$$x \ $(DESTDIR)$(PREFIX)/libexec/arch-test/$$x;done mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1/ install -p *.1 $(DESTDIR)$(PREFIX)/share/man/man1/ install -p elf-arch $(DESTDIR)$(PREFIX)/bin/ arch-test-amd64: amd64.s $(X86)-as --64 $^ -o amd64.o $(X86)-ld -z noexecstack -melf_x86_64 -s amd64.o -o $@ arch-test-x32: x32.s $(X86)-as --x32 $^ -o x32.o $(X86)-ld -z noexecstack -melf32_x86_64 -s x32.o -o $@ arch-test-i386: i386.s $(X86)-as --32 $^ -o i386.o $(X86)-ld -z noexecstack -melf_i386 -s i386.o -o $@ arch-test-win32: win32.s i686-w64-mingw32-as $^ -o win32.o i686-w64-mingw32-ld -s win32.o -lkernel32 -o $@ arch-test-win64: win64.s x86_64-w64-mingw32-as $^ -o win64.o x86_64-w64-mingw32-ld -s win64.o -lkernel32 -o $@ arch-test-mips: mips.s $(MIPS)-as -32 -EB $^ -o mips.o $(MIPS)-ld -z noexecstack -melf32btsmip -s mips.o -o $@ arch-test-mipsel: mips.s $(MIPS)-as -32 -EL $^ -o mipsel.o $(MIPS)-ld -z noexecstack -melf32ltsmip -s mipsel.o -o $@ arch-test-mipsn32: mipsn32.s $(MIPS)-as -n32 -EB $^ -o mipsn32.o $(MIPS)-ld -z noexecstack -melf32btsmipn32 -s mipsn32.o -o $@ arch-test-mipsn32el: mipsn32.s $(MIPS)-as -n32 -EL $^ -o mipsn32el.o $(MIPS)-ld -z noexecstack -melf32ltsmipn32 -s mipsn32el.o -o $@ arch-test-mips64: mips64.s $(MIPS)-as -64 -EB $^ -o mips64.o $(MIPS)-ld -z noexecstack -melf64btsmip -s mips64.o -o $@ arch-test-mips64el: mips64.s $(MIPS)-as -64 -EL $^ -o mips64el.o $(MIPS)-ld -z noexecstack -melf64ltsmip -s mips64el.o -o $@ arch-test-illumos-amd64: solaris-amd64.s $(X86)-as --64 $^ -o illumos-amd64.o $(X86)-ld -z noexecstack -melf_x86_64 -s illumos-amd64.o -o $@ # same ABI as Solaris, save for branding. arch-test-kfreebsd-amd64: solaris-amd64.s $(X86)-as --64 $^ -o kfreebsd-amd64.o $(X86)-ld -z noexecstack -melf_x86_64 -s kfreebsd-amd64.o -o $@ # FreeBSD relies on "branding" of ELF files. printf '\t'|dd of=$@ bs=1 count=1 seek=7 conv=notrunc arch-test-kfreebsd-i386: kfreebsd-i386.s $(X86)-as --32 $^ -o kfreebsd-i386.o $(X86)-ld -z noexecstack -melf_i386 -s kfreebsd-i386.o -o $@ # FreeBSD relies on "branding" of ELF files. printf '\t'|dd of=$@ bs=1 count=1 seek=7 conv=notrunc arch-test-powerpc: powerpc.s $(POWERPC)-as -a32 $^ -o powerpc.o $(POWERPC)-ld -z noexecstack -melf32ppc -s powerpc.o -o $@ arch-test-ppc64: ppc64.s $(POWERPC)-as -a64 $^ -o ppc64.o $(POWERPC)-ld -z noexecstack -melf64ppc -s ppc64.o -o $@ arch-test-ppc64el: ppc64el.s powerpc64le-linux-gnu-as -mpower8 $^ -o ppc64el.o powerpc64le-linux-gnu-ld -z noexecstack -s ppc64el.o -o $@ arch-test-powerpcspe: powerpcspe.s $(POWERPC)-as -a32 -me500 $^ -o powerpcspe.o $(POWERPC)-ld -z noexecstack -melf32ppc -s powerpcspe.o -o $@ arch-test-s390x: s390x.s s390x-linux-gnu-as $^ -o s390x.o s390x-linux-gnu-ld -z noexecstack -s s390x.o -o $@ arch-test-arm64: arm64.s aarch64-linux-gnu-as $^ -o arm64.o aarch64-linux-gnu-ld -z noexecstack -s arm64.o -o $@ arch-test-arm64ilp32: arm64.s aarch64-linux-gnu-as -mabi=ilp32 $^ -o arm64ilp32.o aarch64-linux-gnu-ld -z noexecstack -maarch64linux32 -s arm64ilp32.o -o $@ arch-test-arm: arm.oabi.s $(ARM)-as $^ -o arm.o $(ARM)-ld -z noexecstack -s arm.o -o $@ arch-test-armel: armel.s $(ARM)-as $^ -o armel.o $(ARM)-ld -z noexecstack -s armel.o -o $@ arch-test-armhf: armhf.s $(ARM)-as $^ -o armhf.o $(ARM)-ld -z noexecstack -s armhf.o -o $@ arch-test-sh4: sh4.s sh4-linux-gnu-as $^ -o sh4.o sh4-linux-gnu-ld -z noexecstack -s sh4.o -o $@ arch-test-m68k: m68k.s m68k-linux-gnu-as $^ -o m68k.o m68k-linux-gnu-ld -z noexecstack -s m68k.o -o $@ arch-test-sparc64: sparc64.s $(SPARC)-as --64 $^ -o sparc64.o $(SPARC)-ld -z noexecstack -melf64_sparc -s sparc64.o -o $@ arch-test-sparc: sparc.s $(SPARC)-as --32 $^ -o sparc.o $(SPARC)-ld -z noexecstack -melf32_sparc -s sparc.o -o $@ arch-test-alpha: alpha.s alpha-linux-gnu-as $^ -o alpha.o alpha-linux-gnu-ld -z noexecstack -s alpha.o -o $@ arch-test-hppa: hppa.s hppa-linux-gnu-as $^ -o hppa.o hppa-linux-gnu-ld -z noexecstack -s hppa.o -o $@ arch-test-ia64: ia64.s ia64-linux-gnu-as $^ -o ia64.o ia64-linux-gnu-ld -z noexecstack -s ia64.o -o $@ arch-test-riscv64: riscv64.s $(RISCV)-as --march=rv64g $^ -o riscv64.o $(RISCV)-ld -z noexecstack -m elf64lriscv -s riscv64.o -o $@ arch-test-loong64: loong64.s loongarch64-linux-gnu-as $^ -o loong64.o loongarch64-linux-gnu-ld -z noexecstack -s loong64.o -o $@ arch-test-arc: arc.s arc-linux-gnu-as $^ -o arc.o arc-linux-gnu-ld -z noexecstack -s arc.o -o $@ arch-test-riscv32: riscv32.s $(RISCV)-as --march=rv32g $^ -o riscv32.o $(RISCV)-ld -z noexecstack -m elf32lriscv -s riscv32.o -o $@ arch-test-0.22/README000066400000000000000000000070031476114033200142100ustar00rootroot00000000000000This tool will tell you "can your machine+kernel run architecture X?". The check is for the ability to run machine code and supporting appropriate syscall ABI, not for the presence of userland libraries. Ie, a positive answer means you can use a chroot or container of that architecture, add it to your multiarch set, etc, but doesn't mean you can currently run non-static binaries without installing required libraries. Architectures detected by this version of arch-test are: * amd64, i386, x32 * mips, mipsel, mipsn32, mipsn32el, mips64, mips64el * arm, armel, armhf, arm64, arm64ilp32 * powerpc, ppc64, ppc64el, powerpcspe * m68k * sh4 * s390x * sparc, sparc64 * illumos-amd64 * win32, win64 * kfreebsd-amd64, kfreebsd-i386 * alpha * hppa * ia64 * riscv32, riscv64 * loong64 Detection quirks ================ This tool claims FreeBSD with its Linux emulation layer on can't run i386. That's not a bug -- it can't run _unmodified_ i386 binaries. There's a tool "brandelf" that sets field 0x7 in the ELF header, required by FreeBSD but not set by Linux nor Solaris toolchains. Emulation of the SWP instruction on at least Odroid-U2 vendor kernel is broken, subtly breaking armel processes. They mostly work but once there's lock contention, shit will happen. Thus, it's debatable whether to mark armel as unsupported there -- I do so only because it's easier for me. Adding new archs ================ Helper programs are supposed to write the string "ok\n" to stdout then return exit code 0. This can be done by statically compiling "generic.c" for the given architecture. Unfortunately, doing so with glibc produces ~800KB executables which multiplied by the number of archs to test would take too much space for such a minor tool. And, for non-baseline archs some specific code is needed. Examples: * ppc64el requires POWER8, some versions of qemu-user can run little-endian PPC64 but lack some instructions required by the Debian arch. * powerpcspe has no classic FPU but a bunch of other instructions. * armhf uses same syscall ABI as armel. One way to ascertain required support is trying to run an unprivileged instruction that's lacking on older versions of the ISA. This causes the helper program to fail with SIGILL/SIGFPE/etc which means it will return an exit code other than 0. Missing Debian architectures ============================ * hurd-*: it has no proper syscalls, the equivalent being complicated RPC calls implemented inside glibc. This is similar to Windows where the real syscalls (NT) are undocumented and unstable while everyone is supposed to link to "kernel" shared libraries. Unfortunately for hurd, there's no cross toolchain in Debian, unlike mingw. Non-Debian architectures ======================== While currently arch-test is heavily biased towards Debian, there is no reason for it to stay so. I would need to compile the assembler from source during the build, but that's doable. All that's needed is motivation (ie, tell me if you have a use) and access to test machines. elf-arch ======== Another tool in this package answers "what arch this program/library is for?". Alas, it is impossible to determine this accurately, and in many cases this program will give only a vague architecture family. Known variants of such a family are thus considered "aliases", and you can query whether the given executable matches a set. Besides all archs known by arch-test, elf-arch also knows about hppa64 and mipsr6 variants. Resources ========= man 2 syscall https://github.com/deater/ll_asm.git arch-test-0.22/alpha.s000066400000000000000000000002571476114033200146050ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: br $27, 0 ldgp $gp, 0($27) ldil $0, 4 ldil $16, 1 lda $17, msg ldil $18, 3 callsys clr $16 ldil $0, 1 callsys arch-test-0.22/amd64.s000066400000000000000000000003271476114033200144310ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov $1, %rax # syscall: write(rdi, rsi, rdx) mov $1, %rdi mov $msg, %rsi mov $3, %rdx syscall mov $60, %rax # syscall: _exit(rdi) xor %rdi, %rdi syscall arch-test-0.22/arc.s000066400000000000000000000003311476114033200142560ustar00rootroot00000000000000.globl __start .section .rodata msg: .ascii "ok\n" .text __start: mov_s r0, 1 mov_s r1, msg mov_s r2, 3 mov r8, 64 trap_s 0 # syscall: write(r0, r1, r2) mov_s r0, 0 mov r8, 93 trap_s 0 # syscall: _exit(r0) arch-test-0.22/arch-test000077500000000000000000000032601476114033200151510ustar00rootroot00000000000000#!/bin/sh # Near-misses fail with SIGILL or SIGSEGV, we don't want core dumps. ulimit -c 0 HELPERS=$0- case "$1" in --version) printf 'arch-test %s\n' "$(git describe)" exit 0 ;; -n|--native) export QEMU_VERSION=meow WINEPREFIX=/dev/null shift ;; -c|--chroot) shift CHROOT="$1" shift if [ -z "$CHROOT" ] then echo >&2 "$0: -c requires path to the chroot (possibly '.')."; exit 2 fi if [ ! -d "$CHROOT" ] then echo >&2 "$0: chroot '$CHROOT' is not a directory."; exit 2 fi if [ "x$(id -u)" != "x0" ] then echo >&2 "$0: chrooting requires root."; exit 2 fi if [ -z "$1" ] then echo >&2 "$0: -c works only with a single-arch query."; exit 2 fi ;; -*) echo >&2 "$0: unknown option '$1'."; exit 2 ;; esac if [ $# -gt 1 ] then echo >&2 'Usage: "arch-test [-n]" or "arch-test [-n|-c ] ".'; exit 1 fi if [ $# -eq 1 ] then if [ ! -x "$HELPERS$1" ] then echo "I don't know how to detect arch '$1', sorry."; exit 2 fi if [ -n "$CHROOT" ] then HELPER_F="$(basename $HELPERS$1)" cp -p "$HELPERS$1" "$CHROOT/$HELPER_F" trap "rm '$CHROOT/$HELPER_F'" 0 MSG=`chroot "$CHROOT" /"$HELPER_F" 2>/dev/null` else MSG=`$HELPERS$1 2>/dev/null` fi if [ $? -eq 0 -a "x$MSG" = "xok" ] then echo "$1: ok"; exit 0 else echo "$1: not supported on this machine/kernel"; exit 1 fi fi for x in $HELPERS* do ARCH="$(basename "$x")" ARCH="${ARCH##arch-test-}" MSG=`"$x" 2>/dev/null|tr -d '\r'` if [ $? -eq 0 -a "x$MSG" = "xok" ] then echo "$ARCH" fi done arch-test-0.22/arch-test.1000066400000000000000000000052351476114033200153110ustar00rootroot00000000000000.TH arch-test 1 .SH NAME arch-test \- detect architectures your kernel can run binaries of .SH SYNOPSIS .TP .BR arch-test " [" -n ] enumerates the architectures .TP .BR arch-test " [" -n ] " " [ -c " " "\fI\fR" ] " " "\fI\fR" tests a single arch .SH DESCRIPTION When called without an argument, \fBarch-test\fR outputs the list of architectures executable by your running kernel, one per line, using Debian arch names. \fILibc\fR or other libraries are neither needed nor checked \&\(em an arch is listed if its machine code can be executed and the appropriate syscall ABI is supported by the kernel. This means, you can run these architectures in a \fIchroot\fR or a container, execute them using multiarch, run static binaries, etc. The ability to run additional architectures can be gained via \fIbinfmt\fRs on Linux, Linux emulation on BSD, etc. An architecture is considered runnable only if your kernel can run \fIunmodified\fR binaries, without extra steps such as recompiling (Raspbian armhf) or using \fBbrandelf\fR on binaries you'd want to run (FreeBSD emulation of Linux). Also, as Debian requires 686 on i386 as of the stretch release, 686 support is checked for. If \fB-n\fR is specified, \fBarch-test\fR will try to disable known emulators (currently \fBqemu\fR and \fBwine\fR). Note that a whole-machine emulator appears to be native as far as the kernel is concerned. With \fB-c\fR \fI\fR, the test is done inside a given chroot (qemu-user before 2.12 required the interpreter to live \fIinside\fR the chroot). Root privileges are required here. When called with an arch name as an argument, \fBarch-test\fR tests the specified architecture. A human-friendly message will be printed, and the exit code can be: .TP .B 0 congratulations, the arch can be run on your kernel .TP .B 1 failure .TP .B 2 cannot check \(em \fBarch-test\fR lacks a helper for this arch .TP (Shell hint: with \fIset -e\fR you write: \fIret=0; arch-test $ARCH || ret=$?\fR) .SS "Helper programs" The detection is done by small programs located in \fI/usr/libexec/arch-test/\fR. These programs check whether the running kernel can execute binaries of a given architecture. When run, if successful, each such program prints \fI"ok"\fR on stdout and returns exit code 0. When the check fails, these helper programs may die horribly \(em always with a non-zero exit code. Usually the kernel will notice the incompatibility and nicely abort the attempt, but in some near-miss cases the failure is more messy, such as \fISIGILL\fR or \fISIGSEGV\fR. If you want to run the helpers directly, you'd want to redirect \fIstderr\fR to \&\fI/dev/null\fR and to disable core dumps (\fBulimit -c 0\fR). arch-test-0.22/arm.oabi.s000066400000000000000000000002701476114033200152030ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov a1, #1 ldr a2, =msg mov a3, #3 swi 0x900004 // syscall: write(a1, a2, a3) mov a1, #0 swi 0x900001 // syscall: _exit(a1) arch-test-0.22/arm64.s000066400000000000000000000003031476114033200144410ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov x0, #1 adr x1, msg mov x2, #3 mov x8, 64 // syscall: write(x0, x1, x2) svc 0 mov x0, #0 mov x8, 93 // syscall: _exit(x0) svc 0 arch-test-0.22/armel.s000066400000000000000000000003021476114033200146070ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: ldr r1, =msg mov r0, #1 mov r2, #3 mov r7, #4 // syscall: write(r0, r1, r2) swi 0 mov r0, #0 mov r7, #1 // syscall: _exit(r0) swi 0 arch-test-0.22/armhf.s000066400000000000000000000003461476114033200146140ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: dmb // SIGILL on CPUs below ARMv7 mov r0, #1 ldr r1, =msg mov r2, #3 mov r7, #4 // syscall: write(r0, r1, r2) swi 0 mov r0, #0 mov r7, #1 // syscall: _exit(r0) swi 0 arch-test-0.22/configure000077500000000000000000000027661476114033200152520ustar00rootroot00000000000000#!/usr/bin/perl -w my ($ok, $no) = (-t 1)? ("\e[32;1m✓\e[0m ", "\e[31;1m✗\e[0m ") : ("", ""); open MAKEFILE, "} close MAKEFILE; /^ARCHS=((?:[a-z0-9-]| |\t|\\\n)*)/m or die "Couldn't parse ARCHS= in the Makefile\n"; $ARCH{$_}=1 for($1=~/[a-z0-9-]+/g); my @FOUND; sub alt { my $arch = shift; for (@_) { `which "$_-as"`; $VARS{$arch}=$_, last unless $?; } if ($VARS{$arch}) { s/\$\($arch\)/$VARS{$arch}/g; } else { $VARS{$arch}="{".join(',', @_)."}"; s/\$\($arch\)/$_[0]/g; } } alt qw(X86 x86_64-linux-gnu i386-linux-gnu i486-linux-gnu i586-linux-gnu i686-linux-gnu x86_64-linux-gnux32); alt qw(MIPS mips-linux-gnu mipsel-linux-gnu mips64-linux-gnuabi64 mips64el-linux-gnuabi64); alt qw(POWERPC powerpc-linux-gnu powerpc64-linux-gnu); alt qw(ARM arm-linux-gnueabihf arm-linux-gnueabi); alt qw(SPARC sparc64-linux-gnu sparc-linux-gnu); alt qw(RISCV riscv64-linux-gnu riscv32-linux-gnu); while (/^arch-test-([a-z0-9-]+):.*\n\t([a-z0-9_.-]+-(?:gcc|as))/mg) { $ARCH{$1} or die "Error: $1 known but not listed.\n"; delete $ARCH{$1}; `which $2`; if ($?) { print "${no}Missing $1: $2 not installed\n"; } else { print "$ok$1: $2\n"; push @FOUND, "$1"; } } die "Error: ".join(' ',keys %ARCH)." listed but not known.\n" if (%ARCH); open CONFIG, ">config"; print CONFIG "ARCHS=@FOUND\n"; print CONFIG "$_=$VARS{$_}\n" for keys %VARS; arch-test-0.22/elf-arch000077500000000000000000000076051476114033200147470ustar00rootroot00000000000000#!/usr/bin/perl -w my $a; if ($#ARGV==2 && $ARGV[0] eq '-a') { shift; $a=shift } !$#ARGV or die "Usage: $0 [-a] \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:c3" => "arc", "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", "64:l:102" => "loong64", "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", "32:l:f3" => "riscv32", "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=( 0x0000 => 'pe-universal', 0x0184 => 'win-alpha32', 0x0284 => 'win-alpha64', 0x01d3 => 'win-am33', 0x8664 => 'win64', 0x01c0 => 'win-arm', 0xaa64 => 'win-arm64', 0x01c4 => 'win-armnt', # ARM Thumb-2 little endian 0x0ebc => 'ebc', # EFI byte code 0x014c => 'win32', 0x0200 => 'win-ia64', 0x6232 => 'win-loong32', 0x6264 => 'win-loong64', 0x9041 => 'win-m32r', 0x0266 => 'win-mips16', 0x0366 => 'win-mipsfpu', 0x0466 => 'win-mipsfpu16', 0x01f0 => 'win-powerpc', 0x01f1 => 'win-powerpcfp', 0x0166 => 'win-mipsr4000', 0x5032 => 'win-riscv32', 0x5064 => 'win-riscv64', 0x5128 => 'win-riscv128', 0x01a2 => 'win-sh3', 0x01a3 => 'win-sh3dsp', 0x01a6 => 'win-sh4', 0x01a8 => 'win-sh5', 0x01c2 => 'win-thumb', 0x0169 => '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}} arch-test-0.22/elf-arch.1000066400000000000000000000024461476114033200151010ustar00rootroot00000000000000.TH elf-arch 1 .SH NAME elf-arch \- recognize architecture of an ELF executable/shlib .SH SYNOPSIS .TP .BI "elf-arch " says the arch of given binary .TP .BR elf-arch " " -a " " \fI " " \fI checks if \fI\fR matches ABI \fI\fR .SH DESCRIPTION \fBelf-arch\fR detects the kernel ABI needed to run a given binary, and prints its Debian arch name. This doesn't necessarily mean the arch can actually run that program/library: markings available in the ELF header are pretty much restricted to just word width, endianness and instruction set family. Architectures can also differ by the set of syscalls they use (although these can usually be mixed) or required CPU instructions; you can't generally distinguish between those other than trying to run the program. The difference usually shows in the kernel refusing to run a binary vs executing it and crashing at runtime. Thus, as far as ELF markings are concerned, there's often a set of Debian architectures which are aliases for the same kernel arch. .SS "\fB-a\fR" \fI\fR With this option, elf-arch instead of printing the detected architecture will check if \fI\fR matches one of aliases for the file, and return an exit code: 0 if there's a plausible match, non-zero if the given arch won't even try executing that file. arch-test-0.22/generic.c000066400000000000000000000001131476114033200151030ustar00rootroot00000000000000#include int main() { write(1, "ok\n", 3); return 0; } arch-test-0.22/hppa.s000066400000000000000000000004041476114033200144420ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: ldi 1, %r26 ldil L'msg, %r25 ldo R'msg(%r25), %r25 ldi 3, %r24 ble 0x100(%sr2,%r0) ldi 4, %r20 ; syscall: write(r26, r25, r24) ldi 0, %r26 ble 0x100(%sr2,%r0) ldi 1, %r20 ; syscall: _exit(r26) arch-test-0.22/i386.s000066400000000000000000000004421476114033200142050ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: cmovz %eax, %ebx # 686 required as of Debian stretch movl $4, %eax # syscall: write(ebx, ecx, edx) movl $1, %ebx movl $msg, %ecx movl $3, %edx int $0x80 xorl %eax, %eax incl %eax # syscall: _exit(bl) xorb %bl, %bl int $0x80 arch-test-0.22/ia64.s000066400000000000000000000004101476114033200142520ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: alloc loc0 = ar.pfs,0,32,3,0 mov out0=1 movl out1=msg mov out2=3 mov r15=1027 break.i 0x100000 // syscall: write(out0, out1, out2) mov out0=0 mov r15=1025 break.i 0x100000 // syscall: _exit(out0) arch-test-0.22/kfreebsd-i386.s000066400000000000000000000004641476114033200157740ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: cmovz %eax, %ebx # 686 required as of Debian stretch pushl $3 pushl $msg pushl $1 mov $4, %eax # syscall: write push %eax int $0x80 add $16, %esp # pop 3 arguments + dummy * 4 bytes pushl $0 mov $1, %eax # syscall: _exit push %eax int $0x80 arch-test-0.22/loong64.s000066400000000000000000000003331476114033200150030ustar00rootroot00000000000000.globl _start .section .rodata msg: .ascii "ok\n" .text _start: li.w $a0, 1 la $a1, msg li.w $a2, 3 li.w $a7, 64 syscall 0 # syscall: write(a0, a1, a2) li.w $a0, 0 li.w $a7, 93 syscall 0 # syscall: _exit(a0) arch-test-0.22/m68k.s000066400000000000000000000003601476114033200143000ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: moveq.l #1, %d1 lea msg, %a1 move.l %a1, %d2 moveq.l #3, %d3 moveq.l #4, %d0 | syscall: write(d1, d2, d3) trap #0 moveq.l #0, %d1 moveq.l #1, %d0 | syscall: _exit(d1) trap #0 arch-test-0.22/mips.s000066400000000000000000000003371476114033200144670ustar00rootroot00000000000000.rdata msg: .ascii "ok\n" .text .globl __start __start: li $4, 1 la $5, msg li $6, 3 li $2, 4004 syscall move $4, $0 li $2, 4001 syscall # <-- unreachable # exit gracefully on n32 li $4, 1 li $2, 6058 syscall arch-test-0.22/mips64.s000066400000000000000000000002221476114033200146320ustar00rootroot00000000000000.rdata msg: .ascii "ok\n" .text .globl __start __start: li $4, 1 dla $5, msg li $6, 3 li $2, 5001 syscall move $4, $0 li $2, 5058 syscall arch-test-0.22/mipsn32.s000066400000000000000000000003571476114033200150140ustar00rootroot00000000000000.rdata msg: .ascii "ok\n" .text .globl __start __start: li $4, 1 la $5, msg li $6, 3 li $2, 6001 # write syscall move $4, $0 li $2, 6058 # _exit syscall # <-- unreachable # exit gracefully on o32 li $4, 1 li $2, 4001 syscall arch-test-0.22/powerpc.s000066400000000000000000000003361476114033200151750ustar00rootroot00000000000000.rodata msg: .ascii "ok\n" .text .globl _start _start: fsel 0, 1, 2, 3 # boom on SPE li 0, 4 # syscall write(r3, r4, r5) li 3, 1 lis 4, msg@ha addi 4, 4, msg@l li 5, 3 sc li 0, 1 # syscall _exit(r3) li 3, 0 sc arch-test-0.22/powerpcspe.s000066400000000000000000000005351476114033200157060ustar00rootroot00000000000000.rodata msg: .ascii "ok\n" .text .globl _start _start: li 0, 1 # if not SPE but no SIGILL, we want r0=1 (_exit) li 3, 1 # ... with exit code 1 li 4, 4 efscfsi 0, 4 # f0 = r4 (4) efsctsi 0, 0 # r0 = f0 # r0 will be 4 # syscall write(r3, r4, r5) li 3, 1 lis 4, msg@ha addi 4, 4, msg@l li 5, 3 sc li 0, 1 # syscall _exit(r3) li 3, 0 sc arch-test-0.22/ppc64.s000066400000000000000000000005541476114033200144540ustar00rootroot00000000000000.rodata msg: .ascii "ok\n" .text .globl _start .section ".opd","aw" .align 3 _start: .quad ._start,.TOC.@tocbase,0 .previous .global ._start ._start: li 0, 4 # syscall write(r3, r4, r5) li 3, 1 lis 4, msg@highest addi 4, 4, msg@higher rldicr 4, 4, 32, 31 addis 4, 4, msg@h addi 4, 4, msg@l li 5, 3 sc li 0, 1 # syscall _exit(r3) li 3, 0 sc arch-test-0.22/ppc64el.s000066400000000000000000000006251476114033200147740ustar00rootroot00000000000000.rodata msg: .ascii "ok\n" .text .globl _start .align 3 _start: addis 2, 12, .TOC. - _start@ha addi 2, 2, .TOC. - _start@l .localentry _start, . -_start mtvsrd 0, 0 # trigger SIGILL on power7 CPUs li 0, 4 # syscall write(r3, r4, r5) li 3, 1 lis 4, msg@highest addi 4, 4, msg@higher rldicr 4, 4, 32, 31 addis 4, 4, msg@h addi 4, 4, msg@l li 5, 3 sc li 0, 1 # syscall _exit(r3) li 3, 0 sc arch-test-0.22/riscv32.s000066400000000000000000000004451476114033200150120ustar00rootroot00000000000000.globl _start .section .rodata msg: .ascii "ok\n" .text _start: li a0, 1 la a1, msg li a2, 3 li a7, 64 ecall # syscall: write(a0, a1, a2) li a0, 0 li a7, 93 ecall # syscall: _exit(a0) arch-test-0.22/riscv64.s000066400000000000000000000003471476114033200150200ustar00rootroot00000000000000.globl _start .section .rodata msg: .ascii "ok\n" .text _start: li a0, 1 lui a1, %hi(msg) addi a1, a1, %lo(msg) li a2, 3 li a7, 64 ecall # syscall: write(a0, a1, a2) li a0, 0 li a7, 93 ecall # syscall: _exit(a0) arch-test-0.22/run-all000077500000000000000000000006211476114033200146270ustar00rootroot00000000000000#!/bin/bash # Verbose script for debug purposes. ulimit -c 0 for x in arch-test-* do arch=${x##arch-test-} printf '\e[33m%s\e[0m\n' "$arch" MSG=`"./$x" 2>/dev/null|tr -d '\r'` RET=$? if [ $RET -eq 0 -a "x$MSG" = "xok" ] then COL="32" # green else COL="31" # red fi printf '\e[%smret=\e[1m%d\e[0;%sm stdout=\e[1m%s\e[0m\n' "$COL" "$RET" "$COL" "$MSG" done arch-test-0.22/s390x.s000066400000000000000000000002551476114033200144040ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: basr %r1, 0 base: la %r2, base sr %r1, %r2 lhi %r2, 1 la %r3, msg(%r1) lghi %r4, 3 svc 4 xr %r2, %r2 svc 1 arch-test-0.22/sh4.s000066400000000000000000000004221476114033200142100ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov #4, r3 ! syscall: write(r4, r5, r6) mov #1, r4 mov.l msg_ptr, r5 mov #3, r6 trapa #0x11 ! 1-argument syscall mov #1, r3 ! syscall: _exit(r4) mov #0, r4 trapa #0x13 ! 3-argument syscall msg_ptr: .long msg arch-test-0.22/solaris-amd64.s000066400000000000000000000006751476114033200161110ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov $3, %rdx mov $msg, %rsi mov $1, %rdi mov $4, %eax # syscall: write(rdi, rsi, rdx) syscall # hack: syscall 1 is write() on Linux, write nothing mov $0, %rdx mov $01, %eax # syscall: _exit(rdi) xor %rdi, %rdi syscall # <-- unreachable on Solaris # hack: don't segfault on Linux, exit cleanly with code 1 mov $60, %rax # Linux syscall: _exit(rdi) mov $1, %rdi syscall arch-test-0.22/sparc.s000066400000000000000000000003421476114033200146230ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov 1, %o0 sethi %hi(msg), %g1 or %g1, %lo(msg), %o1 mov 3, %o2 mov 4, %g1 ! syscall: write(o0, o1, o2) t 0x10 mov 0, %o0 mov 1, %g1 ! syscall: _exit(o0) t 0x10 arch-test-0.22/sparc64.s000066400000000000000000000003421476114033200147750ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov 1, %o0 sethi %hi(msg), %g1 or %g1, %lo(msg), %o1 mov 3, %o2 mov 4, %g1 ! syscall: write(o0, o1, o2) t 0x6d mov 0, %o0 mov 1, %g1 ! syscall: _exit(o0) t 0x6d arch-test-0.22/win32.s000066400000000000000000000006631476114033200144630ustar00rootroot00000000000000.globl _start .extern _GetStdHandle@4 .extern _WriteFile@20 .extern _ExitProcess@4 .data msg: .ascii "ok\n" .text _start: mov %esp, %ebp sub $4, %esp # dummy variable push $-11 call _GetStdHandle@4 # GetStdHandle(STD_OUTPUT_HANDLE) mov %eax, %ebx push $0 lea -4(%ebp), %eax push %eax push $3 push $msg push %ebx call _WriteFile@20 # WriteFile(stdout, msg, 3, &dummy, 0) push $0 call _ExitProcess@4 # _ExitProcess(0) arch-test-0.22/win64.s000066400000000000000000000007141476114033200144650ustar00rootroot00000000000000.globl _start .extern GetStdHandle .extern WriteFile .extern ExitProcess .data msg: .ascii "ok\n" .text _start: mov %rsp, %rbp sub $40, %rsp mov $-11, %rcx # STD_OUTPUT_HANDLE call GetStdHandle sub $8, %rsp # make the stack 16-aligned for a 8-byte arg pushq $0 # 0 mov %rbp, %r9 # &dummy mov $3, %r8 # 3 lea msg(%rip), %rdx # msg mov %rax, %rcx # stdout call WriteFile # cleaning the stack is for wimps xor %rcx, %rcx # 0 call ExitProcess arch-test-0.22/x32.s000066400000000000000000000003501476114033200141260ustar00rootroot00000000000000.globl _start .data msg: .ascii "ok\n" .text _start: mov $0x40000001, %rax # syscall: write(rdi, rsi, rdx) mov $1, %rdi mov $msg, %rsi mov $3, %rdx syscall mov $0x4000003c, %rax # syscall: _exit(rdi) xor %rdi, %rdi syscall