mjestecko/articles/tiny-elf/page.mmd

126 lines
3.8 KiB
Plaintext
Raw Normal View History

2023-05-21 14:25:19 +00:00
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 */
```