Esempio n. 1
0
static int
is_aout_shared_lib(const char *name)
{
	struct exec ex;
	struct stat st;
	int fd;

	if (stat(name, &st) < 0)
		return 0;
	if ((st.st_mode & (S_IFREG|S_IFLNK)) == 0)
		return 0;

	fd = open(name, O_RDONLY);
	if (fd < 0) {
		return 0;
	}
	if (read(fd, &ex, sizeof ex) - sizeof ex != 0) {
		close(fd);
		return 0;
	}
	close(fd);
	if (N_GETMAGIC(ex) != ZMAGIC ||
	    (N_GETFLAG(ex) & EX_DYNAMIC) == 0)
		return 0;

	return 1;
}
Esempio n. 2
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);
    }
}
Esempio n. 3
0
static int
is_exos_aout(int fd)
{
  struct exec hdr;
  u_int dynamic;

  if (lseek(fd, 0, SEEK_SET) == -1 ||
      read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
      lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 ||
      read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic))
    return 0;

  if (N_GETMAGIC(hdr) != OMAGIC ||
      N_GETMID(hdr) != MID_I386 ||
      N_GETFLAG(hdr) != 0)
    return 0;

  return 1;
}
Esempio n. 4
0
File: ldd.c Progetto: fengsi/freebsd
static int
is_executable(const char *fname, int fd, int *is_shlib, int *type)
{
	union {
#ifdef AOUT_SUPPORTED
		struct exec aout;
#endif
#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
		Elf32_Ehdr elf32;
#endif
		Elf_Ehdr elf;
	} hdr;
	int n;

	*is_shlib = 0;
	*type = TYPE_UNKNOWN;

	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
		warn("%s: can't read program header", fname);
		return (0);
	}

#ifdef AOUT_SUPPORTED
	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
		/* a.out file */
		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
#if 1 /* Compatibility */
		    || hdr.aout.a_entry < __LDPGSZ
#endif
			) {
			warnx("%s: not a dynamic executable", fname);
			return (0);
		}
		*type = TYPE_AOUT;
		return (1);
	}
#endif

#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
		/* Handle 32 bit ELF objects */
		Elf32_Phdr phdr;
		int dynamic, i;

		dynamic = 0;
		*type = TYPE_ELF32;

		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
			warnx("%s: header too short", fname);
			return (0);
		}
		for (i = 0; i < hdr.elf32.e_phnum; i++) {
			if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
			    sizeof(phdr)) {
				warnx("%s: can't read program header", fname);
				return (0);
			}
			if (phdr.p_type == PT_DYNAMIC) {
				dynamic = 1;
				break;
			}
		}

		if (!dynamic) {
			warnx("%s: not a dynamic ELF executable", fname);
			return (0);
		}
		if (hdr.elf32.e_type == ET_DYN) {
			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
				*is_shlib = 1;
				return (1);
			}
			warnx("%s: not a FreeBSD ELF shared object", fname);
			return (0);
		}

		return (1);
	}
#endif

	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
		/* Handle default ELF objects on this architecture */
		Elf_Phdr phdr;
		int dynamic, i;

		dynamic = 0;
		*type = TYPE_ELF;

		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
			warnx("%s: header too short", fname);
			return (0);
		}
		for (i = 0; i < hdr.elf.e_phnum; i++) {
			if (read(fd, &phdr, hdr.elf.e_phentsize)
			   != sizeof(phdr)) {
				warnx("%s: can't read program header", fname);
				return (0);
			}
			if (phdr.p_type == PT_DYNAMIC) {
				dynamic = 1;
				break;
			}
		}

		if (!dynamic) {
			warnx("%s: not a dynamic ELF executable", fname);
			return (0);
		}
		if (hdr.elf.e_type == ET_DYN) {
			if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
				*is_shlib = 1;
				return (1);
			}
			warnx("%s: not a FreeBSD ELF shared object", fname);
			return (0);
		}

		return (1);
	}

	warnx("%s: not a dynamic executable", fname);
	return (0);
}
Esempio n. 5
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);
}
Esempio n. 6
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) */
		);
	}
}
Esempio n. 7
0
int main (int argc, char *argv[]) {
  register struct nlist *s;
  register caddr_t strtab;
  register off_t stroff, symoff;
  register u_long symsize;
  register int cc;
  size_t strsize;
  struct nlist nbuf[1024];
  struct exec exec;
  struct stat st;
  int fd;
  int pageOffset;

  if ((fd = open (argv[1], O_RDONLY)) < 0) {
    fprintf (stderr, "could not open %s\n", argv[1]);
    return -1;
  }
  if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
      read(fd, &exec, sizeof(exec)) != sizeof(exec) ||
      fstat(fd, &st) < 0) {
    fprintf (stderr, "Invalid binary file\n");
    return -1;
  }
  if (N_BADMAG (exec) || N_GETMID (exec) != MID_I386) {
    fprintf (stderr, "invalid executable file N_BADMAG(exec) %d N_GETMID (exec) %d MID_I386 %d\n", N_BADMAG(exec), N_GETMID(exec), MID_I386);
    exit (1);
  }
  if (N_GETFLAG (exec) & EX_DYNAMIC) {
    fprintf (stderr, "are you giving me a dynamically linked executable??\n");
    return -1;
  }
  symoff = N_SYMOFF(exec);
  symsize = exec.a_syms;
  stroff = symoff + symsize;

#ifndef __linux__
  /* Check for files too large to mmap. */
  if (st.st_size - stroff > SIZE_T_MAX) {
    fprintf (stderr, "file too large\n");
    return -1;
  }
#endif

  /*
   * Map string table into our address space.  This gives us
   * an easy way to randomly access all the strings, without
   * making the memory allocation permanent as with malloc/free
   * (i.e., munmap will return it to the system).
   */
  strsize = st.st_size - stroff;
  pageOffset = stroff % 4096;
  stroff -= pageOffset;
  strsize += pageOffset;

  strtab = mmap(NULL, (size_t)strsize, PROT_READ, MAP_SHARED, fd, stroff);
  if (strtab == (char *)-1) {
    warn ("could not mmap string table");
    return -1;
  }
  strtab += pageOffset;
  strsize -= pageOffset;

  if (lseek(fd, symoff, SEEK_SET) == -1) {
    fprintf (stderr, "could not lseek to symbol table\n");
    return -1;
  }

  while (symsize > 0) {
    int i;
    cc = my_min(symsize, sizeof(nbuf));
    if (read(fd, nbuf, cc) != cc)
      break;
    symsize -= cc;
    for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
      register int soff = s->n_un.n_strx;

      if (soff == 0 || (s->n_type & N_STAB) != 0)
        continue;
      for (i = 0; exclude[i]; i++) {
        if (!strcmp (&strtab[soff], exclude[i]))
          goto skip;
      }
      /* hack to avoid symbol with name equal to tmp filename used
         to build us */
      if (strchr (&strtab[soff], '.') || strchr (&strtab[soff], '/'))
        goto skip;
      if (s->n_type & N_EXT) {
        printf ("\t.globl\t%s\n\t.set\t%s,0x%lx\n\t.weak\t%s\n\n",
                &strtab[soff], &strtab[soff], s->n_value, &strtab[soff]);
      }
    skip:
      ;
    }
  }
  munmap(strtab, strsize);
  return 0;
}
Esempio n. 8
0
static int
exec_exos_aout(int fd, const char *path, char *const argv[],
	       char *const envp[], struct Env *e, u_int flags)
{
  u_int envid = e->env_id;
  struct exec hdr;
  u_int dynamic;
  int r;
  struct _exos_exec_args eea;

  if (lseek(fd, 0, SEEK_SET) == -1 ||
      read(fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
      lseek(fd, sizeof(hdr) + hdr.a_text, SEEK_SET) == -1 ||
      read(fd, &dynamic, sizeof(dynamic)) != sizeof(dynamic))
    return 0;

  if (N_GETMAGIC(hdr) != OMAGIC ||
      N_GETMID(hdr) != MID_I386 ||
      N_GETFLAG(hdr) != 0)
    return 0;

  if (!(flags & _EXEC_USE_FD)) {
    close(fd);
    fd = -1;
  } else if (lseek(fd, 0, SEEK_SET) == -1)
    return 0;

  if (dynamic < SHARED_LIBRARY_START) dynamic = 0;
  if (dynamic == 0 && (flags & _EXEC_SHLIB_ONLY)) {
    r = -EINVAL;
    goto err;
  }

  /* if static, then read in entire program... */
  if (!dynamic) {
    u_int start_text_addr;

    if (flags & _EXEC_USE_FD)
      start_text_addr = __load_prog_fd(fd, 1, envid);
    else
      start_text_addr = __load_prog(path, argv[0], 1, envid);
    if (!start_text_addr) {
      r = -ENOEXEC;
      goto err;
    }
    /* set start address */
    e->env_tf.tf_eip = start_text_addr;
  }
  /* if dynamic, then make sure shared library is available */
  else if (dynamic) {
    struct stat sb;

    /* If flag so indicates, then require RO copy and use in mem version */
    if (!(flags & _EXEC_SHLIB_ONLY)) {
      /* if the shared library is not already in memory, or if it's old */
      /* then we need to (re)read it in */
      if (stat(PATH_LIBEXOS, &sb)) {
	r = -errno;
	kprintf("error stat'ing sl: %d\n", errno);
	goto err;
      }
      /* if we don't have a RO copy or it's out of date... */
      if (!isvamapped(SHARED_LIBRARY_START_RODATA) ||
	  memcmp(&sl_data->mod_time, &sb.st_mtimespec,
		 sizeof(sb.st_mtimespec))) {
	int slfd;

	/* if it's out of date, then unmap it */
	if (isvamapped(SHARED_LIBRARY_START_RODATA))
	  munmap((void*)SHARED_LIBRARY_START_RODATA,
		 (sl_data->text_pages + sl_data->data_pages) * NBPG);
	slfd = open (PATH_LIBEXOS, O_RDONLY);
	if (slfd < 0) {
	  r = -errno;
	  kprintf("could not open shared library " PATH_LIBEXOS "\n");
	  goto err;
	}
	if ((r = __load_sl_image (slfd)) < 0) {
	  kprintf("could not load library\n");
	  close(slfd);
	  goto err;
	}
	*((struct timespec*)&sl_data->mod_time) = sb.st_mtimespec;
	assert(sys_self_mod_pte_range(0, PG_RO, PG_W,
				      SHARED_LIBRARY_START_RODATA, 1) == 0);
	close (slfd);
      }
    } else {
      if (!isvamapped(SHARED_LIBRARY_START_RODATA)) {
	r = -EINVAL;
	goto err;
      }
    }

    /* share the text region read only/exec into child */
    if (__vm_share_region(SHARED_LIBRARY_START_RODATA,
			  sl_data->text_pages * NBPG, 0, 0,
			  envid, SHARED_LIBRARY_START)) {
      kprintf ("__vm_share_region failed for text region\n");
      r = -ENOEXEC;
      goto err;
    }

    /* share the read only data region into child cow */
    if (__vm_share_region(SHARED_LIBRARY_START_RODATA +
			  sl_data->text_pages * NBPG,
			  sl_data->data_pages * NBPG, 0, 0, envid,
			  SHARED_LIBRARY_START + sl_data->text_pages * NBPG)) {
      kprintf ("__vm_share_region failed for cow data region\n");
      r = -ENOEXEC;
      goto err;
    }
    if (sys_mod_pte_range(0, PG_COW, PG_RO | PG_SHARED, SHARED_LIBRARY_START +
			  sl_data->text_pages * NBPG, sl_data->data_pages, 0,
			  envid) < 0) {
      kprintf ("sys_mod_pte_range failed for cow data region\n");
      r = -ENOEXEC;
      goto err;
    }

    /* share the RO copy of the shared library */
    if (__vm_share_region(SHARED_LIBRARY_START_RODATA,
			  (sl_data->text_pages + sl_data->data_pages) * NBPG,
			  0, 0, envid, SHARED_LIBRARY_START_RODATA)) {
      kprintf ("__vm_share_region failed for read only text/data region\n");
      r = -ENOEXEC;
      goto err;
    }

    /* demand alloc bss for sl or no? */    
    if (getenv("NO_BSS_DEMAND_ALLOC")) {
      /* zero the bss */
      if (__zero_segment (envid, SHARED_LIBRARY_START +
			  (sl_data->text_pages + sl_data->data_pages) *
			  NBPG, sl_data->bss_pages * NBPG) < 0) {
	kprintf("could not create bss segment\n");
	r = -ENOEXEC;
	goto err;
      }
     } /* otherwise the fault handler will deal with it */
    
    /* set start address */
    e->env_tf.tf_eip = SHARED_LIBRARY_START + sizeof(struct exec);
  }

  /* take care of args, etc */
  if (flags & _EXEC_USE_FD)
    eea.eea_prog_fd = fd;
  else
    eea.eea_prog_fd = -1;
  if ((r = setup_new_stack(argv, envp, envid, &e->env_tf.tf_esp, &eea)) < 0)
    goto err;

  return 1;

 err:
  return r;
}