Title: Slim Summer Elf Brief: Making of minimal x86 (Linux) ELF executable. Date: 1684666702 Tags: Programming, Linux, C CSS: /style.css Code below was composed for [4mb-jam](https://itch.io/jam/4mb-jam-2023) which I didn't finish. It was tested on `Zorin OS 16.2 x86_64`, but should be compatible with any x86/i386 operating system using ELF executable format (besides the system call part) What's going on: * Amalgamation of shell script and C source, it's possible because of them both having `#if` style directives and similar comment syntax. Also note the usage of shebang starting with `/`. * ELF header is created via `GNU Assembler`. * Custom link script allows for drop of unnecessary data produced by `GNU Linker` by default. There's *a lot* of it it turns out. * One can pass a `DEBUG` argument when compiling so that debug symbols would be generated. ### Source ### ```c //bin/sh #if 0 set -e cat << ELF_HEADER_SOURCE > ./elf-header.as elfoff = 0x08048000 vaddr = 0x08048000 .text ehdrstart: .byte 0x7F # e_ident .ascii "ELF" .skip 3, 1 .skip 9, 0 .word 2 # e_type .word 3 # e_machine .long 1 # e_version .long entry # e_entry .long phdrstart - elfoff # e_phoff .long 0 # e_shoff .long 0 # e_flags .word ehdrsize # e_ehsize .word 32 # e_phentsize .word 1 # e_phnum .skip 6, 0 ehdrsize = . - ehdrstart phdrstart: #PT_LOAD .long 1 # p_type .long 0 # p_offset .long vaddr # p_vaddr .long 0 # p_paddr .long filesz # p_filesz .long memsz # p_memsz .long 7 # p_flags .long 0x0000 # p_align ELF_HEADER_SOURCE cat << LINKER_SCRIPT_SOURCE > ./ld.scr SECTIONS { . = 0x08048000; filestart = .; .elf : { ./elf-header.o (.text) } .text ALIGN(0x1) : SUBALIGN(0x1) { *(.text*) *(.rodata*) } .data ALIGN(0x1) : SUBALIGN(0x1) { *(.data*) } filesz = . - filestart; .bss : { *(.bss*) } memsz = . - filestart; /DISCARD/ : { *(.note.*) *(.gnu*) *(.gcc*) *(.comment) *(.eh_frame*) } } OUTPUT_FORMAT(binary) LINKER_SCRIPT_SOURCE CFLAGS="-x c -std=gnu99 $0 -m32 -nostdlib -fno-pie -DELF -Wall -Wextra -Wpedantic -Werror" LDFLAGS="-m elf_i386" if [ ! -z "$1" ] && [ $1 = DEBUG ]; then CFLAGS="$CFLAGS -O0 -g3 -ggdb -DDEBUG" LDFLAGS="$LDFLAGS -eentry" else CFLAGS="$CFLAGS -Os" LDFLAGS="$LDFLAGS -T ld.scr -s" fi as --32 -o elf-header.o elf-header.as cc -c -o ./elf.o $CFLAGS ld -o elf ./elf-header.o ./elf.o $LDFLAGS ./elf exit; #endif #ifdef ELF /* https://man7.org/linux/man-pages/man2/exit.2.html */ #define SYS_EXIT(p_return_code) \ { \ asm volatile("int $0x80" : : "a"(1), "b"(p_return_code)); \ __builtin_unreachable(); \ } /* https://man7.org/linux/man-pages/man2/write.2.html */ #define SYS_WRITE(p_fd, p_msg, p_msg_len) \ asm volatile("int $0x80" \ : "=a"(sys_result) \ : "a"(4), "b"(p_fd), "c"(p_msg), "d"(p_msg_len)) __attribute((naked)) void entry(void) { static int sys_result; SYS_WRITE(1, "hello world!\n", 13); SYS_EXIT(0); } #endif /* #ifdef ELF */ ```