16

The ELF file format has an e_machine field in the header, which specifies which ISA the executable expects. And the e_ident structure also has an EI_OSABI field that specifies which ABI the executable is expecting. My guess is, that these fields are how my operating system knows not to go ahead and run a binary which was compiled for some other machine.

But how was this achieved on early UNIXes, early Linuxes, and others that used a.out? a.out, from what I can tell, has no equivalent field(s).

1
  • 3
    It's not possible, unfortunately.
    – wizzwizz4
    Apr 24, 2018 at 15:57

4 Answers 4

20

The a_midmag field contains a machine identifier, which can be used on platforms which support that field. a_midmag is a 32-bit value stored in host byte-order (fun already), and bits 16 to 23 give the machine type. The most comprehensive list of machine identifiers I’ve found so far is the list used by libbfd, which shows that the field has been used for quite a long time (values 1, 2 and 3 indicate 68010, 68020 and SPARC respectively). file also has a number of magic values, e.g. for Sun systems and the PDP-11.

Unfortunately the “platforms which support that field” caveat means that it can’t be relied upon, and the FreeBSD a.out manpage highlights that fact:

Since not all of the supported architectures use the a_midmag field, it can be difficult to determine what architecture a binary will execute on without examining its actual machine code. Even with a machine identifier, the byte order of the exec header is machine-dependent.

Historically, a.out binaries were directly executable, their first bytes were a jump instruction to skip the header (see the original documentation). So you could try to recognise old binaries’ architecture by figuring out whether the first (two?) bytes are a valid jump instruction with a sensible offset... Later binaries are not directly executable by the CPU; for example the start of a Linux a.out binary is a magic number such as 0x0064010b (see for example this old i386 bash binary), which isn’t useful x86.

So the answer to your question is really that to determine what architecture an a.out executable runs on, you need to try to run it...

0
16

The short answer is: early Unix systems did not bother to track which architecture an executable was for. In general, the architecture an executable was for, was the one the executable was found on.

If you're on a PDP-11, /bin will contain PDP-11 executables. If you're on a VAX, /bin will contain VAX executables. Multiple architectures all trying to store their executables in the same file system was simply not a problem people were typically having, and therefore not a problem that needed fixing.

If you tried to run something for another architecture (e.g. you restored some files from a tape written on another system) the worst that would happen is the program would crash and give you a core dump. If you were doing that kind of thing you were expected to know to either get the correct tape for your architecture, or recompile the software from source.

In those rare cases where you needed to have binaries from multiple architectures co-existing (e.g. a file server storing files) the early solutions were to do things like having separate directories for each architecture, e.g. /nfs/vax/bin, /nfs/sun3/bin, /nfs/ibm_rt/bin. Then each client would be configured to use the particular directory that was appropriate. Only a fool would mix executables for different architectures in the same directory (absent some other way to track them, e.g. architecture-specific suffixes).

4
  • I don't remember multi-architecture executables until Apple introduced "universal binaries" during one of their CPU changes on Macs. Did Unix do it earlier?
    – Barmar
    Apr 24, 2018 at 21:19
  • 3
    @Barmar Theoretically, it was possible to construct an executable that would work on both VAX and PDP-11, see the first winner of the IOCCC - hint.html for the description.
    – Leo B.
    Apr 25, 2018 at 1:31
  • 2
    @Barmar there were hacks on various systems where code could be written to load on multiple architectures, or OSs (DOS and CP/M for example). I think the first “specified” fat binary support was in NeXTSTEP. Apr 25, 2018 at 4:50
  • There was a time when Sun Microsystems would sell you a Sun-3 (68010) network server, and a bunch of Sun-4 (SPARC) diskless clients. So the server had a full version of the OS installed for each machine type. Being a SysAdmin in that environment was fraught with problems involving PATH. Feb 18, 2021 at 23:27
3

There is no 100% sure way. For an earnest albeit somewhat futile attempt to recognize a.out files, see /usr/share/magic (on Linux; elsewhere your paths may vary) - the pattern file of the UNIX file command.

There you can see that both "386 executable" and "VAX executable" have the same magic header (0407) and the same offset for the symbol table length, and there is no other way to tell them apart except by execution. The first matching pattern ("386 executable", as in the file) will win, just because it is deemed more probable to encounter a 386 a.out executable than a VAX one.

2

The a.out format is, in general, simply plain binary code. It contains no information whatsoever what platform it is intended for.

Obviously, any a.out binary will do something on any platform (the CPU, after all, simply interprets the binary code in the file according to its make and type), but the intended execution can only be achieved on the platform the a.out was built for.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .