Skip to content

Instantly share code, notes, and snippets.

@mrvn
Created January 18, 2021 12:24
Show Gist options
  • Save mrvn/91a9eb78a558982ca92499e16888c980 to your computer and use it in GitHub Desktop.
Save mrvn/91a9eb78a558982ca92499e16888c980 to your computer and use it in GitHub Desktop.
minmal elf
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