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