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