126 lines
3.8 KiB
Plaintext
126 lines
3.8 KiB
Plaintext
|
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 */
|
||
|
|
||
|
```
|