A arquitetura da minha máquina é x86_64 e compilei o assembly arm64 (daqui ) em um executável. No entanto, o binário ainda pode ser executado na minha máquina... como?
Aqui estão as saídas para os seguintes comandos:
$ 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.
Para tornar um executável no Unix, você torna o arquivo executável com a extensão
chmod +x
.É claro que para que isso funcione, o sistema precisa saber como executá-lo. Se for um arquivo de texto, ele pode assumir que é um script de shell e executá-lo com bash ou sh.
Mas se você estiver fazendo certo, você colocaria no topo do seu script de shell
que diz explicitamente ao unix que este arquivo deveria ser interpretado com bash. Acontece que você pode colocar qualquer nome binário lá, desde que ele possa receber um arquivo de texto como entrada e ignorar a primeira linha ou ignorar as linhas que começam com
#
. Você pode fazer isso, por exemplo, com perl, awk, python, etc...Você pode considerar os dois primeiros caracteres do arquivo (
#!
) como um "número mágico" que identifica isso como um script, seguido pelo caminho para o intérprete.O Linux deu um passo adiante. Ele possui um sistema (binfmt_misc) onde você pode descrever números mágicos arbitrários para qualquer formato executável e, em vez de ter explicitamente o nome do intérprete no arquivo, você pode atribuir um intérprete arbitrário a um identificador de número mágico arbitrário.
Por exemplo, é possível identificar arquivos java e executá-los diretamente como se fossem executáveis normais e fazer com que o sistema os invoque automaticamente com o interpretador java.
Acontece que isso é usado até mesmo para executáveis normais. Então, se você disser
Você pode conseguir
/bin/ls: executável ELF LSB pie de 64 bits, x86-64, versão 1 (SYSV), vinculado dinamicamente, interpretador /lib64/ld-linux-x86-64.so.2, para GNU/Linux 3.2.0, despojado
Portanto, o "intérprete" para um executável normal é /lib64/ld-linux-x86-64.so.2 (Nota lateral: não acho que o arquivo saiba sobre binfmt_misc, ele tem seu próprio banco de dados de números mágicos que inclui muitos que binfmt_misc pode não saber.)
Se você prosseguir e instalar um emulador para outra CPU, digamos qemu, não é muito difícil apenas adicionar os números mágicos ao binfmt_misc para os formatos executáveis com os quais o qemu sabe como lidar e, em seguida, executar magicamente os executáveis para esse intérprete como se eles eram executáveis nativos... assim como scripts de shell.