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