0

My machine's architecture is x86_64 and I've cross-compiled arm64 assembly (from here) into an executable. However the binary is still runnable on my machine... how?

Here are the outputs to the following commands:

$ uname -r 6.2.12-100.fc36.x86_64 $ file hello hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, stripped $ ./hello Hello, ARM64 $ qemu-aarch64-static hello Hello, ARM64 $ qemu-x86_64-static hello qemu-x86_64-static: hello: Invalid ELF image for this architecture $ readelf -a hello ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: AArch64 Version: 0x1 Entry point address: 0x4000b0 Start of program headers: 64 (bytes into file) Start of section headers: 264 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 2 Size of section headers: 64 (bytes) Number of section headers: 4 Section header string table index: 3 Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 00000000004000b0 000000b0 0000000000000030 0000000000000000 AX 0 0 8 [ 2] .data PROGBITS 00000000004100e0 000000e0 000000000000000d 0000000000000000 WA 0 0 1 [ 3] .shstrtab STRTAB 0000000000000000 000000ed 0000000000000017 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000000e0 0x00000000000000e0 R E 0x10000 LOAD 0x00000000000000e0 0x00000000004100e0 0x00000000004100e0 0x000000000000000d 0x000000000000000d RW 0x10000 Section to Segment mapping: Segment Sections... 00 .text 01 .data There is no dynamic section in this file. There are no relocations in this file. The decoding of unwind sections for machine type AArch64 is not currently supported. No version information found in this file. 
2
  • ls /proc/sys/fs/binfmt_misc/qemu*aarch* Commented Jul 26, 2024 at 0:01
  • awesome, thank you. Commented Jul 26, 2024 at 1:16

1 Answer 1

1

To make an executable in unix, you make the file executable with chmod +x.

Of course, for this to work, the system has to know how to run it. If it's a text file, it might assume it is a shell script and run it with bash or sh.

But if you're doing it right, you would put at the top of your shell script

#!/bin/bash 

which explicitly tells unix that this file was meant to be interpreted with bash. Turns out you can put any binary name up there as long as it can take a text file as an input and either ignore the first line or ignore lines starting with #. You can do this, for instance, with perl, awk, python, etc...

You could consider the first two characters of the file (#!) to be a "magic number" identifying this as a script, with the path to the interpreter following that.

Linux took this a step further. It has a system (binfmt_misc) where you can describe arbitrary magic numbers for any executable format and rather than have the interpreter name in the file explicitly, you can assign an arbitrary interpreter to an arbitrary magic number identifier.

For instance, it is possible to identify java files and run them directly as if they were normal executables and have the system automatically invoke them with the java interpreter.

Turns out this is used even for normal executables. So if you say

$ file /bin/ls 

you might get

/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped

So the "interpreter" for a normal executable is /lib64/ld-linux-x86-64.so.2 (Side note: I don't think file knows about binfmt_misc, it has its own magic number database that includes a lot that binfmt_misc might not know.)

If you go ahead and install an emulator for another cpu, say qemu, it's not too difficult to just add the magic numbers to binfmt_misc for the executable formats qemu knows how to deal with, and then poof magically executables for that interpreter run as if they were native executables....just like shell scripts.

1
  • Sweet, thank you. I can see the binfmts listed at the path dave_thompson listed above. Commented Jul 26, 2024 at 1:15

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.