/* prepare to run the aout image already verified to be aout */ Retcode aout_load(Environ *e, uByte *load, uInt loadlen, uLong *entrypoint) { struct exec exbuf = *(struct exec*)load; struct exec *ex = &exbuf; /* copy header to support overlapping loads */ char *os = get_config(e, "operating-system", CSTR); uInt loadoff = 0; if (!aout_is_exec(e, load, loadlen)) return E_BAD_IMAGE; *entrypoint = N_TXTADDR(*ex); if (*entrypoint < ex->a_entry) *entrypoint = ex->a_entry; if (AOUT_MAGIC_0 == MID_I386) { /* hacks for booting various x86 OSes */ if (compare_strs(os, CSTR, "openbsd", CSTR)) { DPRINTF(("aout_load: openbsd: entrypoint=%#lx\n", *entrypoint)); *entrypoint &= 0x00FFFFFF; loadoff = *entrypoint - sizeof *ex - N_TXTADDR(*ex); } } /* copy the text segment */ DPRINTF(("aout_load: textaddr=%#x load=%#x offset=%#x\n", loadoff + N_TXTADDR(*ex), load, N_TXTOFF(*ex))); memmove((char*)(loadoff + N_TXTADDR(*ex)), load + N_TXTOFF(*ex), ex->a_text); #ifdef MACHINE_CLAIM_MEMORY /* claim/map this area if requested */ MACHINE_CLAIM_MEMORY(e, (char*)(loadoff + N_TXTADDR(*ex)), ex->a_text); #endif /* MACHINE_CLAIM_MEMORY */ /* copy the data segment */ DPRINTF(("aout_load: dataaddr=%#x load=%#x offset=%#x\n", loadoff + N_DATADDR(*ex), load, N_DATOFF(*ex))); memmove((char*)(loadoff + N_DATADDR(*ex)), load + N_DATOFF(*ex), ex->a_data); /* zero bss segment */ DPRINTF(("aout_load: bssaddr=%#x size=%#x\n", loadoff + N_DATADDR(*ex) + ex->a_data, ex->a_bss)); memset((char*)(loadoff + N_DATADDR(*ex)) + ex->a_data, 0, ex->a_bss); #ifdef MACHINE_CLAIM_MEMORY /* claim/map this area if requested */ MACHINE_CLAIM_MEMORY(e, (char*)(loadoff + N_DATADDR(*ex)), ex->a_data + ex->a_bss); #endif /* MACHINE_CLAIM_MEMORY */ return NO_ERROR; }
/* Set parameters about this a.out file that are machine-dependent. This routine is called from some_aout_object_p just before it returns. */ static const bfd_target * MY (callback) (bfd *abfd) { struct internal_exec *execp = exec_hdr (abfd); /* Calculate the file positions of the parts of a newly read aout header */ obj_textsec (abfd)->size = N_TXTSIZE (*execp); /* The virtual memory addresses of the sections */ obj_textsec (abfd)->vma = N_TXTADDR (*execp); obj_datasec (abfd)->vma = N_DATADDR (*execp); obj_bsssec (abfd)->vma = N_BSSADDR (*execp); obj_textsec (abfd)->lma = obj_textsec (abfd)->vma; obj_datasec (abfd)->lma = obj_datasec (abfd)->vma; obj_bsssec (abfd)->lma = obj_bsssec (abfd)->vma; /* The file offsets of the sections */ obj_textsec (abfd)->filepos = N_TXTOFF (*execp); obj_datasec (abfd)->filepos = N_DATOFF (*execp); /* The file offsets of the relocation info */ obj_textsec (abfd)->rel_filepos = N_TRELOFF (*execp); obj_datasec (abfd)->rel_filepos = N_DRELOFF (*execp); /* The file offsets of the string table and symbol table. */ obj_sym_filepos (abfd) = N_SYMOFF (*execp); obj_str_filepos (abfd) = N_STROFF (*execp); /* Determine the architecture and machine type of the object file. */ #ifdef SET_ARCH_MACH SET_ARCH_MACH (abfd, *execp); #else bfd_default_set_arch_mach (abfd, DEFAULT_ARCH, 0); #endif if (obj_aout_subformat (abfd) == gnu_encap_format) { /* The file offsets of the relocation info */ obj_textsec (abfd)->rel_filepos = N_GNU_TRELOFF (*execp); obj_datasec (abfd)->rel_filepos = N_GNU_DRELOFF (*execp); /* The file offsets of the string table and symbol table. */ obj_sym_filepos (abfd) = N_GNU_SYMOFF (*execp); obj_str_filepos (abfd) = (obj_sym_filepos (abfd) + execp->a_syms); abfd->flags |= HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS; bfd_get_symcount (abfd) = execp->a_syms / 12; obj_symbol_entry_size (abfd) = 12; obj_reloc_entry_size (abfd) = RELOC_STD_SIZE; } return abfd->xvec; }
static void dump_segs(void) { printf(" Text segment starts at address %lx\n", origin + N_TXTOFF(*ex)); if (N_GETFLAG(*ex) & EX_DYNAMIC) { printf(" rel starts at %lx\n", sdt->sdt_rel); printf(" hash starts at %lx\n", sdt->sdt_hash); printf(" nzlist starts at %lx\n", sdt->sdt_nzlist); printf(" strings starts at %lx\n", sdt->sdt_strings); } printf(" Data segment starts at address %lx\n", origin + N_DATOFF(*ex)); if (N_GETFLAG(*ex) & EX_DYNAMIC) { printf(" _dynamic starts at %lx\n", origin + N_DATOFF(*ex)); printf(" so_debug starts at %lx\n", (unsigned long) dyn->d_debug); printf(" sdt starts at %lx\n", (unsigned long) dyn->d_un.d_sdt); printf(" got starts at %lx\n", sdt->sdt_got); printf(" plt starts at %lx\n", sdt->sdt_plt); printf(" rest of stuff starts at %lx\n", sdt->sdt_plt + sdt->sdt_plt_sz); } }
/* dereference a pointer to kernel space */ u_int kv_dref_p(struct kernel *kp, u_int adr){ u_int tadr; if(!kp->incore){ struct exec *ep; ep=(struct exec *)kp->core; tadr=*(u_int*)((adr - ep->a_entry + (N_DATOFF(*ep) - ep->a_text))+kp->core); } else { lseek(kp->fd, adr, SEEK_SET); read(kp->fd, &tadr, sizeof(tadr)); } return(tadr); }
/* malloc()-ing if we aren't mmaped */ u_int kv_to_u(struct kernel *kp, u_int adr, u_int size){ u_int tadr; if(!kp->incore){ struct exec *ep; ep=(struct exec *)kp->core; tadr=(u_int)((adr - ep->a_entry + (N_DATOFF(*ep) - ep->a_text))+kp->core); } else { caddr_t ptr; ptr = malloc(size); lseek(kp->fd, adr, SEEK_SET); read(kp->fd, ptr, size); tadr=(u_int)ptr; } return(tadr); }
/* * "Load" an a.out-format executable. */ static int ld_aout(const struct iodesc * idi, const struct iodesc * ido, struct kgz_hdr * kh, const struct exec * a) { size_t load, addr; load = addr = N_TXTADDR(*a); xcopy(idi, ido, le32toh(a->a_text), N_TXTOFF(*a)); addr += le32toh(a->a_text); if (N_DATADDR(*a) != addr) return -1; xcopy(idi, ido, le32toh(a->a_data), N_DATOFF(*a)); addr += le32toh(a->a_data); kh->dload = load; kh->dsize = addr - load; kh->isize = kh->dsize + le32toh(a->a_bss); kh->entry = le32toh(a->a_entry); return 0; }
static #endif void dump_file(const char *fname) { int fd; struct stat sb; caddr_t objbase; if (stat(fname, &sb) == -1) { warnx("cannot stat \"%s\"", fname); ++error_count; return; } if ((sb.st_mode & S_IFMT) != S_IFREG) { warnx("\"%s\" is not a regular file", fname); ++error_count; return; } if ((fd = open(fname, O_RDONLY, 0)) == -1) { warnx("cannot open \"%s\"", fname); ++error_count; return; } objbase = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); if (objbase == (caddr_t) -1) { warnx("cannot mmap \"%s\"", fname); ++error_count; close(fd); return; } close(fd); file_base = (const char *) objbase; /* Makes address arithmetic easier */ if (IS_ELF(*(const Elf32_Ehdr*) align_struct(file_base))) { warnx("%s: this is an ELF program; use objdump to examine", fname); ++error_count; munmap(objbase, sb.st_size); return; } ex = (const struct exec *) align_struct(file_base); printf("%s: a_midmag = 0x%lx\n", fname, (long)ex->a_midmag); printf(" magic = 0x%lx = 0%lo, netmagic = 0x%lx = 0%lo\n", (long)N_GETMAGIC(*ex), (long)N_GETMAGIC(*ex), (long)N_GETMAGIC_NET(*ex), (long)N_GETMAGIC_NET(*ex)); if (N_BADMAG(*ex)) { warnx("%s: bad magic number", fname); ++error_count; munmap(objbase, sb.st_size); return; } printf(" a_text = 0x%lx\n", (long)ex->a_text); printf(" a_data = 0x%lx\n", (long)ex->a_data); printf(" a_bss = 0x%lx\n", (long)ex->a_bss); printf(" a_syms = 0x%lx\n", (long)ex->a_syms); printf(" a_entry = 0x%lx\n", (long)ex->a_entry); printf(" a_trsize = 0x%lx\n", (long)ex->a_trsize); printf(" a_drsize = 0x%lx\n", (long)ex->a_drsize); text_base = file_base + N_TXTOFF(*ex); data_base = file_base + N_DATOFF(*ex); rel_base = (const struct relocation_info *) align_struct(file_base + N_RELOFF(*ex)); sym_base = (const struct nlist *) align_struct(file_base + N_SYMOFF(*ex)); str_base = file_base + N_STROFF(*ex); rel_count = (ex->a_trsize + ex->a_drsize) / sizeof rel_base[0]; assert(rel_count * sizeof rel_base[0] == ex->a_trsize + ex->a_drsize); sym_count = ex->a_syms / sizeof sym_base[0]; assert(sym_count * sizeof sym_base[0] == ex->a_syms); if (sym_count != 0) { sym_used = (unsigned char *) calloc(sym_count, sizeof(unsigned char)); assert(sym_used != NULL); } printf(" Entry = 0x%lx\n", (long)ex->a_entry); printf(" Text offset = %x, address = %lx\n", N_TXTOFF(*ex), (long)N_TXTADDR(*ex)); printf(" Data offset = %lx, address = %lx\n", (long)N_DATOFF(*ex), (long)N_DATADDR(*ex)); /* * In an executable program file, everything is relocated relative to * the assumed run-time load address, i.e., N_TXTADDR(*ex), i.e., 0x1000. * * In a shared library file, everything is relocated relative to the * start of the file, i.e., N_TXTOFF(*ex), i.e., 0. * * The way to tell the difference is by looking at ex->a_entry. If it * is >= 0x1000, then we have an executable program. Otherwise, we * have a shared library. * * When a program is executed, the entire file is mapped into memory, * including the a.out header and so forth. But it is not mapped at * address 0; rather it is mapped at address 0x1000. The first page * of the user's address space is left unmapped in order to catch null * pointer dereferences. * * In this program, when we map in an executable program, we have to * simulate the empty page by decrementing our assumed base address by * a pagesize. */ text_addr = text_base; data_addr = data_base; origin = 0; if (ex->a_entry >= PAGE_SIZE) { /* Executable, not a shared library */ /* * The fields in the object have already been relocated on the * assumption that the object will be loaded at N_TXTADDR(*ex). * We have to compensate for that. */ text_addr -= PAGE_SIZE; data_addr -= PAGE_SIZE; origin = PAGE_SIZE; printf(" Program, origin = %lx\n", origin); } else if (N_GETFLAG(*ex) & EX_DYNAMIC) printf(" Shared library, origin = %lx\n", origin); else printf(" Object file, origin = %lx\n", origin); if (N_GETFLAG(*ex) & EX_DYNAMIC) { dyn = (const struct _dynamic *) align_struct(data_base); printf(" Dynamic version = %d\n", dyn->d_version); sdt = (const struct section_dispatch_table *) align_struct(text_addr + (unsigned long) dyn->d_un.d_sdt); rtrel_base = (const struct relocation_info *) align_struct(text_addr + sdt->sdt_rel); rtrel_count = (sdt->sdt_hash - sdt->sdt_rel) / sizeof rtrel_base[0]; assert(rtrel_count * sizeof rtrel_base[0] == (size_t)(sdt->sdt_hash - sdt->sdt_rel)); rtsym_base = (const struct nzlist *) align_struct(text_addr + sdt->sdt_nzlist); rtsym_count = (sdt->sdt_strings - sdt->sdt_nzlist) / sizeof rtsym_base[0]; assert(rtsym_count * sizeof rtsym_base[0] == (size_t)(sdt->sdt_strings - sdt->sdt_nzlist)); if (rtsym_count != 0) { rtsym_used = (unsigned char *) calloc(rtsym_count, sizeof(unsigned char)); assert(rtsym_used != NULL); } rtstr_base = text_addr + sdt->sdt_strings; } dump_segs(); dump_sods(); dump_rels("Relocations", rel_base, rel_count, sym_name, sym_used); dump_syms(); dump_rels("Run-time relocations", rtrel_base, rtrel_count, rtsym_name, rtsym_used); dump_rtsyms(); if (rtsym_used != NULL) { free(rtsym_used); rtsym_used = NULL; } if (sym_used != NULL) { free(sym_used); sym_used = NULL; } munmap(objbase, sb.st_size); }
/* End of test binpatch variables */ int main(int argc, char *argv[]) { struct exec e; int c; u_long addr = 0, offset = 0; u_long index = 0;/* Related to offset */ u_long replace = 0, do_replace = 0; char *symbol = 0; char size = 4; /* default to long */ char size_opt = 0; /* Flag to say size option was set, used with index */ char *fname; char *pgname = argv[0]; /* Program name */ int fd; int type, off; u_long lval; u_short sval; u_char cval; while ((c = getopt (argc, argv, "H:a:bwlr:s:o:")) != -1) switch (c) { case 'H': Usage(argv[0]); break; case 'a': if (addr || symbol) error ("only one address/symbol allowed"); if (! strncmp (optarg, "0x", 2)) sscanf (optarg, "%x", &addr); else addr = atoi (optarg); if (! addr) error ("invalid address"); break; case 'b': size = 1; size_opt = 1; break; case 'w': size = 2; size_opt = 1; break; case 'l': size = 4; size_opt = 1; break; case 'r': do_replace = 1; if (! strncmp (optarg, "0x", 2)) sscanf (optarg, "%x", &replace); else replace = atoi (optarg); break; case 's': if (addr || symbol) error ("only one address/symbol allowed"); symbol = optarg; break; case 'o': if (offset) error ("only one offset allowed"); if (! strncmp (optarg, "0x", 2)) sscanf (optarg, "%x", &offset); else offset = atoi (optarg); break; }/* while switch() */ if (argc > 1) { if (addr || symbol) { argv += optind; argc -= optind; if (argc < 1) error ("No file to patch."); fname = argv[0]; if ((fd = open (fname, 0)) < 0) error ("Can't open file"); if (read (fd, &e, sizeof (e)) != sizeof (e) || N_BADMAG (e)) error ("Not a valid executable."); /* fake mid, so the N_ macros work on the amiga.. */ e.a_midmag |= 127 << 16; if (symbol) { struct nlist nl[2]; if (offset == 0) { u_long new_do_replace = 0; new_do_replace = FindAssign(symbol,&replace); if (new_do_replace && do_replace) error("Cannot use both '=' and '-r' option!"); FindOffset(symbol,&index); if (size_opt) offset = index*size; /* Treat like an index */ else offset = index; /* Treat index like an offset */ if (new_do_replace) do_replace = new_do_replace; } nl[0].n_un.n_name = symbol; nl[1].n_un.n_name = 0; if (nlist (fname, nl) != 0) { fprintf(stderr,"Symbol is %s ",symbol); error ("Symbol not found."); } addr = nl[0].n_value; type = nl[0].n_type & N_TYPE; } else { type = N_UNDF; if (addr >= N_TXTADDR(e) && addr < N_DATADDR(e)) type = N_TEXT; else if (addr >= N_DATADDR(e) && addr < N_DATADDR(e) + e.a_data) type = N_DATA; } addr += offset; /* if replace-mode, have to reopen the file for writing. Can't do that from the beginning, or nlist() will not work (at least not under AmigaDOS) */ if (do_replace) { close (fd); if ((fd = open (fname, 2)) == -1) error ("Can't reopen file for writing."); } if (type != N_TEXT && type != N_DATA) error ("address/symbol is not in text or data section."); if (type == N_TEXT) off = addr - N_TXTADDR(e) + N_TXTOFF(e); else off = addr - N_DATADDR(e) + N_DATOFF(e); if (lseek (fd, off, 0) == -1) error ("lseek"); /* not beautiful, but works on big and little endian machines */ switch (size) { case 1: if (read (fd, &cval, 1) != 1) error ("cread"); lval = cval; break; case 2: if (read (fd, &sval, 2) != 2) error ("sread"); lval = sval; break; case 4: if (read (fd, &lval, 4) != 4) error ("lread"); break; }/* switch size */ if (symbol) printf ("%s(0x%x): %d (0x%x)\n", symbol, addr, lval, lval); else printf ("0x%x: %d (0x%x)\n", addr, lval, lval); if (do_replace) { if (lseek (fd, off, 0) == -1) error ("write-lseek"); switch (size) { case 1: cval = replace; if (cval != replace) error ("byte-value overflow."); if (write (fd, &cval, 1) != 1) error ("cwrite"); break; case 2: sval = replace; if (sval != replace) error ("word-value overflow."); if (write (fd, &sval, 2) != 2) error ("swrite"); break; case 4: if (write (fd, &replace, 4) != 4) error ("lwrite"); break; }/* switch(size) */ }/* if (do_replace) */ close (fd); }/* if(addr || symbol ) */ else { error("Must specify either address or symbol."); } }/* if argc < 1 */ else { Synopsis(pgname); } return(0); }/* main () */
void run_header(struct exec *exhdr, int extended_info) { char *id = NULL; assert(NULL != exhdr); /* print raw values */ printf( "\ta_midmag 0x%08x (mid %d, magic 0%o, flag 0x%x)\n" "\ta_text 0x%08x\n" "\ta_data 0x%08x\n" "\ta_bss 0x%08x\n" "\ta_syms 0x%08x\n" "\ta_entry 0x%08x\n" "\ta_trsize 0x%08x\n" "\ta_drsize 0x%08x\n", exhdr->a_midmag, N_GETMID(*exhdr), N_GETMAGIC(*exhdr), N_GETFLAG(*exhdr), exhdr->a_text, exhdr->a_data, exhdr->a_bss, exhdr->a_syms, exhdr->a_entry, exhdr->a_trsize, exhdr->a_drsize ); printf( "magic number %04o: %s\n", N_GETMAGIC(*exhdr), N_GETMAGIC(*exhdr) == OMAGIC ? "old impure format" : N_GETMAGIC(*exhdr) == NMAGIC ? "read-only text" : N_GETMAGIC(*exhdr) == ZMAGIC ? "demand load format" : N_GETMAGIC(*exhdr) == QMAGIC ? "deprecated format" : "totally funky" ); switch (N_GETMID(*exhdr)) { case MID_ZERO: id = "unknown - implementation dependent"; break; case MID_SUN010: id = "sun 68010/68020 binary"; break; case MID_SUN020: id = "sun 68020-only binary"; break; case MID_PC386: id = "386 PC binary. (so quoth BFD)"; break; case MID_HP200: id = "hp200 (68010) BSD binary"; break; case MID_I386: id = "i386 BSD binary"; break; case MID_M68K: id = "m68k BSD binary with 8K page sizes"; break; case MID_M68K4K: id = "m68k BSD binary with 4K page sizes"; break; case MID_NS32532: id = "ns32532"; break; case MID_SPARC: id = "sparc"; break; case MID_PMAX: id = "pmax"; break; case MID_VAX: id = "vax"; break; case MID_ALPHA: id = "Alpha BSD binary"; break; case MID_MIPS: id = "big-endian MIPS"; break; case MID_ARM6: id = "ARM6"; break; case MID_HP300: id = "hp300 (68020+68881) BSD binary"; break; case MID_HPUX: id = "hp200/300 HP-UX binary"; break; case MID_HPUX800: id = "hp800 HP-UX binary"; break; default: id = "don't know"; break; } printf("type %d, %s\n", N_GETMID(*exhdr), id); /* this left shift seems a bit bogus */ switch((N_GETFLAG(*exhdr) & EX_DPMASK)>>4) { case 0: id = "traditional executable or object file"; break; case 1: id = "object file contains PIC code"; break; case 2: id = "dynamic executable"; break; case 3: id = "position independent executable image"; break; default: id = NULL; } if (NULL != id) printf("flags: 0x%x, %s\n", N_GETFLAG(*exhdr), id); else printf("flags: 0x%x\n", N_GETFLAG(*exhdr)); if (extended_info) { unsigned long txt_addr; unsigned long dat_addr; unsigned long bss_addr; /* N_TXTADDR and N_DATADDR macros DON'T WORK */ if (N_GETMAGIC(*exhdr) == ZMAGIC) { txt_addr = __LDPGSZ; dat_addr = ((txt_addr + exhdr->a_text + __LDPGSZ - 1) & ~(__LDPGSZ - 1)); } else if (N_GETMAGIC(*exhdr) == OMAGIC) { txt_addr = 0; dat_addr = txt_addr + exhdr->a_text; } else { txt_addr = 0xdeadbeef; dat_addr = 0xcafebabe; } bss_addr = dat_addr + exhdr->a_data; printf(" text segment size = 0x%lx, text segment file offset = %ld\n", exhdr->a_text, N_TXTOFF(*exhdr)); printf(" data segment size = 0x%lx, data segment file offset = %ld\n", exhdr->a_data, N_DATOFF(*exhdr)); printf(" bss segment size = 0x%lx\n", exhdr->a_bss); printf(" text segment relocation size = 0x%lx, file offset = %ld, %d text relocations\n", exhdr->a_trsize, N_TRELOFF(*exhdr), exhdr->a_trsize/sizeof(struct relocation_info)); printf(" data segment relocation size = 0x%lx, file offset = %ld, %d data relocations\n", exhdr->a_drsize, N_DRELOFF(*exhdr), exhdr->a_drsize/sizeof(struct relocation_info)); printf(" symbol table size = 0x%lx, symbol table file offset = %ld (%d symbols)\n", exhdr->a_syms, N_SYMOFF(*exhdr), exhdr->a_syms/sizeof(struct nlist)); printf(" string table file offset = 0x%lx (%d)\n", N_STROFF(*exhdr), N_STROFF(*exhdr)); printf(" entry point = 0x%lx\n", exhdr->a_entry); printf(" text address = 0x%lx\n\tdata address = 0x%lx\n" "\tbss address = 0x%lx\n", txt_addr, dat_addr, bss_addr /* N_TXTADDR(*exhdr), N_DATADDR(*exhdr), N_BSSADDR(*exhdr) */ ); } }
main (int argc, char **argv, char **envp) { Elf32_Ehdr ex; Elf32_Phdr *ph; Elf32_Shdr *sh; Elf32_Sym *symtab; char *shstrtab; int strtabix, symtabix; int i, pad; struct sect text, data, bss; struct filehdr efh; struct aouthdr eah; struct scnhdr esecs [6]; int infile, outfile; unsigned long cur_vma = ULONG_MAX; int addflag = 0; int nosecs; text.len = data.len = bss.len = 0; text.vaddr = data.vaddr = bss.vaddr = 0; /* Check args... */ if (argc < 3 || argc > 4) { usage: fprintf (stderr, "usage: elf2aout <elf executable> <a.out executable> [-a]\n"); exit (1); } if (argc == 4) { if (strcmp (argv [3], "-a")) goto usage; addflag = 1; } /* Try the input file... */ if ((infile = open (argv [1], O_RDONLY)) < 0) { fprintf (stderr, "Can't open %s for read: %s\n", argv [1], strerror (errno)); exit (1); } /* Read the header, which is at the beginning of the file... */ i = read (infile, &ex, sizeof ex); if (i != sizeof ex) { fprintf (stderr, "ex: %s: %s.\n", argv [1], i ? strerror (errno) : "End of file reached"); exit (1); } if (ex.e_ident[EI_DATA] == ELFDATA2MSB) format_bigendian = 1; if (ntohs (0xaa55) == 0xaa55) { if (!format_bigendian) must_convert_endian = 1; } else { if (format_bigendian) must_convert_endian = 1; } if (must_convert_endian) convert_elf_hdr (&ex); /* Read the program headers... */ ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff, ex.e_phnum * sizeof (Elf32_Phdr), "ph"); if (must_convert_endian) convert_elf_phdrs (ph, ex.e_phnum); /* Read the section headers... */ sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff, ex.e_shnum * sizeof (Elf32_Shdr), "sh"); if (must_convert_endian) convert_elf_shdrs (sh, ex.e_shnum); /* Read in the section string table. */ shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset, sh [ex.e_shstrndx].sh_size, "shstrtab"); /* Figure out if we can cram the program header into an ECOFF header... Basically, we can't handle anything but loadable segments, but we can ignore some kinds of segments. We can't handle holes in the address space. Segments may be out of order, so we sort them first. */ qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp); for (i = 0; i < ex.e_phnum; i++) { /* Section types we can ignore... */ if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE || ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO) continue; /* Section types we can't handle... */ else if (ph [i].p_type != PT_LOAD) { fprintf (stderr, "Program header %d type %d can't be converted.\n"); exit (1); } /* Writable (data) segment? */ if (ph [i].p_flags & PF_W) { struct sect ndata, nbss; ndata.vaddr = ph [i].p_vaddr; ndata.len = ph [i].p_filesz; nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz; nbss.len = ph [i].p_memsz - ph [i].p_filesz; combine (&data, &ndata, 0); combine (&bss, &nbss, 1); } else { struct sect ntxt; ntxt.vaddr = ph [i].p_vaddr; ntxt.len = ph [i].p_filesz; combine (&text, &ntxt, 0); } /* Remember the lowest segment start address. */ if (ph [i].p_vaddr < cur_vma) cur_vma = ph [i].p_vaddr; } /* Sections must be in order to be converted... */ if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) { fprintf (stderr, "Sections ordering prevents a.out conversion.\n"); exit (1); } /* If there's a data section but no text section, then the loader combined everything into one section. That needs to be the text section, so just make the data section zero length following text. */ if (data.len && !text.len) { text = data; data.vaddr = text.vaddr + text.len; data.len = 0; } /* If there is a gap between text and data, we'll fill it when we copy the data, so update the length of the text segment as represented in a.out to reflect that, since a.out doesn't allow gaps in the program address space. */ if (text.vaddr + text.len < data.vaddr) text.len = data.vaddr - text.vaddr; /* We now have enough information to cons up an a.out header... */ eah.magic = OMAGIC; eah.vstamp = 200; eah.tsize = text.len; eah.dsize = data.len; eah.bsize = bss.len; eah.entry = ex.e_entry; eah.text_start = text.vaddr; eah.data_start = data.vaddr; eah.bss_start = bss.vaddr; eah.gprmask = 0xf3fffffe; memset (&eah.cprmask, '\0', sizeof eah.cprmask); eah.gp_value = 0; /* unused. */ if (format_bigendian) efh.f_magic = MIPSEBMAGIC; else efh.f_magic = MIPSELMAGIC; if (addflag) nosecs = 6; else nosecs = 3; efh.f_nscns = nosecs; efh.f_timdat = 0; /* bogus */ efh.f_symptr = 0; efh.f_nsyms = 0; efh.f_opthdr = sizeof eah; efh.f_flags = 0x100f; /* Stripped, not sharable. */ memset (esecs, 0, sizeof esecs); strcpy (esecs [0].s_name, ".text"); strcpy (esecs [1].s_name, ".data"); strcpy (esecs [2].s_name, ".bss"); if (addflag) { strcpy (esecs [3].s_name, ".rdata"); strcpy (esecs [4].s_name, ".sdata"); strcpy (esecs [5].s_name, ".sbss"); } esecs [0].s_paddr = esecs [0].s_vaddr = eah.text_start; esecs [1].s_paddr = esecs [1].s_vaddr = eah.data_start; esecs [2].s_paddr = esecs [2].s_vaddr = eah.bss_start; if (addflag) { esecs [3].s_paddr = esecs [3].s_vaddr = 0; esecs [4].s_paddr = esecs [4].s_vaddr = 0; esecs [5].s_paddr = esecs [5].s_vaddr = 0; } esecs [0].s_size = eah.tsize; esecs [1].s_size = eah.dsize; esecs [2].s_size = eah.bsize; if (addflag) { esecs [3].s_size = 0; esecs [4].s_size = 0; esecs [5].s_size = 0; } esecs [0].s_scnptr = N_TXTOFF (efh, eah); esecs [1].s_scnptr = N_DATOFF (efh, eah); #define ECOFF_SEGMENT_ALIGNMENT(a) 0x10 #define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1)) esecs [2].s_scnptr = esecs [1].s_scnptr + ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eah)); if (addflag) { esecs [3].s_scnptr = 0; esecs [4].s_scnptr = 0; esecs [5].s_scnptr = 0; } esecs [0].s_relptr = esecs [1].s_relptr = esecs [2].s_relptr = 0; esecs [0].s_lnnoptr = esecs [1].s_lnnoptr = esecs [2].s_lnnoptr = 0; esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0; esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0; if (addflag) { esecs [3].s_relptr = esecs [4].s_relptr = esecs [5].s_relptr = 0; esecs [3].s_lnnoptr = esecs [4].s_lnnoptr = esecs [5].s_lnnoptr = 0; esecs [3].s_nreloc = esecs [4].s_nreloc = esecs [5].s_nreloc = 0; esecs [3].s_nlnno = esecs [4].s_nlnno = esecs [5].s_nlnno = 0; } esecs [0].s_flags = 0x20; esecs [1].s_flags = 0x40; esecs [2].s_flags = 0x82; if (addflag) { esecs [3].s_flags = 0x100; esecs [4].s_flags = 0x200; esecs [5].s_flags = 0x400; } /* Make the output file... */ if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0) { fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno)); exit (1); } if (must_convert_endian) convert_ecoff_filehdr (&efh); /* Write the headers... */ i = write (outfile, &efh, sizeof efh); if (i != sizeof efh) { perror ("efh: write"); exit (1); for (i = 0; i < nosecs; i++) { printf ("Section %d: %s phys %x size %x file offset %x\n", i, esecs [i].s_name, esecs [i].s_paddr, esecs [i].s_size, esecs [i].s_scnptr); } } fprintf (stderr, "wrote %d byte file header.\n", i); if (must_convert_endian) convert_ecoff_aouthdr (&eah); i = write (outfile, &eah, sizeof eah); if (i != sizeof eah) { perror ("eah: write"); exit (1); } fprintf (stderr, "wrote %d byte a.out header.\n", i); if (must_convert_endian) convert_ecoff_esecs (&esecs[0], nosecs); i = write (outfile, &esecs, nosecs * sizeof(struct scnhdr)); if (i != nosecs * sizeof(struct scnhdr)) { perror ("esecs: write"); exit (1); } fprintf (stderr, "wrote %d bytes of section headers.\n", i); if (pad = ((sizeof efh + sizeof eah + nosecs * sizeof(struct scnhdr)) & 15)) { pad = 16 - pad; i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad); if (i < 0) { perror ("ipad: write"); exit (1); } fprintf (stderr, "wrote %d byte pad.\n", i); } /* Copy the loadable sections. Zero-fill any gaps less than 64k; complain about any zero-filling, and die if we're asked to zero-fill more than 64k. */ for (i = 0; i < ex.e_phnum; i++) { /* Unprocessable sections were handled above, so just verify that the section can be loaded before copying. */ if (ph [i].p_type == PT_LOAD && ph [i].p_filesz) { if (cur_vma != ph [i].p_vaddr) { unsigned long gap = ph [i].p_vaddr - cur_vma; char obuf [1024]; if (gap > 65536) { fprintf (stderr, "Intersegment gap (%d bytes) too large.\n", gap); exit (1); } fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap); memset (obuf, 0, sizeof obuf); while (gap) { int count = write (outfile, obuf, (gap > sizeof obuf ? sizeof obuf : gap)); if (count < 0) { fprintf (stderr, "Error writing gap: %s\n", strerror (errno)); exit (1); } gap -= count; } } fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz); copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz); cur_vma = ph [i].p_vaddr + ph [i].p_filesz; } } /* * Write a page of padding for boot PROMS that read entire pages. * Without this, they may attempt to read past the end of the * data section, incur an error, and refuse to boot. */ { char obuf[4096]; memset(obuf, 0, sizeof obuf); if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) { fprintf(stderr, "Error writing PROM padding: %s\n", strerror(errno)); exit(1); } } /* Looks like we won... */ exit (0); }
int main(int argc, char *argv[]) { struct exec head; struct ecoff_exechdr ehead; struct ecoff_scnhdr escn[3]; int infd, outfd; int n; if (argc != 3) usage(); infd = open(argv[1], O_RDONLY); if (infd < 0) err(1, argv[1]); outfd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644); if (outfd < 0) err(1, argv[2]); n = read(infd, &head, sizeof(head)); if (n < sizeof(head)) err(1, "read"); if (N_BADMAG(head)) { printf("%s: bad magic number\n", argv[1]); exit(1); } if (head.a_trsize || head.a_drsize) { printf("%s: has relocations\n", argv[1]); exit(1); } /* * Header */ ehead.f.f_magic = 0x016d; /* MC88OMAGIC */ ehead.f.f_nscns = 3; ehead.f.f_timdat = 0; /* ignored */ ehead.f.f_symptr = 0; /* ignored */ ehead.f.f_nsyms = 0; /* ignored */ ehead.f.f_opthdr = sizeof ehead.a; ehead.f.f_flags = 0x020f; /* F_RELFLG | F_EXEC | F_LNNO | 8 | F_AR16WR */ ehead.a.magic = N_GETMAGIC(head); ehead.a.vstamp = 0; /* ignored */ ehead.a.tsize = head.a_text; /* ignored */ ehead.a.dsize = head.a_data; /* ignored */ ehead.a.bsize = head.a_bss; /* ignored */ ehead.a.entry = head.a_entry; ehead.a.text_start = N_TXTADDR(head); /* ignored */ ehead.a.data_start = N_DATADDR(head); /* ignored */ n = write(outfd, &ehead, sizeof(ehead)); if (n != sizeof(ehead)) err(1, "write"); /* * Sections. * Note that we merge .bss into .data since the PROM will not * clear it and locore does not do this either. */ strncpy(escn[0].s_name, ".text", sizeof escn[0].s_name); escn[0].s_paddr = N_TXTADDR(head); /* ignored, 1:1 mapping */ escn[0].s_size = round(head.a_text, 8); escn[0].s_scnptr = round(sizeof(ehead) + sizeof(escn), 0x10); escn[0].s_relptr = 0; escn[0].s_lnnoptr = 0; escn[0].s_nlnno = 0; escn[0].s_flags = 0x20; /* STYP_TEXT */ strncpy(escn[1].s_name, ".data", sizeof escn[1].s_name); escn[1].s_paddr = N_DATADDR(head); /* ignored, 1:1 mapping */ escn[1].s_scnptr = escn[0].s_scnptr + escn[0].s_size; escn[1].s_size = round(head.a_data + head.a_bss, 8); escn[1].s_relptr = 0; escn[1].s_lnnoptr = 0; escn[1].s_nlnno = 0; escn[1].s_flags = 0x40; /* STYP_DATA */ strncpy(escn[2].s_name, ".bss", sizeof escn[2].s_name); escn[2].s_paddr = N_BSSADDR(head) + head.a_bss; /* ignored, 1:1 mapping */ escn[2].s_scnptr = 0; /* nothing in the file */ escn[2].s_size = 0; escn[2].s_relptr = 0; escn[2].s_lnnoptr = 0; escn[2].s_nlnno = 0; escn[2].s_flags = 0x80; /* STYP_BSS */ /* adjust load addresses */ escn[0].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ; escn[1].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ; escn[2].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ; escn[0].s_vaddr = escn[0].s_paddr; escn[1].s_vaddr = escn[1].s_paddr; escn[2].s_vaddr = escn[2].s_paddr; n = write(outfd, &escn, sizeof(escn)); if (n != sizeof(escn)) err(1, "write"); /* * Copy text section */ #ifdef DEBUG printf("copying %s: source %lx dest %lx size %x\n", escn[0].s_name, N_TXTOFF(head), escn[0].s_scnptr, head.a_text); #endif lseek(outfd, escn[0].s_scnptr, SEEK_SET); lseek(infd, N_TXTOFF(head), SEEK_SET); copybits(infd, outfd, head.a_text); /* * Copy data section */ #ifdef DEBUG printf("copying %s: source %lx dest %lx size %x\n", escn[1].s_name, N_DATOFF(head), escn[1].s_scnptr, head.a_data); #endif lseek(outfd, escn[1].s_scnptr, SEEK_SET); lseek(infd, N_DATOFF(head), SEEK_SET); copybits(infd, outfd, head.a_data); /* * ``Copy'' bss section */ #ifdef DEBUG printf("copying %s: size %lx\n", escn[2].s_name, round(head.a_data + head.a_bss, 8) - head.a_data); #endif zerobits(outfd, round(head.a_data + head.a_bss, 8) - head.a_data); close(infd); close(outfd); exit(0); }