refactor dependencies
[ginge.git] / loader / loader.c
CommitLineData
55fe8e70 1// vim:shiftwidth=2:expandtab
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <elf.h>
6#include <sys/mman.h>
7
11913091 8#include "header.h"
7fd42181 9#include "realfuncs.h"
11913091 10
55fe8e70 11#define CHECK_(val, fail_operator, expect, err_msg) \
12 if (val fail_operator expect) { \
13 fprintf(stderr, err_msg ", exiting (%d)\n", (int)(long)val); \
14 return 1; \
15 }
16
17#define CHECK_EQ(val, expect, err_msg) \
18 CHECK_(val, !=, expect, err_msg)
19
20#define CHECK_NE(val, expect, err_msg) \
21 CHECK_(val, ==, expect, err_msg)
22
23#define HDR_CHECK_EQ(field, expect, err_msg) \
24 CHECK_(hdr.field, !=, expect, err_msg)
25
26#define HDR_CHECK_NE(field, expect, err_msg) \
27 CHECK_(hdr.field, ==, expect, err_msg)
28
29#define FAIL_PERROR(msg) { \
30 perror(msg); \
31 return 1; \
32}
33
55fe8e70 34typedef struct {
35 unsigned long start;
36 unsigned long end;
37} maps_range;
38
39static int is_range_used(maps_range *maps, int map_cnt, unsigned long start, unsigned long end)
40{
41 int i;
42 for (i = 0; i < map_cnt; i++) {
43 if (maps[i].end <= start)
44 continue;
45 if (end <= maps[i].start)
46 continue;
47
48 return i + 1;
49 }
50
51 return 0;
52}
53
54extern char **environ;
55fe8e70 55
56int main(int argc, char *argv[])
57{
11913091 58 void *lowest_segment = (void *)-1;
55fe8e70 59 Elf32_Ehdr hdr;
60 Elf32_Phdr *phdr;
61 FILE *fi;
62 maps_range maps[16];
63 int map_cnt;
306e06f7 64 int i, ret, envc, sfp;
65 long *stack_frame;
55fe8e70 66
306e06f7 67 if (argc < 2) {
68 fprintf(stderr, "usage: %s <program> [args]\n", argv[0]);
55fe8e70 69 return 1;
70 }
71
72 fi = fopen("/proc/self/maps", "r");
73 CHECK_NE(fi, NULL, "fopen maps");
74
75 for (i = 0; i < ARRAY_SIZE(maps); i++) {
76 ret = fscanf(fi, "%lx-%lx %*s %*s %*s %*s %*s\n", &maps[i].start, &maps[i].end);
7fd42181 77 if (ret <= 0)
55fe8e70 78 break;
79 CHECK_EQ(ret, 2, "maps parse error");
80 }
81 fclose(fi);
82 map_cnt = i;
83 CHECK_NE(map_cnt, 0, "no maps");
84 CHECK_NE(map_cnt, ARRAY_SIZE(maps), "too many maps");
85
86 fi = fopen(argv[1], "rb");
87 if (fi == NULL)
88 FAIL_PERROR("fopen");
89
90 if (fread(&hdr, 1, sizeof(hdr), fi) != sizeof(hdr))
91 FAIL_PERROR("too small or");
92
93 if (memcmp(hdr.e_ident, ELFMAG "\x01\x01", SELFMAG + 2) != 0) {
94 fprintf(stderr, "not 32bit LE ELF?\n");
95 return 1;
96 }
97
98 HDR_CHECK_EQ(e_type, ET_EXEC, "not executable");
306e06f7 99 HDR_CHECK_EQ(e_machine, EM_ARM, "not ARM");
55fe8e70 100 HDR_CHECK_EQ(e_phentsize, sizeof(Elf32_Phdr), "bad PH entry size");
101 HDR_CHECK_NE(e_phnum, 0, "no PH entries");
102
103 phdr = malloc(hdr.e_phnum * hdr.e_phentsize);
104 CHECK_NE(phdr, NULL, "OOM");
105
106 if (fread(phdr, hdr.e_phentsize, hdr.e_phnum, fi) != hdr.e_phnum)
107 FAIL_PERROR("too small or");
108
109 for (i = 0; i < hdr.e_phnum; i++) {
110 Elf32_Addr end_addr = phdr[i].p_vaddr + phdr[i].p_memsz;
111 Elf32_Addr align;
112 void *ptr, *map_ptr;
113
114 if (phdr[i].p_type == PT_NOTE)
115 continue;
116 if (phdr[i].p_type != PT_LOAD) {
117 fprintf(stderr, "skipping section %d\n", phdr[i].p_type);
118 continue;
119 }
120
121 ret = is_range_used(maps, map_cnt, phdr[i].p_vaddr, end_addr);
122 if (ret) {
123 fprintf(stderr, "segment %d (%08x-%08x) hits %08lx-%08lx in maps\n",
124 i, phdr[i].p_vaddr, end_addr, maps[ret - 1].start, maps[ret - 1].end);
125 return 1;
126 }
127
4d045184 128 log("load %d %08x-%08x from %08x\n", phdr[i].p_type,
55fe8e70 129 phdr[i].p_vaddr, end_addr, phdr[i].p_offset);
130
131 align = phdr[i].p_vaddr & 0xfff;
132 map_ptr = (void *)(phdr[i].p_vaddr - align);
133 ptr = mmap(map_ptr, phdr[i].p_memsz + align, PROT_READ|PROT_WRITE|PROT_EXEC,
134 MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
135 if (ptr == MAP_FAILED || ptr != map_ptr)
136 FAIL_PERROR("mmap");
137
138 if (phdr[i].p_filesz > 0) {
139 if (fseek(fi, phdr[i].p_offset, SEEK_SET) != 0)
140 FAIL_PERROR("fseek");
141 if (fread((char *)ptr + align, 1, phdr[i].p_filesz, fi) != phdr[i].p_filesz)
142 FAIL_PERROR("too small or");
11913091 143
144 if (phdr[i].p_flags & PF_X)
145 do_patches((char *)ptr + align, phdr[i].p_filesz);
55fe8e70 146 }
11913091 147
148 if (map_ptr < lowest_segment)
149 lowest_segment = map_ptr;
55fe8e70 150 }
151
11913091 152 emu_init(lowest_segment);
153
306e06f7 154 // generate stack frame: argc, argv[], NULL, env[], NULL
155 for (envc = 0; environ[envc] != NULL; envc++)
156 ;
55fe8e70 157
306e06f7 158 stack_frame = calloc(argc + envc + 3, sizeof(stack_frame[0]));
159 if (stack_frame == NULL) {
160 fprintf(stderr, "stack_frame OOM\n");
161 return 1;
162 }
55fe8e70 163
306e06f7 164 sfp = 0;
165 stack_frame[sfp++] = argc - 1;
166 for (i = 1; i < argc; i++)
167 stack_frame[sfp++] = (long)argv[i];
168 stack_frame[sfp++] = 0;
169 for (i = 0; i < envc; i++)
170 stack_frame[sfp++] = (long)environ[i];
171 stack_frame[sfp++] = 0;
172
4d045184 173 log("entering %08x, %d stack entries\n", hdr.e_entry, sfp);
306e06f7 174 do_entry(hdr.e_entry, stack_frame, sfp, NULL);
175
176 fprintf(stderr, "do_entry failed!\n");
177 return 1;
55fe8e70 178}
179