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