summaryrefslogtreecommitdiff
path: root/write_elf.c
blob: adb11a8daf734524442097375b871277eb7ccfed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <elf.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
write_elf(char* restrict file, size_t opcodes_len, char* restrict opcodes) {
  int error                   = 0;

  Elf64_Phdr header_program[] = {
    //{
    //  .p_type   = PT_LOAD,
    //  .p_flags  = PF_R,
    //  .p_offset = 0, /* Segment file offset */
    //  .p_vaddr  = 0x400000, /* Segment virtual address */
    //  .p_paddr  = 0x400000,        /* Segment physical address */
    //  .p_filesz = 0xb0,        /* Segment size in file */
    //  .p_memsz  = 0xb0,      /* Segment size in memory */
    //  .p_align  = 0x1000, /* Segment alignment */
    //},
    {
      .p_type   = PT_LOAD,
      .p_flags  = PF_X | PF_R,
      .p_offset = 0x1000,            /* Segment file offset */
      .p_vaddr  = 0x400000 + 0x1000, /* Segment virtual address */
      .p_paddr  = 0x400000 + 0x1000, /* Segment physical address */
      .p_filesz = opcodes_len,       /* Segment size in file */
      .p_memsz  = opcodes_len,       /* Segment size in memory */
      .p_align  = 0x1,               /* Segment alignment */
    },
  };

  unsigned char string_header_table[] = {0,   '.', 'i', 'n', 'i', 't',
                                         0,   '.', 's', 'h', 's', 't',
                                         'r', 't', 'a', 'b', 0};

  Elf64_Shdr header_section[]         = {
    {0}, // NULL
    {
      // .init
      // Index in section header string table
      .sh_name   = 1,
      .sh_type   = SHT_PROGBITS,
      .sh_flags  = SHF_ALLOC | SHF_EXECINSTR,
      .sh_addr   = 0x401000,
      .sh_offset = 0x1000,
      .sh_size   = opcodes_len,
      /* todo: deps on type */
      .sh_link = 0,
      /* todo: deps on type */
      .sh_info      = 0,
      .sh_addralign = 4,
      .sh_entsize   = 0,
    },
    {
      // .shstrtab Section Header String Table
      // Index in section header string table
      .sh_name   = 7,
      .sh_type   = SHT_STRTAB,
      .sh_flags  = 0,
      .sh_addr   = 0x0,
      .sh_offset = 0x2000,
      .sh_size   = sizeof(string_header_table) / sizeof(string_header_table[0]),
      /* todo: deps on type */
      .sh_link = 0,
      /* todo: deps on type */
      .sh_info      = 0,
      .sh_addralign = 1,
      .sh_entsize   = 0,
    },
  };

  Elf64_Ehdr header = {
    // memset(&header, 0, sizeof(Elf64_Ehdr));
    .e_ident   = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS64, ELFDATA2LSB,
                  EV_CURRENT, ELFOSABI_SYSV},
    .e_type    = ET_EXEC,
    .e_machine = EM_X86_64,
    .e_version = EV_CURRENT,
    // point to VIRTUAL address of _start
    .e_entry = 0x400000 + 0x1000,
    // Program header table offset
    .e_phoff = sizeof(Elf64_Ehdr),
    // Section header table offset
    .e_shoff     = sizeof(Elf64_Ehdr) + sizeof(header_program),
    .e_flags     = 0,
    .e_ehsize    = sizeof(Elf64_Ehdr),
    .e_phentsize = sizeof(Elf64_Phdr),
    // If larger than PN_XNUM, then set to PN_XNUM and store real number in
    // sh_info of first program header entry
    .e_phnum     = 1,
    .e_shentsize = sizeof(header_section[0]),
    // If larger than SHN_LORESERVE, then set to 0 and store real number in
    // sh_size of first section header entry
    .e_shnum = sizeof(header_section) / sizeof(header_section[0]),
    // If larger than SHN_LORESERVE, then set to SHN_XINDEX and store real
    // index
    // in sh_link of first section header entry
    // "Section Header string-table-index
    .e_shstrndx = 2,
  };

  size_t bytes_written = 0;
  FILE* fd             = fopen(file, "w");

  fwrite(&header, sizeof(Elf64_Ehdr), 1, fd);
  fwrite(&header_program, sizeof(Elf64_Phdr),
         sizeof(header_program) / sizeof(header_program[0]), fd);
  fwrite(&header_section, sizeof(Elf64_Shdr),
         sizeof(header_section) / sizeof(header_section[0]), fd);

  fseek(fd, 0x1000, SEEK_SET);

  do {
    bytes_written += fwrite(opcodes, sizeof(char), opcodes_len, fd);
  } while (bytes_written != opcodes_len);

  fseek(fd, 0x2000, SEEK_SET);
  fwrite(string_header_table, sizeof(char),
         sizeof(string_header_table) / sizeof(string_header_table[0]), fd);

  error = fclose(fd);
  if (error) {
    err(EXIT_FAILURE, "no way");
  }
  return 0;
}