aout2hux.c revision 1.7 1 1.1 itohy /*
2 1.4 itohy * aout2hux - convert a.out/ELF executable to Human68k .x format
3 1.1 itohy *
4 1.4 itohy * Read two a.out/ELF format executables with different load addresses
5 1.1 itohy * and generate Human68k .x format executable.
6 1.1 itohy *
7 1.1 itohy * written by Yasha (ITOH Yasufumi)
8 1.1 itohy * public domain
9 1.1 itohy *
10 1.1 itohy * usage:
11 1.1 itohy * aout2hux [ -o output.x ] a.out1 loadaddr1 a.out2 loadaddr2
12 1.1 itohy *
13 1.4 itohy * The input files must be static OMAGIC/NMAGIC m68k a.out executables
14 1.4 itohy * or m68k ELF executables.
15 1.4 itohy * Two executables must have different loading addresses.
16 1.1 itohy * Each of the load address must be a hexadecimal number.
17 1.1 itohy * Load address shall be multiple of 4 for as / ld of NetBSD/m68k.
18 1.1 itohy *
19 1.1 itohy * example:
20 1.4 itohy * % cc -N -static -Wl,-Ttext,0 -o aout1 *.o
21 1.4 itohy * % cc -N -static -Wl,-Ttext,10203040 -o aout2 *.o
22 1.1 itohy * % aout2hux -o foo.x aout1 0 aout2 10203040
23 1.1 itohy *
24 1.7 dsl * $NetBSD: aout2hux.c,v 1.7 2009/03/14 15:36:15 dsl Exp $
25 1.1 itohy */
26 1.1 itohy
27 1.1 itohy #include <sys/types.h>
28 1.1 itohy #ifndef NO_UNISTD
29 1.1 itohy # include <unistd.h>
30 1.1 itohy #endif
31 1.1 itohy #ifndef NO_STDLIB
32 1.1 itohy # include <stdlib.h>
33 1.1 itohy #endif
34 1.1 itohy #include <stdio.h>
35 1.1 itohy #include <string.h>
36 1.1 itohy
37 1.1 itohy #include "type_local.h"
38 1.1 itohy #include "aout68k.h"
39 1.1 itohy #include "hux.h"
40 1.1 itohy
41 1.4 itohy /* fseek() offset type */
42 1.4 itohy typedef long foff_t;
43 1.4 itohy
44 1.1 itohy #ifndef DEFAULT_OUTPUT_FILE
45 1.1 itohy # define DEFAULT_OUTPUT_FILE "out.x"
46 1.1 itohy #endif
47 1.1 itohy
48 1.1 itohy #ifdef DEBUG
49 1.1 itohy # define DPRINTF(x) printf x
50 1.1 itohy #else
51 1.1 itohy # define DPRINTF(x)
52 1.1 itohy #endif
53 1.1 itohy
54 1.4 itohy struct exec_info {
55 1.4 itohy foff_t text_off; /* file offset of text section */
56 1.4 itohy foff_t data_off; /* file offset of data section */
57 1.4 itohy u_int32_t text_size; /* size of text section */
58 1.4 itohy u_int32_t text_pad; /* pad between text and data */
59 1.4 itohy u_int32_t data_size; /* size of data section */
60 1.4 itohy u_int32_t bss_size; /* size of bss */
61 1.4 itohy u_int32_t entry_addr; /* entry point address */
62 1.4 itohy };
63 1.4 itohy
64 1.1 itohy unsigned get_uint16 PROTO((be_uint16_t *be));
65 1.1 itohy u_int32_t get_uint32 PROTO((be_uint32_t *be));
66 1.1 itohy void put_uint16 PROTO((be_uint16_t *be, unsigned v));
67 1.1 itohy void put_uint32 PROTO((be_uint32_t *be, u_int32_t v));
68 1.1 itohy void *do_realloc PROTO((void *p, size_t s));
69 1.1 itohy
70 1.6 dsl static int open_aout(const char *fn, struct aout_m68k *hdr,
71 1.6 dsl struct exec_info *inf);
72 1.4 itohy static int open_elf PROTO((const char *fn, FILE *fp, struct elf_m68k_hdr *hdr,
73 1.4 itohy struct exec_info *inf));
74 1.4 itohy FILE *open_exec PROTO((const char *fn, struct exec_info *inf));
75 1.4 itohy int check_2_exec_inf PROTO((struct exec_info *inf1, struct exec_info *inf2));
76 1.1 itohy int aout2hux PROTO((const char *fn1, const char *fn2,
77 1.1 itohy u_int32_t loadadr1, u_int32_t loadadr2, const char *fnx));
78 1.1 itohy int gethex PROTO((u_int32_t *pval, const char *str));
79 1.1 itohy void usage PROTO((const char *name));
80 1.1 itohy int main PROTO((int argc, char *argv[]));
81 1.1 itohy
82 1.1 itohy #if !defined(bzero) && defined(__SVR4)
83 1.1 itohy # define bzero(d, n) memset((d), 0, (n))
84 1.1 itohy #endif
85 1.1 itohy
86 1.1 itohy /*
87 1.1 itohy * read/write big-endian integer
88 1.1 itohy */
89 1.1 itohy
90 1.1 itohy unsigned
91 1.7 dsl get_uint16(be_uint16_t *be)
92 1.1 itohy {
93 1.1 itohy
94 1.1 itohy return be->val[0] << 8 | be->val[1];
95 1.1 itohy }
96 1.1 itohy
97 1.1 itohy u_int32_t
98 1.7 dsl get_uint32(be_uint32_t *be)
99 1.1 itohy {
100 1.1 itohy
101 1.1 itohy return be->val[0]<<24 | be->val[1]<<16 | be->val[2]<<8 | be->val[3];
102 1.1 itohy }
103 1.1 itohy
104 1.1 itohy void
105 1.7 dsl put_uint16(be_uint16_t *be, unsigned v)
106 1.1 itohy {
107 1.1 itohy
108 1.1 itohy be->val[0] = (u_int8_t) (v >> 8);
109 1.1 itohy be->val[1] = (u_int8_t) v;
110 1.1 itohy }
111 1.1 itohy
112 1.1 itohy void
113 1.7 dsl put_uint32(be_uint32_t *be, u_int32_t v)
114 1.1 itohy {
115 1.1 itohy
116 1.1 itohy be->val[0] = (u_int8_t) (v >> 24);
117 1.1 itohy be->val[1] = (u_int8_t) (v >> 16);
118 1.1 itohy be->val[2] = (u_int8_t) (v >> 8);
119 1.1 itohy be->val[3] = (u_int8_t) v;
120 1.1 itohy }
121 1.1 itohy
122 1.1 itohy void *
123 1.7 dsl do_realloc(void *p, size_t s)
124 1.1 itohy {
125 1.1 itohy
126 1.1 itohy p = p ? realloc(p, s) : malloc(s); /* for portability */
127 1.1 itohy
128 1.1 itohy if (!p) {
129 1.1 itohy fprintf(stderr, "malloc failed\n");
130 1.1 itohy exit(1);
131 1.1 itohy }
132 1.1 itohy
133 1.1 itohy return p;
134 1.1 itohy }
135 1.1 itohy
136 1.1 itohy /*
137 1.4 itohy * check a.out header
138 1.4 itohy */
139 1.4 itohy static int
140 1.7 dsl open_aout(const char *fn, struct aout_m68k *hdr, struct exec_info *inf)
141 1.4 itohy {
142 1.4 itohy int i;
143 1.4 itohy
144 1.4 itohy DPRINTF(("%s: is an a.out\n", fn));
145 1.4 itohy
146 1.4 itohy if ((i = AOUT_GET_MID(hdr)) != AOUT_MID_M68K && i != AOUT_MID_M68K4K) {
147 1.4 itohy fprintf(stderr, "%s: wrong architecture (mid %d)\n", fn, i);
148 1.4 itohy return 1;
149 1.4 itohy }
150 1.4 itohy
151 1.4 itohy /* if unsolved relocations exist, not an executable but an object */
152 1.4 itohy if (hdr->a_trsize.hostval || hdr->a_drsize.hostval) {
153 1.4 itohy fprintf(stderr, "%s: not an executable (object file?)\n", fn);
154 1.4 itohy return 1;
155 1.4 itohy }
156 1.4 itohy
157 1.4 itohy if (AOUT_GET_FLAGS(hdr) & (AOUT_FLAG_PIC | AOUT_FLAG_DYNAMIC)) {
158 1.4 itohy fprintf(stderr, "%s: PIC and DYNAMIC are not supported\n", fn);
159 1.4 itohy return 1;
160 1.4 itohy }
161 1.4 itohy
162 1.4 itohy inf->text_size = get_uint32(&hdr->a_text);
163 1.4 itohy inf->data_size = get_uint32(&hdr->a_data);
164 1.4 itohy inf->bss_size = get_uint32(&hdr->a_bss);
165 1.4 itohy inf->entry_addr = get_uint32(&hdr->a_entry);
166 1.4 itohy inf->text_off = sizeof(struct aout_m68k);
167 1.4 itohy inf->data_off = sizeof(struct aout_m68k) + inf->text_size;
168 1.4 itohy inf->text_pad = -inf->text_size & (AOUT_PAGESIZE(hdr) - 1);
169 1.4 itohy
170 1.4 itohy return 0;
171 1.4 itohy }
172 1.4 itohy
173 1.4 itohy /*
174 1.4 itohy * digest ELF structure
175 1.4 itohy */
176 1.4 itohy static int
177 1.7 dsl open_elf(const char *fn, FILE *fp, struct elf_m68k_hdr *hdr, struct exec_info *inf)
178 1.4 itohy {
179 1.4 itohy int i;
180 1.4 itohy size_t nphdr;
181 1.4 itohy struct elf_m68k_phdr phdr[2];
182 1.4 itohy
183 1.4 itohy DPRINTF(("%s: is an ELF\n", fn));
184 1.4 itohy
185 1.4 itohy if (hdr->e_ident[EI_VERSION] != EV_CURRENT ||
186 1.4 itohy get_uint32(&hdr->e_version) != EV_CURRENT) {
187 1.4 itohy fprintf(stderr, "%s: unknown ELF version\n", fn);
188 1.4 itohy return 1;
189 1.4 itohy }
190 1.4 itohy
191 1.5 itohy if (get_uint16(&hdr->e_type) != ET_EXEC) {
192 1.4 itohy fprintf(stderr, "%s: not an executable\n", fn);
193 1.4 itohy return 1;
194 1.4 itohy }
195 1.4 itohy
196 1.4 itohy if ((i = get_uint16(&hdr->e_machine)) != EM_68K) {
197 1.4 itohy fprintf(stderr, "%s: wrong architecture (%d)\n", fn, i);
198 1.4 itohy return 1;
199 1.4 itohy }
200 1.4 itohy
201 1.4 itohy if ((i = get_uint16(&hdr->e_shentsize)) != SIZE_ELF68K_SHDR) {
202 1.4 itohy fprintf(stderr, "%s: size shdr %d should be %d\n", fn, i,
203 1.4 itohy SIZE_ELF68K_SHDR);
204 1.4 itohy return 1;
205 1.4 itohy }
206 1.4 itohy
207 1.4 itohy if ((i = get_uint16(&hdr->e_phentsize)) != SIZE_ELF68K_PHDR) {
208 1.4 itohy fprintf(stderr, "%s: size phdr %d should be %d\n", fn, i,
209 1.4 itohy SIZE_ELF68K_PHDR);
210 1.4 itohy return 1;
211 1.4 itohy }
212 1.4 itohy
213 1.4 itohy if ((nphdr = get_uint16(&hdr->e_phnum)) != 1 && nphdr != 2) {
214 1.4 itohy fprintf(stderr,
215 1.4 itohy "%s: has %d loadable segments (should be 1 or 2)\n",
216 1.4 itohy fn, nphdr);
217 1.4 itohy return 1;
218 1.4 itohy }
219 1.4 itohy
220 1.4 itohy /* Read ELF program header table. */
221 1.4 itohy if (fseek(fp, (foff_t) get_uint32(&hdr->e_phoff), SEEK_SET)) {
222 1.4 itohy perror(fn);
223 1.4 itohy return 1;
224 1.4 itohy }
225 1.4 itohy if (fread(phdr, sizeof phdr[0], nphdr, fp) != nphdr) {
226 1.4 itohy fprintf(stderr, "%s: can't read ELF program header\n", fn);
227 1.4 itohy return 1;
228 1.4 itohy }
229 1.4 itohy
230 1.4 itohy /* Just error checking. */
231 1.4 itohy for (i = 0; i < (int) nphdr; i++) {
232 1.4 itohy if (get_uint32(&phdr[i].p_type) != PT_LOAD) {
233 1.4 itohy fprintf(stderr,
234 1.4 itohy "%s: program header #%d is not loadable\n",
235 1.4 itohy fn, i);
236 1.4 itohy return 1;
237 1.4 itohy }
238 1.4 itohy }
239 1.4 itohy
240 1.4 itohy if (nphdr == 1 && (get_uint32(&phdr[0].p_flags) & PF_W)) {
241 1.4 itohy /*
242 1.4 itohy * Only one writable section --- probably "ld -N" executable.
243 1.4 itohy * Find out the start of data segment.
244 1.4 itohy */
245 1.4 itohy struct elf_m68k_shdr shdr;
246 1.4 itohy int nshdr;
247 1.4 itohy
248 1.4 itohy nshdr = get_uint16(&hdr->e_shnum);
249 1.4 itohy
250 1.4 itohy /* section #0 always exists and reserved --- skip */
251 1.4 itohy if (nshdr > 1 &&
252 1.4 itohy fseek(fp,
253 1.4 itohy (foff_t) (get_uint32(&hdr->e_shoff) + sizeof shdr),
254 1.4 itohy SEEK_SET)) {
255 1.4 itohy perror(fn);
256 1.4 itohy return 1;
257 1.4 itohy }
258 1.4 itohy for (i = 1; i < nshdr; i++) {
259 1.4 itohy if (fread(&shdr, sizeof shdr, 1, fp) != 1) {
260 1.4 itohy fprintf(stderr,
261 1.4 itohy "%s: can't read ELF section header\n",
262 1.4 itohy fn);
263 1.4 itohy return 1;
264 1.4 itohy }
265 1.4 itohy
266 1.4 itohy DPRINTF(("%s: section header #%d: flags 0x%x\n",
267 1.4 itohy fn, i, get_uint32(&shdr.sh_flags)));
268 1.4 itohy
269 1.4 itohy if (ELF68K_ISDATASEG(&shdr)) {
270 1.4 itohy /*
271 1.4 itohy * data section is found.
272 1.4 itohy */
273 1.4 itohy DPRINTF(("%s: one section, data found\n", fn));
274 1.4 itohy inf->text_off = get_uint32(&phdr[0].p_offset);
275 1.4 itohy inf->text_size = get_uint32(&shdr.sh_offset) -
276 1.4 itohy inf->text_off;
277 1.4 itohy inf->text_pad = 0;
278 1.4 itohy inf->data_off = inf->text_off + inf->text_size;
279 1.4 itohy inf->data_size = get_uint32(&phdr[0].p_filesz) -
280 1.4 itohy inf->text_size;
281 1.4 itohy inf->bss_size = get_uint32(&phdr[0].p_memsz) -
282 1.4 itohy get_uint32(&phdr[0].p_filesz);
283 1.4 itohy inf->entry_addr = get_uint32(&hdr->e_entry);
284 1.4 itohy goto data_found;
285 1.4 itohy }
286 1.4 itohy }
287 1.4 itohy /*
288 1.4 itohy * No data section found --- probably text + bss.
289 1.4 itohy */
290 1.4 itohy DPRINTF(("%s: one section, no data section\n", fn));
291 1.4 itohy inf->text_size = get_uint32(&phdr[0].p_filesz);
292 1.4 itohy inf->data_size = 0;
293 1.4 itohy inf->bss_size = get_uint32(&phdr[0].p_memsz) - inf->text_size;
294 1.4 itohy inf->entry_addr = get_uint32(&hdr->e_entry);
295 1.4 itohy inf->text_off = get_uint32(&phdr[0].p_offset);
296 1.4 itohy inf->data_off = 0;
297 1.4 itohy inf->text_pad = 0;
298 1.4 itohy data_found:;
299 1.4 itohy } else if (nphdr == 1) {
300 1.4 itohy /*
301 1.4 itohy * Only one non-writable section --- pure text program?
302 1.4 itohy */
303 1.4 itohy DPRINTF(("%s: one RO section\n", fn));
304 1.4 itohy inf->text_size = get_uint32(&phdr[0].p_filesz);
305 1.4 itohy inf->data_size = 0;
306 1.4 itohy inf->bss_size = 0;
307 1.4 itohy inf->entry_addr = get_uint32(&hdr->e_entry);
308 1.4 itohy inf->text_off = get_uint32(&phdr[0].p_offset);
309 1.4 itohy inf->data_off = 0;
310 1.4 itohy inf->text_pad = get_uint32(&phdr[0].p_memsz) - inf->text_size;
311 1.4 itohy } else {
312 1.4 itohy /*
313 1.4 itohy * two sections
314 1.4 itohy * text + data assumed.
315 1.4 itohy */
316 1.4 itohy int t = 0, d = 1, tmp; /* first guess */
317 1.4 itohy #define SWAP_T_D tmp = t, t = d, d = tmp
318 1.4 itohy
319 1.4 itohy DPRINTF(("%s: two sections\n", fn));
320 1.4 itohy
321 1.4 itohy /* Find out text and data. */
322 1.4 itohy if (get_uint32(&phdr[t].p_vaddr) > get_uint32(&phdr[d].p_vaddr))
323 1.4 itohy SWAP_T_D;
324 1.4 itohy
325 1.4 itohy if ((get_uint32(&phdr[t].p_flags) & PF_X) == 0 &&
326 1.4 itohy get_uint32(&phdr[d].p_flags) & PF_X)
327 1.4 itohy SWAP_T_D;
328 1.4 itohy
329 1.4 itohy if ((get_uint32(&phdr[d].p_flags) & PF_W) == 0 &&
330 1.4 itohy get_uint32(&phdr[t].p_flags) & PF_W)
331 1.4 itohy SWAP_T_D;
332 1.4 itohy #undef SWAP_T_D
333 1.4 itohy
334 1.4 itohy /* Are the text/data sections correctly detected? */
335 1.4 itohy if (get_uint32(&phdr[t].p_vaddr) >
336 1.4 itohy get_uint32(&phdr[d].p_vaddr)) {
337 1.4 itohy fprintf(stderr, "%s: program sections not in order\n",
338 1.4 itohy fn);
339 1.4 itohy return 1;
340 1.4 itohy }
341 1.4 itohy
342 1.4 itohy if ((get_uint32(&phdr[t].p_flags) & PF_X) == 0)
343 1.4 itohy fprintf(stderr, "%s: warning: text is not executable\n",
344 1.4 itohy fn);
345 1.4 itohy
346 1.4 itohy if ((get_uint32(&phdr[d].p_flags) & PF_W) == 0)
347 1.4 itohy fprintf(stderr, "%s: warning: data is not writable\n",
348 1.4 itohy fn);
349 1.4 itohy
350 1.4 itohy inf->text_size = get_uint32(&phdr[t].p_filesz);
351 1.4 itohy inf->data_size = get_uint32(&phdr[d].p_filesz);
352 1.4 itohy inf->bss_size = get_uint32(&phdr[d].p_memsz) - inf->data_size;
353 1.4 itohy inf->entry_addr = get_uint32(&hdr->e_entry);
354 1.4 itohy inf->text_off = get_uint32(&phdr[t].p_offset);
355 1.4 itohy inf->data_off = get_uint32(&phdr[d].p_offset);
356 1.4 itohy inf->text_pad = get_uint32(&phdr[d].p_vaddr) -
357 1.4 itohy (get_uint32(&phdr[t].p_vaddr) + inf->text_size);
358 1.4 itohy }
359 1.4 itohy
360 1.4 itohy return 0;
361 1.4 itohy }
362 1.4 itohy
363 1.4 itohy /*
364 1.4 itohy * open an executable
365 1.1 itohy */
366 1.1 itohy FILE *
367 1.7 dsl open_exec(const char *fn, struct exec_info *inf)
368 1.1 itohy {
369 1.1 itohy FILE *fp;
370 1.1 itohy int i;
371 1.4 itohy union {
372 1.4 itohy struct aout_m68k u_aout;
373 1.4 itohy struct elf_m68k_hdr u_elf;
374 1.4 itohy } buf;
375 1.4 itohy #define hdra (&buf.u_aout)
376 1.4 itohy #define hdre (&buf.u_elf)
377 1.1 itohy
378 1.1 itohy if (!(fp = fopen(fn, "r"))) {
379 1.1 itohy perror(fn);
380 1.1 itohy return (FILE *) NULL;
381 1.1 itohy }
382 1.4 itohy
383 1.4 itohy /*
384 1.4 itohy * Check for a.out.
385 1.4 itohy */
386 1.4 itohy
387 1.4 itohy if (fread(hdra, sizeof(struct aout_m68k), 1, fp) != 1) {
388 1.1 itohy fprintf(stderr, "%s: can't read a.out header\n", fn);
389 1.1 itohy goto out;
390 1.1 itohy }
391 1.1 itohy
392 1.4 itohy if ((i = AOUT_GET_MAGIC(hdra)) != AOUT_OMAGIC && i != AOUT_NMAGIC)
393 1.4 itohy goto notaout;
394 1.4 itohy
395 1.4 itohy if (open_aout(fn, hdra, inf))
396 1.1 itohy goto out;
397 1.1 itohy
398 1.4 itohy /* OK! */
399 1.4 itohy return fp;
400 1.4 itohy
401 1.4 itohy notaout:
402 1.4 itohy /*
403 1.4 itohy * Check for ELF.
404 1.4 itohy */
405 1.4 itohy
406 1.4 itohy if (hdre->e_ident[EI_MAG0] != ELFMAG0 ||
407 1.4 itohy hdre->e_ident[EI_MAG1] != ELFMAG1 ||
408 1.4 itohy hdre->e_ident[EI_MAG2] != ELFMAG2 ||
409 1.4 itohy hdre->e_ident[EI_MAG3] != ELFMAG3 ||
410 1.4 itohy hdre->e_ident[EI_CLASS] != ELFCLASS32 ||
411 1.4 itohy hdre->e_ident[EI_DATA] != ELFDATA2MSB) {
412 1.4 itohy fprintf(stderr,
413 1.4 itohy "%s: not an OMAGIC or NMAGIC a.out, or a 32bit BE ELF\n",
414 1.4 itohy fn);
415 1.1 itohy goto out;
416 1.1 itohy }
417 1.1 itohy
418 1.4 itohy /* ELF header is longer than a.out header. Read the rest. */
419 1.4 itohy if (fread(hdra + 1,
420 1.4 itohy sizeof(struct elf_m68k_hdr) - sizeof(struct aout_m68k),
421 1.4 itohy 1, fp) != 1) {
422 1.4 itohy fprintf(stderr, "%s: can't read ELF header\n", fn);
423 1.1 itohy goto out;
424 1.1 itohy }
425 1.1 itohy
426 1.4 itohy if (open_elf(fn, fp, hdre, inf))
427 1.1 itohy goto out;
428 1.1 itohy
429 1.1 itohy /* OK! */
430 1.1 itohy return fp;
431 1.1 itohy
432 1.1 itohy out: fclose(fp);
433 1.1 itohy return (FILE *) NULL;
434 1.4 itohy #undef hdra
435 1.4 itohy #undef hdre
436 1.1 itohy }
437 1.1 itohy
438 1.1 itohy /*
439 1.4 itohy * compare two executables and check if they are compatible
440 1.1 itohy */
441 1.1 itohy int
442 1.4 itohy check_2_exec_inf(inf1, inf2)
443 1.4 itohy struct exec_info *inf1, *inf2;
444 1.1 itohy {
445 1.1 itohy
446 1.4 itohy if (inf1->text_size != inf2->text_size ||
447 1.4 itohy inf1->text_pad != inf2->text_pad ||
448 1.4 itohy inf1->data_size != inf2->data_size ||
449 1.4 itohy inf1->bss_size != inf2->bss_size)
450 1.1 itohy return -1;
451 1.1 itohy
452 1.1 itohy return 0;
453 1.1 itohy }
454 1.1 itohy
455 1.1 itohy /* allocation unit (in bytes) of relocation table */
456 1.1 itohy #define RELTBL_CHUNK 8192
457 1.1 itohy
458 1.1 itohy /*
459 1.1 itohy * add an entry to the relocation table
460 1.1 itohy */
461 1.1 itohy #define ADD_RELTBL(adr) \
462 1.1 itohy if (relsize + sizeof(struct relinf_l) > relallocsize) \
463 1.1 itohy reltbl = do_realloc(reltbl, relallocsize += RELTBL_CHUNK); \
464 1.1 itohy if ((adr) < reladdr + HUX_MINLREL) { \
465 1.1 itohy struct relinf_s *r = (struct relinf_s *)(reltbl + relsize); \
466 1.1 itohy put_uint16(&r->locoff_s, (unsigned)((adr) - reladdr)); \
467 1.1 itohy relsize += sizeof(struct relinf_s); \
468 1.1 itohy DPRINTF(("short")); \
469 1.1 itohy } else { \
470 1.1 itohy struct relinf_l *r = (struct relinf_l *)(reltbl + relsize); \
471 1.1 itohy put_uint16(&r->lrelmag, HUXLRELMAGIC); \
472 1.1 itohy put_uint32((be_uint32_t *)r->locoff_l, (adr) - reladdr); \
473 1.1 itohy relsize += sizeof(struct relinf_l); \
474 1.1 itohy DPRINTF(("long ")); \
475 1.1 itohy } \
476 1.1 itohy DPRINTF((" reloc 0x%06x", (adr))); \
477 1.1 itohy reladdr = (adr);
478 1.1 itohy
479 1.1 itohy #define ERR1 { if (ferror(fpa1)) perror(fn1); \
480 1.1 itohy else fprintf(stderr, "%s: unexpected EOF\n", fn1); \
481 1.1 itohy goto out; }
482 1.1 itohy #define ERR2 { if (ferror(fpa2)) perror(fn2); \
483 1.1 itohy else fprintf(stderr, "%s: unexpected EOF\n", fn2); \
484 1.1 itohy goto out; }
485 1.1 itohy #define ERRC { fprintf(stderr, "files %s and %s are inconsistent\n", \
486 1.1 itohy fn1, fn2); \
487 1.1 itohy goto out; }
488 1.1 itohy
489 1.1 itohy /*
490 1.4 itohy * read input executables and output .x body
491 1.1 itohy * and create relocation table
492 1.1 itohy */
493 1.1 itohy #define CREATE_RELOCATION(segsize) \
494 1.1 itohy while (segsize > 0 || nbuf) { \
495 1.1 itohy if (nbuf == 0) { \
496 1.1 itohy if (fread(&b1.half[0], SIZE_16, 1, fpa1) != 1) \
497 1.1 itohy ERR1 \
498 1.1 itohy if (fread(&b2.half[0], SIZE_16, 1, fpa2) != 1) \
499 1.1 itohy ERR2 \
500 1.1 itohy nbuf = 1; \
501 1.1 itohy segsize -= SIZE_16; \
502 1.1 itohy } else if (nbuf == 1) { \
503 1.1 itohy if (segsize == 0) { \
504 1.1 itohy if (b1.half[0].hostval != b2.half[0].hostval) \
505 1.1 itohy ERRC \
506 1.1 itohy fwrite(&b1.half[0], SIZE_16, 1, fpx); \
507 1.1 itohy nbuf = 0; \
508 1.1 itohy addr += SIZE_16; \
509 1.1 itohy } else { \
510 1.1 itohy if (fread(&b1.half[1], SIZE_16, 1, fpa1) != 1)\
511 1.1 itohy ERR1 \
512 1.1 itohy if (fread(&b2.half[1], SIZE_16, 1, fpa2) != 1)\
513 1.1 itohy ERR2 \
514 1.1 itohy nbuf = 2; \
515 1.1 itohy segsize -= SIZE_16; \
516 1.1 itohy } \
517 1.1 itohy } else /* if (nbuf == 2) */ { \
518 1.1 itohy if (b1.hostval != b2.hostval && \
519 1.1 itohy get_uint32(&b1) - loadadr1 \
520 1.1 itohy == get_uint32(&b2) - loadadr2) {\
521 1.1 itohy /* do relocation */ \
522 1.1 itohy ADD_RELTBL(addr) \
523 1.1 itohy \
524 1.1 itohy put_uint32(&b1, get_uint32(&b1) - loadadr1); \
525 1.1 itohy DPRINTF((" v 0x%08x\t", get_uint32(&b1))); \
526 1.1 itohy fwrite(&b1, SIZE_32, 1, fpx); \
527 1.1 itohy nbuf = 0; \
528 1.1 itohy addr += SIZE_32; \
529 1.1 itohy } else if (b1.half[0].hostval == b2.half[0].hostval) {\
530 1.1 itohy fwrite(&b1.half[0], SIZE_16, 1, fpx); \
531 1.1 itohy addr += SIZE_16; \
532 1.1 itohy b1.half[0] = b1.half[1]; \
533 1.1 itohy b2.half[0] = b2.half[1]; \
534 1.1 itohy nbuf = 1; \
535 1.1 itohy } else \
536 1.1 itohy ERRC \
537 1.1 itohy } \
538 1.1 itohy }
539 1.1 itohy
540 1.1 itohy int
541 1.1 itohy aout2hux(fn1, fn2, loadadr1, loadadr2, fnx)
542 1.1 itohy const char *fn1, *fn2, *fnx;
543 1.1 itohy u_int32_t loadadr1, loadadr2;
544 1.1 itohy {
545 1.1 itohy int status = 1; /* the default is "failed" */
546 1.1 itohy FILE *fpa1 = NULL, *fpa2 = NULL;
547 1.4 itohy struct exec_info inf1, inf2;
548 1.1 itohy FILE *fpx = NULL;
549 1.1 itohy struct huxhdr xhdr;
550 1.4 itohy u_int32_t textsize, datasize, paddingsize, execoff;
551 1.1 itohy
552 1.1 itohy /* for relocation */
553 1.1 itohy be_uint32_t b1, b2;
554 1.1 itohy int nbuf;
555 1.1 itohy u_int32_t addr;
556 1.1 itohy
557 1.1 itohy /* for relocation table */
558 1.1 itohy size_t relsize, relallocsize;
559 1.1 itohy u_int32_t reladdr;
560 1.1 itohy char *reltbl = NULL;
561 1.1 itohy
562 1.1 itohy
563 1.1 itohy /*
564 1.1 itohy * check load addresses
565 1.1 itohy */
566 1.1 itohy if (loadadr1 == loadadr2) {
567 1.1 itohy fprintf(stderr, "two load addresses must be different\n");
568 1.1 itohy return 1;
569 1.1 itohy }
570 1.1 itohy
571 1.1 itohy /*
572 1.4 itohy * open input executables and check them
573 1.1 itohy */
574 1.4 itohy if (!(fpa1 = open_exec(fn1, &inf1)) || !(fpa2 = open_exec(fn2, &inf2)))
575 1.1 itohy goto out;
576 1.1 itohy
577 1.1 itohy /*
578 1.1 itohy * check for consistency
579 1.1 itohy */
580 1.4 itohy if (check_2_exec_inf(&inf1, &inf2)) {
581 1.1 itohy fprintf(stderr, "files %s and %s are incompatible\n",
582 1.1 itohy fn1, fn2);
583 1.1 itohy goto out;
584 1.1 itohy }
585 1.1 itohy /* check entry address */
586 1.4 itohy if (inf1.entry_addr - loadadr1 != inf2.entry_addr - loadadr2) {
587 1.1 itohy fprintf(stderr, "address of %s or %s may be incorrect\n",
588 1.1 itohy fn1, fn2);
589 1.1 itohy goto out;
590 1.1 itohy }
591 1.1 itohy
592 1.1 itohy /*
593 1.4 itohy * get information of the executables
594 1.1 itohy */
595 1.4 itohy textsize = inf1.text_size;
596 1.4 itohy paddingsize = inf1.text_pad;
597 1.4 itohy datasize = inf1.data_size;
598 1.4 itohy execoff = inf1.entry_addr - loadadr1;
599 1.4 itohy
600 1.4 itohy DPRINTF(("text: %u, data: %u, pad: %u, bss: %u, exec: %u\n",
601 1.4 itohy textsize, datasize, paddingsize, inf1.bss_size, execoff));
602 1.1 itohy
603 1.1 itohy if (textsize & 1) {
604 1.1 itohy fprintf(stderr, "text size is not even\n");
605 1.1 itohy goto out;
606 1.1 itohy }
607 1.1 itohy if (datasize & 1) {
608 1.1 itohy fprintf(stderr, "data size is not even\n");
609 1.1 itohy goto out;
610 1.1 itohy }
611 1.1 itohy if (execoff >= textsize &&
612 1.1 itohy (execoff < textsize + paddingsize ||
613 1.1 itohy execoff >= textsize + paddingsize + datasize)) {
614 1.1 itohy fprintf(stderr, "exec addr is not in text or data segment\n");
615 1.1 itohy goto out;
616 1.1 itohy }
617 1.1 itohy
618 1.1 itohy /*
619 1.1 itohy * prepare for .x header
620 1.1 itohy */
621 1.1 itohy bzero((void *) &xhdr, sizeof xhdr);
622 1.1 itohy put_uint16(&xhdr.x_magic, HUXMAGIC);
623 1.1 itohy put_uint32(&xhdr.x_entry, execoff);
624 1.1 itohy put_uint32(&xhdr.x_text, textsize + paddingsize);
625 1.4 itohy put_uint32(&xhdr.x_data, inf1.data_size);
626 1.4 itohy put_uint32(&xhdr.x_bss, inf1.bss_size);
627 1.1 itohy
628 1.1 itohy /*
629 1.1 itohy * create output file
630 1.1 itohy */
631 1.1 itohy if (!(fpx = fopen(fnx, "w")) ||
632 1.4 itohy fseek(fpx, (foff_t) sizeof xhdr, SEEK_SET)) { /* skip header */
633 1.1 itohy perror(fnx);
634 1.1 itohy goto out;
635 1.1 itohy }
636 1.1 itohy
637 1.1 itohy addr = 0;
638 1.1 itohy nbuf = 0;
639 1.1 itohy
640 1.1 itohy relsize = relallocsize = 0;
641 1.1 itohy reladdr = 0;
642 1.1 itohy
643 1.1 itohy /*
644 1.1 itohy * text segment
645 1.1 itohy */
646 1.4 itohy if (fseek(fpa1, inf1.text_off, SEEK_SET)) {
647 1.4 itohy perror(fn1);
648 1.4 itohy goto out;
649 1.4 itohy }
650 1.4 itohy if (fseek(fpa2, inf2.text_off, SEEK_SET)) {
651 1.4 itohy perror(fn2);
652 1.4 itohy goto out;
653 1.4 itohy }
654 1.1 itohy CREATE_RELOCATION(textsize)
655 1.1 itohy
656 1.1 itohy /*
657 1.1 itohy * page boundary
658 1.1 itohy */
659 1.1 itohy addr += paddingsize;
660 1.1 itohy while (paddingsize--)
661 1.1 itohy putc('\0', fpx);
662 1.1 itohy
663 1.1 itohy /*
664 1.1 itohy * data segment
665 1.1 itohy */
666 1.4 itohy if (fseek(fpa1, inf1.data_off, SEEK_SET)) {
667 1.4 itohy perror(fn1);
668 1.4 itohy goto out;
669 1.4 itohy }
670 1.4 itohy if (fseek(fpa2, inf2.data_off, SEEK_SET)) {
671 1.4 itohy perror(fn2);
672 1.4 itohy goto out;
673 1.4 itohy }
674 1.1 itohy CREATE_RELOCATION(datasize)
675 1.1 itohy
676 1.1 itohy /*
677 1.1 itohy * error check of the above
678 1.1 itohy */
679 1.1 itohy if (ferror(fpx)) {
680 1.1 itohy fprintf(stderr, "%s: write failure\n", fnx);
681 1.1 itohy goto out;
682 1.1 itohy }
683 1.1 itohy
684 1.1 itohy /*
685 1.1 itohy * write relocation table
686 1.1 itohy */
687 1.1 itohy if (relsize > 0) {
688 1.1 itohy DPRINTF(("\n"));
689 1.1 itohy if (fwrite(reltbl, 1, relsize, fpx) != relsize) {
690 1.1 itohy perror(fnx);
691 1.1 itohy goto out;
692 1.1 itohy }
693 1.1 itohy }
694 1.1 itohy
695 1.1 itohy /*
696 1.1 itohy * write .x header at the top of the output file
697 1.1 itohy */
698 1.1 itohy put_uint32(&xhdr.x_rsize, relsize);
699 1.4 itohy if (fseek(fpx, (foff_t) 0, SEEK_SET) ||
700 1.1 itohy fwrite(&xhdr, sizeof xhdr, 1, fpx) != 1) {
701 1.1 itohy perror(fnx);
702 1.1 itohy goto out;
703 1.1 itohy }
704 1.1 itohy
705 1.1 itohy status = 0; /* all OK */
706 1.1 itohy
707 1.1 itohy out: /*
708 1.1 itohy * cleanup
709 1.1 itohy */
710 1.1 itohy if (fpa1)
711 1.1 itohy fclose(fpa1);
712 1.1 itohy if (fpa2)
713 1.1 itohy fclose(fpa2);
714 1.1 itohy if (fpx) {
715 1.1 itohy if (fclose(fpx) && status == 0) {
716 1.1 itohy /* Alas, final flush failed! */
717 1.1 itohy perror(fnx);
718 1.1 itohy status = 1;
719 1.1 itohy }
720 1.1 itohy if (status)
721 1.1 itohy remove(fnx);
722 1.1 itohy }
723 1.1 itohy if (reltbl)
724 1.1 itohy free(reltbl);
725 1.1 itohy
726 1.1 itohy return status;
727 1.1 itohy }
728 1.1 itohy
729 1.1 itohy #ifndef NO_BIST
730 1.1 itohy void bist PROTO((void));
731 1.1 itohy
732 1.1 itohy /*
733 1.1 itohy * built-in self test
734 1.1 itohy */
735 1.1 itohy void
736 1.1 itohy bist()
737 1.1 itohy {
738 1.1 itohy be_uint16_t be16;
739 1.1 itohy be_uint32_t be32;
740 1.1 itohy be_uint32_t be32x2[2];
741 1.1 itohy
742 1.1 itohy be16.val[0] = 0x12; be16.val[1] = 0x34;
743 1.1 itohy be32.val[0] = 0xfe; be32.val[1] = 0xdc;
744 1.1 itohy be32.val[2] = 0xba; be32.val[3] = 0x98;
745 1.1 itohy
746 1.1 itohy put_uint16(&be32x2[0].half[1], 0x4567);
747 1.1 itohy put_uint32(&be32x2[1], 0xa9876543);
748 1.1 itohy
749 1.1 itohy if (sizeof(u_int8_t) != 1 || sizeof(u_int16_t) != 2 ||
750 1.1 itohy sizeof(u_int32_t) != 4 ||
751 1.1 itohy SIZE_16 != 2 || SIZE_32 != 4 || sizeof be32x2 != 8 ||
752 1.1 itohy sizeof(struct relinf_s) != 2 || sizeof(struct relinf_l) != 6 ||
753 1.4 itohy SIZE_ELF68K_HDR != 52 || SIZE_ELF68K_SHDR != 40 ||
754 1.4 itohy SIZE_ELF68K_PHDR != 32 ||
755 1.1 itohy get_uint16(&be16) != 0x1234 || get_uint32(&be32) != 0xfedcba98 ||
756 1.1 itohy get_uint16(&be32x2[0].half[1]) != 0x4567 ||
757 1.1 itohy get_uint32(&be32x2[1]) != 0xa9876543) {
758 1.1 itohy fprintf(stderr, "BIST failed\n");
759 1.1 itohy exit(1);
760 1.1 itohy }
761 1.1 itohy }
762 1.1 itohy #endif
763 1.1 itohy
764 1.1 itohy int
765 1.7 dsl gethex(u_int32_t *pval, const char *str)
766 1.1 itohy {
767 1.1 itohy const unsigned char *p = (const unsigned char *) str;
768 1.1 itohy u_int32_t val;
769 1.1 itohy int over;
770 1.1 itohy
771 1.1 itohy /* skip leading "0x" if exists */
772 1.1 itohy if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
773 1.1 itohy p += 2;
774 1.1 itohy
775 1.1 itohy if (!*p)
776 1.1 itohy goto bad;
777 1.1 itohy
778 1.1 itohy for (val = 0, over = 0; *p; p++) {
779 1.1 itohy int digit;
780 1.1 itohy
781 1.1 itohy switch (*p) {
782 1.1 itohy case '0': case '1': case '2': case '3': case '4':
783 1.1 itohy case '5': case '6': case '7': case '8': case '9':
784 1.1 itohy digit = *p - '0';
785 1.1 itohy break;
786 1.1 itohy case 'a': case 'A': digit = 10; break;
787 1.1 itohy case 'b': case 'B': digit = 11; break;
788 1.1 itohy case 'c': case 'C': digit = 12; break;
789 1.1 itohy case 'd': case 'D': digit = 13; break;
790 1.1 itohy case 'e': case 'E': digit = 14; break;
791 1.1 itohy case 'f': case 'F': digit = 15; break;
792 1.1 itohy default:
793 1.1 itohy goto bad;
794 1.1 itohy }
795 1.4 itohy if (val >= 0x10000000)
796 1.1 itohy over = 1;
797 1.1 itohy val = (val << 4) | digit;
798 1.1 itohy }
799 1.1 itohy
800 1.1 itohy if (over)
801 1.1 itohy fprintf(stderr, "warning: %s: constant overflow\n", str);
802 1.1 itohy
803 1.1 itohy *pval = val;
804 1.1 itohy
805 1.1 itohy DPRINTF(("gethex: %s -> 0x%x\n", str, val));
806 1.1 itohy
807 1.1 itohy return 0;
808 1.1 itohy
809 1.1 itohy bad:
810 1.1 itohy fprintf(stderr, "%s: not a hexadecimal number\n", str);
811 1.1 itohy return 1;
812 1.1 itohy }
813 1.1 itohy
814 1.1 itohy void
815 1.7 dsl usage(const char *name)
816 1.1 itohy {
817 1.1 itohy
818 1.1 itohy fprintf(stderr, "\
819 1.1 itohy usage: %s [ -o output.x ] a.out1 loadaddr1 a.out2 loadaddr2\n\n\
820 1.4 itohy The input files must be static OMAGIC/NMAGIC m68k a.out executables\n\
821 1.4 itohy or m68k ELF executables.\n\
822 1.4 itohy Two executables must have different loading addresses.\n\
823 1.1 itohy Each of the load address must be a hexadecimal number.\n\
824 1.1 itohy The default output filename is \"%s\".\n" ,name, DEFAULT_OUTPUT_FILE);
825 1.1 itohy
826 1.1 itohy exit(1);
827 1.1 itohy }
828 1.1 itohy
829 1.1 itohy int
830 1.1 itohy main(argc, argv)
831 1.1 itohy int argc;
832 1.1 itohy char *argv[];
833 1.1 itohy {
834 1.1 itohy const char *outfile = DEFAULT_OUTPUT_FILE;
835 1.1 itohy u_int32_t adr1, adr2;
836 1.1 itohy
837 1.1 itohy #ifndef NO_BIST
838 1.1 itohy bist();
839 1.1 itohy #endif
840 1.1 itohy
841 1.1 itohy if (argc > 2 && argv[1][0] == '-' && argv[1][1] == 'o' && !argv[1][2]) {
842 1.1 itohy outfile = argv[2];
843 1.1 itohy argv += 2;
844 1.1 itohy argc -= 2;
845 1.1 itohy }
846 1.1 itohy
847 1.1 itohy if (argc != 5)
848 1.1 itohy usage(argv[0]);
849 1.1 itohy
850 1.1 itohy if (gethex(&adr1, argv[2]) || gethex(&adr2, argv[4]))
851 1.1 itohy usage(argv[0]);
852 1.1 itohy
853 1.1 itohy return aout2hux(argv[1], argv[3], adr1, adr2, outfile);
854 1.1 itohy }
855