El kernel de Linux puede cargar varios formatos binarios diferentes:ELF es el más común, aunque el formato a.out también es bastante conocido.
Los formatos binarios admitidos están controlados por los módulos binfmt que se cargan o compilan en el núcleo (se encuentran en la sección Sistema de archivos de la configuración del núcleo). Hay un binfmt_flat
para archivos binarios de formato plano uClinux BFLT que son bastante mínimos, incluso se pueden comprimir con zlib, lo que le permitirá hacer que su archivo binario sea aún más pequeño, por lo que esta podría ser una buena opción.
No parece que nasm sea compatible de forma nativa con este formato, pero es bastante fácil agregar el encabezado necesario manualmente como describe Jim Lewis para ELF. Hay una descripción del formato aquí.
¿Hay alguna razón por la que no quieras usar "-f elf" en lugar de "-f bin"?
Creo que Linux no ejecutará un binario que no esté en formato ELF. No puedo encontrar una herramienta que convierta binarios planos a ELF, pero puedes hacer trampa poniendo la información de ELF en foo.asm, usando la técnica descrita aquí:
Podemos ver la especificación ELF, y/usr/include/linux/elf.h, y los ejecutables creados por las herramientas estándar, para averiguar cómo debería verse nuestro ejecutable ELF vacío. Pero, si eres del tipo impaciente, puedes usar el que he proporcionado aquí:
BITS 32
org 0x08048000
ehdr: ; Elf32_Ehdr
db 0x7F, "ELF", 1, 1, 1, 0 ; e_ident
times 8 db 0
dw 2 ; e_type
dw 3 ; e_machine
dd 1 ; e_version
dd _start ; e_entry
dd phdr - $$ ; e_phoff
dd 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf32_Phdr
dd 1 ; p_type
dd 0 ; p_offset
dd $$ ; p_vaddr
dd $$ ; p_paddr
dd filesize ; p_filesz
dd filesize ; p_memsz
dd 5 ; p_flags
dd 0x1000 ; p_align
phdrsize equ $ - phdr
_start:
; your program here
filesize equ $ - $$
Esta imagen contiene un encabezado ELF, que identifica el archivo como un ejecutable Intel 386, sin tabla de encabezado de sección y una tabla de encabezado de programa que contiene una entrada. Dicha entrada le indica al cargador de programas que cargue todo el archivo en la memoria (es un comportamiento normal que un programa incluya su encabezado ELF y la tabla de encabezado de programa en su imagen de memoria) comenzando en la dirección de memoria 0x08048000 (que es la dirección predeterminada para cargar los ejecutables) y comenzar a ejecutar el código en _start, que aparece inmediatamente después de la tabla de encabezado de programa. Sin segmento .data, sin segmento bss, sin comentarios, nada más que las necesidades básicas.
Entonces, agreguemos nuestro pequeño programa:
; tiny.asm
org 0x08048000
;
; (as above)
;
_start: mov bl, 42 xor eax, eax inc eax int 0x80 filesize equ $ - $$
y pruébalo:
$ nasm -f bin -o a.out tiny.asm
$ chmod +x a.out
$ ./a.out ; echo $?
42