~ current output point, string pointer : pack-raw-string { unpack8 dup } { 3roll swap pack8 swap } while drop drop ; : origin 0x08000000 ; heap hexdump latest @ .hex space here @ .hex newline latest @ @ word-heading latest @ @ hexdump latest @ word-heading latest @ hexdump : foo latest @ word-heading latest @ hexdump ~ s" labels" create 8 allocate s" labels" variable ; foo latest @ word-heading latest @ hexdump s" labels" find .hex bye ~ ~~ ~ ~~ ELF header ~ ~~ ~ ~~ This is the top-level ELF header, for the entire file. An ELF always ~ ~~ has exactly one of this header, which is always at the start of the file. ~ ~~ : elf-file-header 0x7f pack8 s" ELF" pack-raw-string ~ magic number 2 pack8 ~ 64-bit 1 pack8 ~ little-endian 1 pack8 ~ ELF header format v1 0 pack8 ~ System-V ABI 0 pack64 ~ (padding) 2 pack16 ~ executable 0x3e pack16 ~ Intel x86-64 1 pack32 ~ ELF format version ~ Compute the entry pointer. origin 0x78 + pack64 ~ entry point ~ This includes the origin, intentionally. 0 pack64 ~ program header offset ~ We place the program header immediately after the ELF header. This ~ offset is from the start of the file. 0 pack64 ~ section header offset 0 pack32 ~ processor flags 64 pack16 ~ ELF header size 56 pack16 ~ program header entry size 1 pack16 ~ number of program header entries 0 pack16 ~ section header entry size 0 pack16 ~ number of section header entries 0 pack16 ~ section name string table index ; ~ ~~ ~ ~~ Program header ~ ~~ ~ ~~ An ELF program header consists of any number of these entries; they are ~ ~~ always consecutive, but may be anywhere in the file. We always have ~ ~~ exactly one, and it's always right after the ELF file header. ~ ~~ : elf-program-header 1 pack32 ~ "loadable" segment type 0x05 pack32 ~ read+execute permission 0 pack64 ~ offset in file origin pack64 ~ virtual address ~ required, but can be anything, subject to alignment 0 pack64 ~ physical address (ignored) ~ Fill in 0 as the file size for now, to avoid uninitialized memory. 0 pack64 ~ size in file ~ TODO call use-label here 0 pack64 ~ size in memory ~ TODO call use-label here 0 pack64 ~ segment alignment ~ for relocation, but this doesn't apply to us ; : output-start-routine ~ lit 1 :rax mov-reg64-imm32 ; : all-contents ~ current output point elf-file-header elf-program-header output-start-routine ; 0x1000 allocate dup ~ output memory start, current output point all-contents ~ output memory start, current output point over - swap sys-write bye