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