]> git.sesse.net Git - pistorm/blob - platforms/amiga/hunk-reloc.c
4869600f95571b6515a4dae8580fc20afd6db0dc
[pistorm] / platforms / amiga / hunk-reloc.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <endian.h>
7 #include "hunk-reloc.h"
8
9 #ifdef FAKESTORM
10 #define lseek64 lseek
11 #endif
12
13 #define DEBUG(...)
14 //#define DEBUG printf
15
16 #define BE(val) be32toh(val)
17 #define BE16(val) be16toh(val)
18
19 #define READLW(a, b) fread(&a, 4, 1, b); a = be32toh(a);
20 #define READW(a, b) fread(&a, 2, 1, b); a = be16toh(a);
21
22 uint32_t lw = 0;
23 static uint32_t file_offset = 0, add_size = 0;
24
25 char *hunk_id_name(uint32_t index) {
26     switch (index) {
27         case HUNKTYPE_HEADER:
28             return "HUNK_HEADER";
29         case HUNKTYPE_CODE:
30             return "HUNK_CODE";
31         case HUNKTYPE_HUNK_RELOC32:
32             return "HUNK_RELOC32";
33         case HUNKTYPE_SYMBOL:
34             return "HUNK_SYMBOL";
35         case HUNKTYPE_BSS:
36             return "HUNK_BSS";
37         case HUNKTYPE_DATA:
38             return "HUNK_DATA";
39         case HUNKTYPE_END:
40             return "HUNK_END";
41         default:
42             return "UNKNOWN HUNK TYPE";
43     }
44 }
45
46 int process_hunk(uint32_t index, struct hunk_info *info, FILE *f, struct hunk_reloc *r) {
47     if (!f)
48         return -1;
49     
50     uint32_t discard = 0, cur_hunk = 0, offs32 = 0;
51     
52     switch (index) {
53         case HUNKTYPE_HEADER:
54             DEBUG("Processing hunk header.\n");
55             do {
56                 READLW(discard, f);
57                 if (discard) {
58                     info->libnames[info->num_libs] = malloc(discard * 4);
59                     fread(info->libnames[info->num_libs], discard, 4, f);
60                     info->num_libs++;
61                 }
62             } while (discard);
63             
64             READLW(info->table_size, f);
65             DEBUG("Table size: %d\n", info->table_size);
66             READLW(info->first_hunk, f);
67             READLW(info->last_hunk, f);
68             info->num_hunks = (info->last_hunk - info->first_hunk) + 1;
69             DEBUG("First: %d Last: %d Num: %d\n", info->first_hunk, info->last_hunk, info->num_hunks);
70             info->hunk_sizes = malloc(info->num_hunks * 4);
71             info->hunk_offsets = malloc(info->num_hunks * 4);
72             for (uint32_t i = 0; i < info->table_size; i++) {
73                 READLW(info->hunk_sizes[i], f);
74                 DEBUG("Hunk %d: %d (%.8X)\n", i, info->hunk_sizes[i] * 4, info->hunk_sizes[i] * 4);
75             }
76             return 0;
77             break;
78         case HUNKTYPE_CODE:
79             DEBUG("Hunk %d: CODE.\n", info->current_hunk);
80             READLW(discard, f);
81             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
82             DEBUG("Code hunk size: %d (%.8X)\n", discard * 4, discard * 4);
83             fseek(f, discard * 4, SEEK_CUR);
84             return 0;
85             break;
86         case HUNKTYPE_HUNK_RELOC32:
87             DEBUG("Hunk %d: RELOC32.\n", info->current_hunk);
88             DEBUG("Processing Reloc32 hunk.\n");
89             do {
90                 READLW(discard, f);
91                 if (discard && discard != 0xFFFFFFFF) {
92                     READLW(cur_hunk, f);
93                     DEBUG("Relocating %d offsets pointing to hunk %d.\n", discard, cur_hunk);
94                     for(uint32_t i = 0; i < discard; i++) {
95                         READLW(offs32, f);
96                         DEBUG("#%d: @%.8X in hunk %d\n", i + 1, offs32, cur_hunk);
97                         r[info->reloc_hunks].offset = offs32;
98                         r[info->reloc_hunks].src_hunk = info->current_hunk;
99                         r[info->reloc_hunks].target_hunk = cur_hunk;
100                         info->reloc_hunks++;
101                     }
102                 }
103             } while(discard);
104             return 0;
105             break;
106         case HUNKTYPE_SYMBOL:
107             DEBUG("Hunk %d: SYMBOL.\n", info->current_hunk);
108             DEBUG("Processing Symbol hunk.\n");
109             READLW(discard, f);
110             do {
111                 if (discard) {
112                     char sstr[256];
113                     memset(sstr, 0x00, 256);
114                     fread(sstr, discard, 4, f);
115                     READLW(discard, f);
116                     DEBUG("Symbol: %s - %.8X\n", sstr, discard);
117                 }
118                 READLW(discard, f);
119             } while (discard);
120             return 0;
121             break;
122         case HUNKTYPE_BSS:
123             DEBUG("Hunk %d: BSS.\n", info->current_hunk);
124             READLW(discard, f);
125             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
126             DEBUG("Skipping BSS hunk. Size: %d\n", discard * 4);
127             add_size += (discard * 4);
128             return 0;
129         case HUNKTYPE_DATA:
130             DEBUG("Hunk %d: DATA.\n", info->current_hunk);
131             READLW(discard, f);
132             info->hunk_offsets[info->current_hunk] = ftell(f) - file_offset;
133             DEBUG("Skipping data hunk. Size: %d.\n", discard * 4);
134             fseek(f, discard * 4, SEEK_CUR);
135             return 0;
136             break;
137         case HUNKTYPE_END:
138             DEBUG("END: Ending hunk %d.\n", info->current_hunk);
139             info->current_hunk++;
140             return 0;
141             break;
142         default:
143             DEBUG("Unknown hunk type %.8X! Can't process!\n", index);
144             break;
145     }
146
147     return -1;
148 }
149
150 void reloc_hunk(struct hunk_reloc *h, uint8_t *buf, struct hunk_info *i) {
151     uint32_t rel = i->hunk_offsets[h->target_hunk];
152     uint32_t *src_ptr = (uint32_t *)(&buf[i->hunk_offsets[h->src_hunk] + h->offset]);
153
154     uint32_t src = be32toh(*src_ptr);
155     uint32_t dst = src + i->base_offset + rel;
156     DEBUG("%.8X -> %.8X\n", src, dst);
157     *src_ptr = htobe32(dst);
158 }
159
160 void process_hunks(FILE *in, struct hunk_info *h_info, struct hunk_reloc *r, uint32_t offset) {
161     READLW(lw, in);
162     DEBUG("Hunk ID: %.8X (%s)\n", lw, hunk_id_name(lw));
163
164     file_offset = offset;
165     add_size = 0;
166
167     while (!feof(in) && process_hunk(lw, h_info, in, r) != -1) {
168         READLW(lw, in);
169         if (feof(in)) goto end_parse;
170         DEBUG("Hunk ID: %.8X (%s)\n", lw, hunk_id_name(lw));
171         DEBUG("File pos: %.8lX\n", ftell(in) - file_offset);
172     }
173     end_parse:;
174     DEBUG("Done processing hunks.\n");
175 }
176
177 void reloc_hunks(struct hunk_reloc *r, uint8_t *buf, struct hunk_info *h_info) {
178     DEBUG("Relocating %d offsets.\n", h_info->reloc_hunks);
179     for (uint32_t i = 0; i < h_info->reloc_hunks; i++) {
180         DEBUG("Relocating offset %d.\n", i);
181         reloc_hunk(&r[i], buf, h_info);
182     }
183     DEBUG("Done relocating offsets.\n");
184 }
185
186 struct LoadSegBlock {
187     uint32_t   lsb_ID;
188     uint32_t   lsb_SummedLongs;
189     int32_t    lsb_ChkSum;
190     uint32_t   lsb_HostID;
191     uint32_t   lsb_Next;
192     uint32_t   lsb_LoadData[123]; // Assumes 512 byte blocks
193 };
194 #define LOADSEG_IDENTIFIER 0x4C534547
195
196 int load_lseg(int fd, uint8_t **buf_p, struct hunk_info *i, struct hunk_reloc *relocs) {
197     if (fd == -1)
198         return -1;
199
200     uint8_t *block = malloc(512);
201     uint32_t next_blk = 0;
202     struct LoadSegBlock *lsb = (struct LoadSegBlock *)block;
203
204     read(fd, block, 512);
205     if (BE(lsb->lsb_ID) != LOADSEG_IDENTIFIER) {
206         DEBUG("[LOAD_LSEG] Attempted to load a non LSEG-block: %.8X", BE(lsb->lsb_ID));
207         goto fail;
208     }
209
210     char *filename = "data/lsegout.bin";
211     FILE *out = fopen(filename, "wb+");
212
213     DEBUG("[LOAD_LSEG] LSEG data:\n");
214     DEBUG("[LOAD_LSEG] Longs: %d HostID: %d\n", BE(lsb->lsb_SummedLongs), BE(lsb->lsb_HostID));
215     DEBUG("[LOAD_LSEG] Next: %d LoadData: %p\n", BE(lsb->lsb_Next), (void *)lsb->lsb_LoadData);
216     next_blk = BE(lsb->lsb_Next);
217     do {
218         next_blk = BE(lsb->lsb_Next);
219         fwrite(lsb->lsb_LoadData, 4, 123, out);
220         lseek64(fd, next_blk * 512, SEEK_SET);
221         read(fd, block, 512);
222     } while (next_blk != 0xFFFFFFFF);
223     
224     uint32_t file_size = ftell(out);
225     fseek(out, 0, SEEK_SET);
226     uint8_t *buf = malloc(file_size + 1024);
227     fread(buf, file_size, 1, out);
228     fseek(out, 0, SEEK_SET);
229     process_hunks(out, i, relocs, 0x0);
230
231     fclose(out);
232     *buf_p = buf;
233     i->byte_size = file_size;
234     i->alloc_size = file_size + add_size;
235
236     return 0;
237
238 fail:;
239     if (block)
240         free(block);
241
242     return -1;
243 }