Exemple #1
0
/* 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;
}
Exemple #2
0
/* 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;
}
Exemple #3
0
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);
    }
}
Exemple #4
0
/* 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);
}
Exemple #5
0
/* 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);
}
Exemple #6
0
/*
 * "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;
}
Exemple #7
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 () */
Exemple #9
0
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) */
		);
	}
}
Exemple #10
0
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);
}
Exemple #11
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);
}