Created
January 18, 2021 12:24
-
-
Save mrvn/91a9eb78a558982ca92499e16888c980 to your computer and use it in GitHub Desktop.
minmal elf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let magic = "\x7FELF" | |
let class_32_bit = '\x01' | |
let class_64_bit = '\x02' | |
let data_little_endian = '\x01' | |
let data_big_endian = '\x02' | |
let ident_version = '\x01' | |
let osabi_system_V = '\x00' | |
let osabi_linux = '\x03' | |
let abiversion = '\x00' | |
let pad = "\x00\x00\x00\x00\x00\x00\x00" | |
let type_none = 0 | |
let type_rel = 1 | |
let type_exec = 2 | |
let type_dyn = 3 | |
let type_core = 4 | |
let type_loos = 0xFE00 | |
let type_hios = 0xFEFF | |
let type_loproc = 0xFF00 | |
let type_hiproc = 0xFFFF | |
let machine_arm = 0x28 | |
let machine_amd64 = 0x3E | |
let machine_arm64 = 0xB7 | |
let version = 1 | |
let header_size = 0x40 | |
let prog_header_size = 0x38 | |
let section_header_size = 0x40 | |
let default_prog_start = 0x100000L | |
let output_uint16_little out x = | |
output_char out (char_of_int (x land 0xFF)); | |
output_char out (char_of_int ((x lsr 8) land 0xFF)) | |
let output_uint32_little out x = | |
output_char out (char_of_int (x land 0xFF)); | |
output_char out (char_of_int ((x lsr 8) land 0xFF)); | |
output_char out (char_of_int ((x lsr 16) land 0xFF)); | |
output_char out (char_of_int ((x lsr 24) land 0xFF)) | |
let output_uint64_little out x = | |
for i = 0 to 7 do | |
let t = Int64.logand (Int64.shift_right_logical x (i * 8)) 0xFFL in | |
output_char out (char_of_int (Int64.to_int t)); | |
done | |
type flags = | |
| Text | |
| RoData | |
| Data | |
| BSS | |
type section = { | |
name : string; | |
start : int64; | |
size : int64; | |
flags : flags; | |
data : string; | |
mutable file_off : int64; | |
} | |
type prog = { | |
prog_start : int64; | |
sections : section array; | |
} | |
let write_header out prog = | |
let program_header_off = Int64.of_int header_size in (* program header follows header *) | |
let program_header_num = 1 in | |
let section_header_off = | |
Int64.of_int (header_size + program_header_num * prog_header_size) | |
in | |
let section_header_num = 3 | |
in | |
output_string out magic; | |
output_char out class_64_bit; | |
output_char out data_little_endian; | |
output_char out ident_version; | |
output_char out osabi_system_V; | |
output_char out abiversion; | |
output_string out pad; | |
output_uint16_little out type_dyn; | |
output_uint16_little out machine_amd64; | |
output_uint32_little out version; | |
output_uint64_little out prog.prog_start; | |
output_uint64_little out program_header_off; | |
output_uint64_little out section_header_off; | |
output_uint32_little out 0; (* flags *) | |
output_uint16_little out header_size; | |
output_uint16_little out prog_header_size; | |
output_uint16_little out program_header_num; | |
output_uint16_little out section_header_size; | |
output_uint16_little out section_header_num; | |
output_uint16_little out (Array.length prog.sections + 1); (* index of section names *) | |
(* return offset in file *) | |
0x40 | |
let write_program_headers out off prog = | |
let rec loop n off file_off = | |
if n = Array.length prog.sections | |
then off | |
else | |
let section = prog.sections.(n) in | |
if section.flags = BSS | |
then loop (n + 1) off file_off | |
else | |
begin | |
section.file_off <- file_off; | |
output_uint32_little out 1; (* type = PT_LOAD *) | |
(match section.flags with (* flags *) | |
| Text -> output_uint32_little out 5 (* E *) | |
| RoData -> output_uint32_little out 4 (* R *) | |
| Data -> output_uint32_little out 6 (* RW *) | |
| BSS -> assert false | |
); | |
output_uint64_little out file_off; | |
output_uint64_little out section.start; (* vaddr *) | |
output_uint64_little out section.start; (* paddr *) | |
output_uint64_little out 4096L; (*section.size; (* file size *)*) | |
output_uint64_little out 4096L; (*section.size; (* mem size *)*) | |
output_uint64_little out 4096L; (* align *) | |
let off = off + prog_header_size in | |
let file_off = Int64.add file_off section.size in | |
(* align to page *) | |
let file_off = Int64.add file_off 4095L in | |
let file_off = Int64.logand file_off (Int64.lognot 4095L) in | |
loop (n + 1) off file_off | |
end | |
in | |
loop 0 off 4096L | |
let write_section_headers out off prog = | |
(* write NULL section *) | |
output_uint32_little out 0; (* name: offset into .shstrtab *) | |
output_uint32_little out 0x0; (* NULL *) | |
output_uint64_little out 0x0L; (* flags: *) | |
output_uint64_little out 0L; (* addr *) | |
output_uint64_little out 0L; (* offset *) | |
output_uint64_little out 0L; (* size *) | |
output_uint32_little out 0; (* link *) | |
output_uint32_little out 0; (* info *) | |
output_uint64_little out 0L; (* align *) | |
output_uint64_little out 0L; (* entry size *) | |
let off = off + 0x40 in | |
(* other sections *) | |
let rec loop n off strings = | |
let name_off = String.length strings in | |
if n = Array.length prog.sections | |
then (* write section names *) | |
let strings = strings ^ ".shstrtab\x00" in | |
(* output section header *) | |
output_uint32_little out name_off; (* name: offset into .shstrtab *) | |
output_uint32_little out 0x03; (* strtab *) | |
output_uint64_little out 0x20L; (* flags: strings *) | |
output_uint64_little out 0L; (* addr *) | |
output_uint64_little out (Int64.of_int (off + 0x40)); (* offset *) | |
output_uint64_little out (Int64.of_int (String.length strings)); (* size *) | |
output_uint32_little out 0; (* link *) | |
output_uint32_little out 0; (* info *) | |
output_uint64_little out 1L; (* align *) | |
output_uint64_little out 0L; (* entry size *) | |
(* output actual section *) | |
output_string out strings; | |
(* return offset in file *) | |
off + 0x40 + String.length strings | |
else | |
let section = prog.sections.(n) in | |
let strings = strings ^ section.name ^ "\x00" in | |
output_uint32_little out name_off; (* name: index into .shstrtab *) | |
output_uint32_little out 0x01; (* progbits *) | |
(match section.flags with (* flags *) | |
| Text -> output_uint64_little out 0x6L; (* alloc exec *) | |
| RoData -> output_uint64_little out 0x2L; (* alloc *) | |
| Data -> output_uint64_little out 0x3L; (* write alloc *) | |
| BSS -> output_uint64_little out 0x3L; (* write alloc *) | |
); | |
output_uint64_little out section.start; (* addr *) | |
output_uint64_little out section.file_off; (* offset *) | |
output_uint64_little out 4096L; (* section.size; size *) | |
output_uint32_little out 0; (* link *) | |
output_uint32_little out 0; (* info *) | |
output_uint64_little out 4096L; (* align *) | |
output_uint64_little out 0L; (* entry size *) | |
loop (n + 1) (off + section_header_size) strings | |
in | |
loop 0 off "\x00" | |
let write_sections out off prog = | |
assert (off <= 4096); | |
let rec pad off = | |
if off land 4095 = 0 | |
then off | |
else | |
begin | |
output_char out '\x00'; | |
pad (off + 1) | |
end | |
in | |
let off = | |
Array.fold_left | |
(fun off section -> | |
if section.flags = BSS | |
then off | |
else | |
let off = pad off in | |
output_string out section.data; | |
let off = off + String.length section.data in | |
pad off) | |
off | |
prog.sections | |
in | |
off | |
let write filename prog = | |
let out = | |
open_out_gen | |
[Open_wronly; Open_binary; Open_creat; Open_trunc] | |
0o776 | |
filename | |
in | |
let off = write_header out prog in | |
let off = write_program_headers out off prog in | |
let off = write_section_headers out off prog in | |
let _ = write_sections out off prog in | |
close_out out |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment