xref: /qemu/linux-user/elfload.c (revision 9de5e440b9f6a6c6305c0b81d1df4ddcc5a4b966)
131e31b8aSbellard /* This is the Linux kernel elf-loading code, ported into user space */
231e31b8aSbellard 
331e31b8aSbellard #include <stdio.h>
431e31b8aSbellard #include <sys/types.h>
531e31b8aSbellard #include <fcntl.h>
631e31b8aSbellard #include <sys/stat.h>
731e31b8aSbellard #include <errno.h>
831e31b8aSbellard #include <unistd.h>
931e31b8aSbellard #include <sys/mman.h>
1031e31b8aSbellard #include <stdlib.h>
1131e31b8aSbellard #include <string.h>
1231e31b8aSbellard 
1331e31b8aSbellard #include "gemu.h"
1431e31b8aSbellard 
1531e31b8aSbellard #include "linux_bin.h"
1631e31b8aSbellard #include "elf.h"
1731e31b8aSbellard #include "segment.h"
1831e31b8aSbellard 
1931e31b8aSbellard /* Necessary parameters */
2031e31b8aSbellard #define	ALPHA_PAGE_SIZE 4096
2131e31b8aSbellard #define	X86_PAGE_SIZE 4096
2231e31b8aSbellard 
2331e31b8aSbellard #define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1))
2431e31b8aSbellard #define X86_PAGE_MASK (~(X86_PAGE_SIZE-1))
2531e31b8aSbellard 
2631e31b8aSbellard #define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK)
2731e31b8aSbellard #define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK)
2831e31b8aSbellard 
2931e31b8aSbellard #define NGROUPS 32
3031e31b8aSbellard 
3131e31b8aSbellard #define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE
3231e31b8aSbellard #define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1))
3331e31b8aSbellard #define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1))
3431e31b8aSbellard 
3531e31b8aSbellard #define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1))
3631e31b8aSbellard #define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1))
3731e31b8aSbellard 
3831e31b8aSbellard #define INTERPRETER_NONE 0
3931e31b8aSbellard #define INTERPRETER_AOUT 1
4031e31b8aSbellard #define INTERPRETER_ELF 2
4131e31b8aSbellard 
4231e31b8aSbellard #define DLINFO_ITEMS 12
4331e31b8aSbellard 
4431e31b8aSbellard /* Where we find X86 libraries... */
4531e31b8aSbellard //#define X86_DEFAULT_LIB_DIR	"/usr/x86/"
4631e31b8aSbellard #define X86_DEFAULT_LIB_DIR	"/"
4731e31b8aSbellard 
4831e31b8aSbellard //extern void * mmap4k();
4931e31b8aSbellard #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
5031e31b8aSbellard 
5131e31b8aSbellard extern unsigned long x86_stack_size;
5231e31b8aSbellard 
5331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
5431e31b8aSbellard 
5531e31b8aSbellard #ifdef BSWAP_NEEDED
5631e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr)
5731e31b8aSbellard {
5831e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
5931e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
6031e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
6131e31b8aSbellard     bswap32s(&ehdr->e_entry);		/* Entry point virtual address */
6231e31b8aSbellard     bswap32s(&ehdr->e_phoff);		/* Program header table file offset */
6331e31b8aSbellard     bswap32s(&ehdr->e_shoff);		/* Section header table file offset */
6431e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
6531e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
6631e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
6731e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
6831e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
6931e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
7031e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
7131e31b8aSbellard }
7231e31b8aSbellard 
7331e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr)
7431e31b8aSbellard {
7531e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
7631e31b8aSbellard     bswap32s(&phdr->p_offset);		/* Segment file offset */
7731e31b8aSbellard     bswap32s(&phdr->p_vaddr);		/* Segment virtual address */
7831e31b8aSbellard     bswap32s(&phdr->p_paddr);		/* Segment physical address */
7931e31b8aSbellard     bswap32s(&phdr->p_filesz);		/* Segment size in file */
8031e31b8aSbellard     bswap32s(&phdr->p_memsz);		/* Segment size in memory */
8131e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
8231e31b8aSbellard     bswap32s(&phdr->p_align);		/* Segment alignment */
8331e31b8aSbellard }
8431e31b8aSbellard #endif
8531e31b8aSbellard 
8631e31b8aSbellard static void * get_free_page(void)
8731e31b8aSbellard {
8831e31b8aSbellard     void *	retval;
8931e31b8aSbellard 
9031e31b8aSbellard     /* User-space version of kernel get_free_page.  Returns a page-aligned
9131e31b8aSbellard      * page-sized chunk of memory.
9231e31b8aSbellard      */
9331e31b8aSbellard     retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
9431e31b8aSbellard 			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
9531e31b8aSbellard 
9631e31b8aSbellard     if((long)retval == -1) {
9731e31b8aSbellard 	perror("get_free_page");
9831e31b8aSbellard 	exit(-1);
9931e31b8aSbellard     }
10031e31b8aSbellard     else {
10131e31b8aSbellard 	return(retval);
10231e31b8aSbellard     }
10331e31b8aSbellard }
10431e31b8aSbellard 
10531e31b8aSbellard static void free_page(void * pageaddr)
10631e31b8aSbellard {
10731e31b8aSbellard     (void)munmap(pageaddr, ALPHA_PAGE_SIZE);
10831e31b8aSbellard }
10931e31b8aSbellard 
11031e31b8aSbellard /*
11131e31b8aSbellard  * 'copy_string()' copies argument/envelope strings from user
11231e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
11331e31b8aSbellard  * to be put directly into the top of new user memory.
11431e31b8aSbellard  *
11531e31b8aSbellard  */
11631e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
11731e31b8aSbellard                 unsigned long p)
11831e31b8aSbellard {
11931e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
12031e31b8aSbellard     int len, offset = 0;
12131e31b8aSbellard 
12231e31b8aSbellard     if (!p) {
12331e31b8aSbellard 	return 0;       /* bullet-proofing */
12431e31b8aSbellard     }
12531e31b8aSbellard     while (argc-- > 0) {
12631e31b8aSbellard 	if (!(tmp1 = tmp = get_user(argv+argc))) {
12731e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
12831e31b8aSbellard 	    exit(-1);
12931e31b8aSbellard 	}
13031e31b8aSbellard 	while (get_user(tmp++));
13131e31b8aSbellard 	len = tmp - tmp1;
13231e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
13331e31b8aSbellard 		return 0;
13431e31b8aSbellard 	}
13531e31b8aSbellard 	while (len) {
13631e31b8aSbellard 	    --p; --tmp; --len;
13731e31b8aSbellard 	    if (--offset < 0) {
13831e31b8aSbellard 		offset = p % X86_PAGE_SIZE;
13931e31b8aSbellard 		if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
14031e31b8aSbellard 		    !(pag = (char *) page[p/X86_PAGE_SIZE] =
14131e31b8aSbellard 		      (unsigned long *) get_free_page())) {
14231e31b8aSbellard 			return 0;
14331e31b8aSbellard 		}
14431e31b8aSbellard 	    }
14531e31b8aSbellard 	    if (len == 0 || offset == 0) {
14631e31b8aSbellard 	        *(pag + offset) = get_user(tmp);
14731e31b8aSbellard 	    }
14831e31b8aSbellard 	    else {
14931e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
15031e31b8aSbellard 	      tmp -= bytes_to_copy;
15131e31b8aSbellard 	      p -= bytes_to_copy;
15231e31b8aSbellard 	      offset -= bytes_to_copy;
15331e31b8aSbellard 	      len -= bytes_to_copy;
15431e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
15531e31b8aSbellard 	    }
15631e31b8aSbellard 	}
15731e31b8aSbellard     }
15831e31b8aSbellard     return p;
15931e31b8aSbellard }
16031e31b8aSbellard 
16131e31b8aSbellard static int in_group_p(gid_t g)
16231e31b8aSbellard {
16331e31b8aSbellard     /* return TRUE if we're in the specified group, FALSE otherwise */
16431e31b8aSbellard     int		ngroup;
16531e31b8aSbellard     int		i;
16631e31b8aSbellard     gid_t	grouplist[NGROUPS];
16731e31b8aSbellard 
16831e31b8aSbellard     ngroup = getgroups(NGROUPS, grouplist);
16931e31b8aSbellard     for(i = 0; i < ngroup; i++) {
17031e31b8aSbellard 	if(grouplist[i] == g) {
17131e31b8aSbellard 	    return 1;
17231e31b8aSbellard 	}
17331e31b8aSbellard     }
17431e31b8aSbellard     return 0;
17531e31b8aSbellard }
17631e31b8aSbellard 
17731e31b8aSbellard static int count(char ** vec)
17831e31b8aSbellard {
17931e31b8aSbellard     int		i;
18031e31b8aSbellard 
18131e31b8aSbellard     for(i = 0; *vec; i++) {
18231e31b8aSbellard         vec++;
18331e31b8aSbellard     }
18431e31b8aSbellard 
18531e31b8aSbellard     return(i);
18631e31b8aSbellard }
18731e31b8aSbellard 
18831e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm)
18931e31b8aSbellard {
19031e31b8aSbellard     struct stat		st;
19131e31b8aSbellard     int mode;
19231e31b8aSbellard     int retval, id_change;
19331e31b8aSbellard 
19431e31b8aSbellard     if(fstat(bprm->fd, &st) < 0) {
19531e31b8aSbellard 	return(-errno);
19631e31b8aSbellard     }
19731e31b8aSbellard 
19831e31b8aSbellard     mode = st.st_mode;
19931e31b8aSbellard     if(!S_ISREG(mode)) {	/* Must be regular file */
20031e31b8aSbellard 	return(-EACCES);
20131e31b8aSbellard     }
20231e31b8aSbellard     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
20331e31b8aSbellard 	return(-EACCES);
20431e31b8aSbellard     }
20531e31b8aSbellard 
20631e31b8aSbellard     bprm->e_uid = geteuid();
20731e31b8aSbellard     bprm->e_gid = getegid();
20831e31b8aSbellard     id_change = 0;
20931e31b8aSbellard 
21031e31b8aSbellard     /* Set-uid? */
21131e31b8aSbellard     if(mode & S_ISUID) {
21231e31b8aSbellard     	bprm->e_uid = st.st_uid;
21331e31b8aSbellard 	if(bprm->e_uid != geteuid()) {
21431e31b8aSbellard 	    id_change = 1;
21531e31b8aSbellard 	}
21631e31b8aSbellard     }
21731e31b8aSbellard 
21831e31b8aSbellard     /* Set-gid? */
21931e31b8aSbellard     /*
22031e31b8aSbellard      * If setgid is set but no group execute bit then this
22131e31b8aSbellard      * is a candidate for mandatory locking, not a setgid
22231e31b8aSbellard      * executable.
22331e31b8aSbellard      */
22431e31b8aSbellard     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
22531e31b8aSbellard 	bprm->e_gid = st.st_gid;
22631e31b8aSbellard 	if (!in_group_p(bprm->e_gid)) {
22731e31b8aSbellard 		id_change = 1;
22831e31b8aSbellard 	}
22931e31b8aSbellard     }
23031e31b8aSbellard 
23131e31b8aSbellard     memset(bprm->buf, 0, sizeof(bprm->buf));
23231e31b8aSbellard     retval = lseek(bprm->fd, 0L, SEEK_SET);
23331e31b8aSbellard     if(retval >= 0) {
23431e31b8aSbellard         retval = read(bprm->fd, bprm->buf, 128);
23531e31b8aSbellard     }
23631e31b8aSbellard     if(retval < 0) {
23731e31b8aSbellard 	perror("prepare_binprm");
23831e31b8aSbellard 	exit(-1);
23931e31b8aSbellard 	/* return(-errno); */
24031e31b8aSbellard     }
24131e31b8aSbellard     else {
24231e31b8aSbellard 	return(retval);
24331e31b8aSbellard     }
24431e31b8aSbellard }
24531e31b8aSbellard 
24631e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
24731e31b8aSbellard 						struct image_info * info)
24831e31b8aSbellard {
24931e31b8aSbellard     unsigned long stack_base;
25031e31b8aSbellard     int i;
25131e31b8aSbellard     extern unsigned long stktop;
25231e31b8aSbellard 
25331e31b8aSbellard     stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
25431e31b8aSbellard 
25531e31b8aSbellard     p += stack_base;
25631e31b8aSbellard     if (bprm->loader) {
25731e31b8aSbellard 	bprm->loader += stack_base;
25831e31b8aSbellard     }
25931e31b8aSbellard     bprm->exec += stack_base;
26031e31b8aSbellard 
26131e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
26231e31b8aSbellard      * it for args, we'll use it for something else...
26331e31b8aSbellard      */
264*9de5e440Sbellard     /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
265*9de5e440Sbellard        we allocate a bigger stack. Need a better solution, for example
266*9de5e440Sbellard        by remapping the process stack directly at the right place */
26731e31b8aSbellard     if(x86_stack_size >  MAX_ARG_PAGES*X86_PAGE_SIZE) {
26831e31b8aSbellard         if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
26931e31b8aSbellard     		     PROT_READ | PROT_WRITE,
27031e31b8aSbellard 		     MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
27131e31b8aSbellard 	    perror("stk mmap");
27231e31b8aSbellard 	    exit(-1);
27331e31b8aSbellard 	}
27431e31b8aSbellard     }
27531e31b8aSbellard     else {
27631e31b8aSbellard         if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
27731e31b8aSbellard     		     PROT_READ | PROT_WRITE,
27831e31b8aSbellard 		     MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
27931e31b8aSbellard 	    perror("stk mmap");
28031e31b8aSbellard 	    exit(-1);
28131e31b8aSbellard 	}
28231e31b8aSbellard     }
28331e31b8aSbellard 
28431e31b8aSbellard     stktop = stack_base;
28531e31b8aSbellard 
28631e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
28731e31b8aSbellard 	if (bprm->page[i]) {
28831e31b8aSbellard 	    info->rss++;
28931e31b8aSbellard 
29031e31b8aSbellard 	    memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
29131e31b8aSbellard 	    free_page((void *)bprm->page[i]);
29231e31b8aSbellard 	}
29331e31b8aSbellard 	stack_base += X86_PAGE_SIZE;
29431e31b8aSbellard     }
29531e31b8aSbellard     return p;
29631e31b8aSbellard }
29731e31b8aSbellard 
29831e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
29931e31b8aSbellard {
30031e31b8aSbellard 	/* page-align the start and end addresses... */
30131e31b8aSbellard         start = ALPHA_PAGE_ALIGN(start);
30231e31b8aSbellard         end = ALPHA_PAGE_ALIGN(end);
30331e31b8aSbellard         if (end <= start)
30431e31b8aSbellard                 return;
30531e31b8aSbellard         if((long)mmap4k(start, end - start,
30631e31b8aSbellard                 PROT_READ | PROT_WRITE | PROT_EXEC,
30731e31b8aSbellard                 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
30831e31b8aSbellard 	    perror("cannot mmap brk");
30931e31b8aSbellard 	    exit(-1);
31031e31b8aSbellard 	}
31131e31b8aSbellard }
31231e31b8aSbellard 
31331e31b8aSbellard 
31431e31b8aSbellard /* We need to explicitly zero any fractional pages
31531e31b8aSbellard    after the data section (i.e. bss).  This would
31631e31b8aSbellard    contain the junk from the file that should not
31731e31b8aSbellard    be in memory */
31831e31b8aSbellard 
31931e31b8aSbellard 
32031e31b8aSbellard static void padzero(unsigned long elf_bss)
32131e31b8aSbellard {
32231e31b8aSbellard         unsigned long nbyte;
32331e31b8aSbellard         char * fpnt;
32431e31b8aSbellard 
32531e31b8aSbellard         nbyte = elf_bss & (ALPHA_PAGE_SIZE-1);	/* was X86_PAGE_SIZE - JRP */
32631e31b8aSbellard         if (nbyte) {
32731e31b8aSbellard 	    nbyte = ALPHA_PAGE_SIZE - nbyte;
32831e31b8aSbellard 	    fpnt = (char *) elf_bss;
32931e31b8aSbellard 	    do {
33031e31b8aSbellard 		*fpnt++ = 0;
33131e31b8aSbellard 	    } while (--nbyte);
33231e31b8aSbellard         }
33331e31b8aSbellard }
33431e31b8aSbellard 
33531e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc,
33631e31b8aSbellard                                   struct elfhdr * exec,
33731e31b8aSbellard                                   unsigned long load_addr,
33831e31b8aSbellard                                   unsigned long interp_load_addr, int ibcs,
33931e31b8aSbellard 				  struct image_info *info)
34031e31b8aSbellard {
341b17780d5Sbellard         target_ulong *argv, *envp, *dlinfo;
342b17780d5Sbellard         target_ulong *sp;
34331e31b8aSbellard 
34431e31b8aSbellard         /*
34531e31b8aSbellard          * Force 16 byte alignment here for generality.
34631e31b8aSbellard          */
34731e31b8aSbellard         sp = (unsigned int *) (~15UL & (unsigned long) p);
34831e31b8aSbellard         sp -= exec ? DLINFO_ITEMS*2 : 2;
34931e31b8aSbellard         dlinfo = sp;
35031e31b8aSbellard         sp -= envc+1;
35131e31b8aSbellard         envp = sp;
35231e31b8aSbellard         sp -= argc+1;
35331e31b8aSbellard         argv = sp;
35431e31b8aSbellard         if (!ibcs) {
355b17780d5Sbellard                 put_user(tswapl((target_ulong)envp),--sp);
356b17780d5Sbellard                 put_user(tswapl((target_ulong)argv),--sp);
35731e31b8aSbellard         }
35831e31b8aSbellard 
35931e31b8aSbellard #define NEW_AUX_ENT(id, val) \
360b17780d5Sbellard           put_user (tswapl(id), dlinfo++); \
361b17780d5Sbellard           put_user (tswapl(val), dlinfo++)
36231e31b8aSbellard 
36331e31b8aSbellard         if (exec) { /* Put this here for an ELF program interpreter */
36431e31b8aSbellard           struct elf_phdr * eppnt;
36531e31b8aSbellard           eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff);
36631e31b8aSbellard 
36731e31b8aSbellard           NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
36831e31b8aSbellard           NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
36931e31b8aSbellard           NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
37031e31b8aSbellard           NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
37131e31b8aSbellard           NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
37231e31b8aSbellard           NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
37331e31b8aSbellard           NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
37431e31b8aSbellard           NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
37531e31b8aSbellard           NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
37631e31b8aSbellard           NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
37731e31b8aSbellard           NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
37831e31b8aSbellard         }
37931e31b8aSbellard         NEW_AUX_ENT (AT_NULL, 0);
38031e31b8aSbellard #undef NEW_AUX_ENT
381b17780d5Sbellard         put_user(tswapl(argc),--sp);
38231e31b8aSbellard         info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
38331e31b8aSbellard         while (argc-->0) {
384b17780d5Sbellard                 put_user(tswapl((target_ulong)p),argv++);
38531e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
38631e31b8aSbellard         }
38731e31b8aSbellard         put_user(0,argv);
38831e31b8aSbellard         info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
38931e31b8aSbellard         while (envc-->0) {
390b17780d5Sbellard                 put_user(tswapl((target_ulong)p),envp++);
39131e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
39231e31b8aSbellard         }
39331e31b8aSbellard         put_user(0,envp);
39431e31b8aSbellard         info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
39531e31b8aSbellard         return sp;
39631e31b8aSbellard }
39731e31b8aSbellard 
39831e31b8aSbellard 
39931e31b8aSbellard 
40031e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
40131e31b8aSbellard 				     int interpreter_fd,
40231e31b8aSbellard 				     unsigned long *interp_load_addr)
40331e31b8aSbellard {
40431e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
40531e31b8aSbellard 	struct elf_phdr *eppnt;
40631e31b8aSbellard 	unsigned long load_addr;
40731e31b8aSbellard 	int load_addr_set = 0;
40831e31b8aSbellard 	int retval;
40931e31b8aSbellard 	unsigned long last_bss, elf_bss;
41031e31b8aSbellard 	unsigned long error;
41131e31b8aSbellard 	int i;
41231e31b8aSbellard 
41331e31b8aSbellard 	elf_bss = 0;
41431e31b8aSbellard 	last_bss = 0;
41531e31b8aSbellard 	error = 0;
41631e31b8aSbellard 
41731e31b8aSbellard 	/* We put this here so that mmap will search for the *first*
41831e31b8aSbellard 	 * available memory...
41931e31b8aSbellard 	 */
42031e31b8aSbellard 	load_addr = INTERP_LOADADDR;
42131e31b8aSbellard 
42231e31b8aSbellard 	/* First of all, some simple consistency checks */
42331e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
42431e31b8aSbellard 	    interp_elf_ex->e_type != ET_DYN) ||
42531e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
42631e31b8aSbellard 		return ~0UL;
42731e31b8aSbellard 	}
42831e31b8aSbellard 
42931e31b8aSbellard 	/* Now read in all of the header information */
43031e31b8aSbellard 
43131e31b8aSbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
43231e31b8aSbellard 	    return ~0UL;
43331e31b8aSbellard 
43431e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
43531e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
43631e31b8aSbellard 
43731e31b8aSbellard 	if (!elf_phdata)
43831e31b8aSbellard 	  return ~0UL;
43931e31b8aSbellard 
44031e31b8aSbellard 	/*
44131e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
44231e31b8aSbellard 	 * we will be doing the wrong thing.
44331e31b8aSbellard 	 */
44431e31b8aSbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
44531e31b8aSbellard 	  {
44631e31b8aSbellard 	    free(elf_phdata);
44731e31b8aSbellard 	    return ~0UL;
44831e31b8aSbellard 	  }
44931e31b8aSbellard 
45031e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
45131e31b8aSbellard 	if(retval >= 0) {
45231e31b8aSbellard 	    retval = read(interpreter_fd,
45331e31b8aSbellard 			   (char *) elf_phdata,
45431e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
45531e31b8aSbellard 	}
45631e31b8aSbellard 
45731e31b8aSbellard 	if (retval < 0) {
45831e31b8aSbellard 		perror("load_elf_interp");
45931e31b8aSbellard 		exit(-1);
46031e31b8aSbellard 		free (elf_phdata);
46131e31b8aSbellard 		return retval;
46231e31b8aSbellard  	}
46331e31b8aSbellard #ifdef BSWAP_NEEDED
46431e31b8aSbellard 	eppnt = elf_phdata;
46531e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
46631e31b8aSbellard             bswap_phdr(eppnt);
46731e31b8aSbellard         }
46831e31b8aSbellard #endif
46931e31b8aSbellard 	eppnt = elf_phdata;
47031e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
47131e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
47231e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
47331e31b8aSbellard 	    int elf_prot = 0;
47431e31b8aSbellard 	    unsigned long vaddr = 0;
47531e31b8aSbellard 	    unsigned long k;
47631e31b8aSbellard 
47731e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
47831e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
47931e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
48031e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
48131e31b8aSbellard 	    	elf_type |= MAP_FIXED;
48231e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
48331e31b8aSbellard 	    }
48431e31b8aSbellard 	    error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
48531e31b8aSbellard 		 eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
48631e31b8aSbellard 		 elf_prot,
48731e31b8aSbellard 		 elf_type,
48831e31b8aSbellard 		 interpreter_fd,
48931e31b8aSbellard 		 eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
49031e31b8aSbellard 
49131e31b8aSbellard 	    if (error > -1024UL) {
49231e31b8aSbellard 	      /* Real error */
49331e31b8aSbellard 	      close(interpreter_fd);
49431e31b8aSbellard 	      free(elf_phdata);
49531e31b8aSbellard 	      return ~0UL;
49631e31b8aSbellard 	    }
49731e31b8aSbellard 
49831e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
49931e31b8aSbellard 	      load_addr = error;
50031e31b8aSbellard 	      load_addr_set = 1;
50131e31b8aSbellard 	    }
50231e31b8aSbellard 
50331e31b8aSbellard 	    /*
50431e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
50531e31b8aSbellard 	     * track of the largest address we see for this.
50631e31b8aSbellard 	     */
50731e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
50831e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
50931e31b8aSbellard 
51031e31b8aSbellard 	    /*
51131e31b8aSbellard 	     * Do the same thing for the memory mapping - between
51231e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
51331e31b8aSbellard 	     */
51431e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
51531e31b8aSbellard 	    if (k > last_bss) last_bss = k;
51631e31b8aSbellard 	  }
51731e31b8aSbellard 
51831e31b8aSbellard 	/* Now use mmap to map the library into memory. */
51931e31b8aSbellard 
52031e31b8aSbellard 	close(interpreter_fd);
52131e31b8aSbellard 
52231e31b8aSbellard 	/*
52331e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
52431e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
52531e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
52631e31b8aSbellard 	 * bss page.
52731e31b8aSbellard 	 */
52831e31b8aSbellard 	padzero(elf_bss);
52931e31b8aSbellard 	elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
53031e31b8aSbellard 
53131e31b8aSbellard 	/* Map the last of the bss segment */
53231e31b8aSbellard 	if (last_bss > elf_bss) {
53331e31b8aSbellard 	  mmap4k(elf_bss, last_bss-elf_bss,
53431e31b8aSbellard 		  PROT_READ|PROT_WRITE|PROT_EXEC,
53531e31b8aSbellard 		  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
53631e31b8aSbellard 	}
53731e31b8aSbellard 	free(elf_phdata);
53831e31b8aSbellard 
53931e31b8aSbellard 	*interp_load_addr = load_addr;
54031e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
54131e31b8aSbellard }
54231e31b8aSbellard 
54331e31b8aSbellard 
54431e31b8aSbellard 
545b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
54631e31b8aSbellard                            struct image_info * info)
54731e31b8aSbellard {
54831e31b8aSbellard     struct elfhdr elf_ex;
54931e31b8aSbellard     struct elfhdr interp_elf_ex;
55031e31b8aSbellard     struct exec interp_ex;
55131e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
55231e31b8aSbellard     unsigned long load_addr;
55331e31b8aSbellard     int load_addr_set = 0;
55431e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
55531e31b8aSbellard     unsigned char ibcs2_interpreter;
55631e31b8aSbellard     int i;
55731e31b8aSbellard     void * mapped_addr;
55831e31b8aSbellard     struct elf_phdr * elf_ppnt;
55931e31b8aSbellard     struct elf_phdr *elf_phdata;
56031e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
56131e31b8aSbellard     int retval;
56231e31b8aSbellard     char * elf_interpreter;
56331e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
56431e31b8aSbellard     int status;
56531e31b8aSbellard     unsigned long start_code, end_code, end_data;
56631e31b8aSbellard     unsigned long elf_stack;
56731e31b8aSbellard     char passed_fileno[6];
56831e31b8aSbellard 
56931e31b8aSbellard     ibcs2_interpreter = 0;
57031e31b8aSbellard     status = 0;
57131e31b8aSbellard     load_addr = 0;
57231e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
57331e31b8aSbellard #ifdef BSWAP_NEEDED
57431e31b8aSbellard     bswap_ehdr(&elf_ex);
57531e31b8aSbellard #endif
57631e31b8aSbellard 
57731e31b8aSbellard     if (elf_ex.e_ident[0] != 0x7f ||
57831e31b8aSbellard 	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
57931e31b8aSbellard 	    return  -ENOEXEC;
58031e31b8aSbellard     }
58131e31b8aSbellard 
58231e31b8aSbellard     /* First of all, some simple consistency checks */
58331e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
58431e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
58531e31b8aSbellard 	    return -ENOEXEC;
58631e31b8aSbellard     }
58731e31b8aSbellard 
58831e31b8aSbellard     /* Now read in all of the header information */
58931e31b8aSbellard 
59031e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
59131e31b8aSbellard     if (elf_phdata == NULL) {
59231e31b8aSbellard 	return -ENOMEM;
59331e31b8aSbellard     }
59431e31b8aSbellard 
59531e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
59631e31b8aSbellard     if(retval > 0) {
59731e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
59831e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
59931e31b8aSbellard     }
60031e31b8aSbellard 
60131e31b8aSbellard     if (retval < 0) {
60231e31b8aSbellard 	perror("load_elf_binary");
60331e31b8aSbellard 	exit(-1);
60431e31b8aSbellard 	free (elf_phdata);
60531e31b8aSbellard 	return -errno;
60631e31b8aSbellard     }
60731e31b8aSbellard 
608b17780d5Sbellard #ifdef BSWAP_NEEDED
609b17780d5Sbellard     elf_ppnt = elf_phdata;
610b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
611b17780d5Sbellard         bswap_phdr(elf_ppnt);
612b17780d5Sbellard     }
613b17780d5Sbellard #endif
61431e31b8aSbellard     elf_ppnt = elf_phdata;
61531e31b8aSbellard 
61631e31b8aSbellard     elf_bss = 0;
61731e31b8aSbellard     elf_brk = 0;
61831e31b8aSbellard 
61931e31b8aSbellard 
62031e31b8aSbellard     elf_stack = ~0UL;
62131e31b8aSbellard     elf_interpreter = NULL;
62231e31b8aSbellard     start_code = ~0UL;
62331e31b8aSbellard     end_code = 0;
62431e31b8aSbellard     end_data = 0;
62531e31b8aSbellard 
62631e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
62731e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
62831e31b8aSbellard 	    if ( elf_interpreter != NULL )
62931e31b8aSbellard 	    {
63031e31b8aSbellard 		free (elf_phdata);
63131e31b8aSbellard 		free(elf_interpreter);
63231e31b8aSbellard 		close(bprm->fd);
63331e31b8aSbellard 		return -EINVAL;
63431e31b8aSbellard 	    }
63531e31b8aSbellard 
63631e31b8aSbellard 	    /* This is the program interpreter used for
63731e31b8aSbellard 	     * shared libraries - for now assume that this
63831e31b8aSbellard 	     * is an a.out format binary
63931e31b8aSbellard 	     */
64031e31b8aSbellard 
64131e31b8aSbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+strlen(X86_DEFAULT_LIB_DIR));
64231e31b8aSbellard 
64331e31b8aSbellard 	    if (elf_interpreter == NULL) {
64431e31b8aSbellard 		free (elf_phdata);
64531e31b8aSbellard 		close(bprm->fd);
64631e31b8aSbellard 		return -ENOMEM;
64731e31b8aSbellard 	    }
64831e31b8aSbellard 
64931e31b8aSbellard 	    strcpy(elf_interpreter, X86_DEFAULT_LIB_DIR);
65031e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
65131e31b8aSbellard 	    if(retval >= 0) {
65231e31b8aSbellard 		retval = read(bprm->fd,
65331e31b8aSbellard 			      elf_interpreter+strlen(X86_DEFAULT_LIB_DIR),
65431e31b8aSbellard 			      elf_ppnt->p_filesz);
65531e31b8aSbellard 	    }
65631e31b8aSbellard 	    if(retval < 0) {
65731e31b8aSbellard 	 	perror("load_elf_binary2");
65831e31b8aSbellard 		exit(-1);
65931e31b8aSbellard 	    }
66031e31b8aSbellard 
66131e31b8aSbellard 	    /* If the program interpreter is one of these two,
66231e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
66331e31b8aSbellard 	       a native linux image. */
66431e31b8aSbellard 
66531e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
66631e31b8aSbellard 
66731e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
66831e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
66931e31b8aSbellard 	      ibcs2_interpreter = 1;
67031e31b8aSbellard 	    }
67131e31b8aSbellard 
67231e31b8aSbellard #if 0
67331e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
67431e31b8aSbellard #endif
67531e31b8aSbellard 	    if (retval >= 0) {
67631e31b8aSbellard 		retval = open(elf_interpreter, O_RDONLY);
67731e31b8aSbellard 		if(retval >= 0) {
67831e31b8aSbellard 		    interpreter_fd = retval;
67931e31b8aSbellard 		}
68031e31b8aSbellard 		else {
68131e31b8aSbellard 		    perror(elf_interpreter);
68231e31b8aSbellard 		    exit(-1);
68331e31b8aSbellard 		    /* retval = -errno; */
68431e31b8aSbellard 		}
68531e31b8aSbellard 	    }
68631e31b8aSbellard 
68731e31b8aSbellard 	    if (retval >= 0) {
68831e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
68931e31b8aSbellard 		if(retval >= 0) {
69031e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
69131e31b8aSbellard 		}
69231e31b8aSbellard 	    }
69331e31b8aSbellard 	    if (retval >= 0) {
69431e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
69531e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
69631e31b8aSbellard 	    }
69731e31b8aSbellard 	    if (retval < 0) {
69831e31b8aSbellard 		perror("load_elf_binary3");
69931e31b8aSbellard 		exit(-1);
70031e31b8aSbellard 		free (elf_phdata);
70131e31b8aSbellard 		free(elf_interpreter);
70231e31b8aSbellard 		close(bprm->fd);
70331e31b8aSbellard 		return retval;
70431e31b8aSbellard 	    }
70531e31b8aSbellard 	}
70631e31b8aSbellard 	elf_ppnt++;
70731e31b8aSbellard     }
70831e31b8aSbellard 
70931e31b8aSbellard     /* Some simple consistency checks for the interpreter */
71031e31b8aSbellard     if (elf_interpreter){
71131e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
71231e31b8aSbellard 
71331e31b8aSbellard 	/* Now figure out which format our binary is */
71431e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
71531e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
71631e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
71731e31b8aSbellard 	}
71831e31b8aSbellard 
71931e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
72031e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
72131e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
72231e31b8aSbellard 	}
72331e31b8aSbellard 
72431e31b8aSbellard 	if (!interpreter_type) {
72531e31b8aSbellard 	    free(elf_interpreter);
72631e31b8aSbellard 	    free(elf_phdata);
72731e31b8aSbellard 	    close(bprm->fd);
72831e31b8aSbellard 	    return -ELIBBAD;
72931e31b8aSbellard 	}
73031e31b8aSbellard     }
73131e31b8aSbellard 
73231e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
73331e31b8aSbellard        and then start this sucker up */
73431e31b8aSbellard 
73531e31b8aSbellard     if (!bprm->sh_bang) {
73631e31b8aSbellard 	char * passed_p;
73731e31b8aSbellard 
73831e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
73931e31b8aSbellard 	    sprintf(passed_fileno, "%d", bprm->fd);
74031e31b8aSbellard 	    passed_p = passed_fileno;
74131e31b8aSbellard 
74231e31b8aSbellard 	    if (elf_interpreter) {
74331e31b8aSbellard 		bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
74431e31b8aSbellard 		bprm->argc++;
74531e31b8aSbellard 	    }
74631e31b8aSbellard 	}
74731e31b8aSbellard 	if (!bprm->p) {
74831e31b8aSbellard 	    if (elf_interpreter) {
74931e31b8aSbellard 	        free(elf_interpreter);
75031e31b8aSbellard 	    }
75131e31b8aSbellard 	    free (elf_phdata);
75231e31b8aSbellard 	    close(bprm->fd);
75331e31b8aSbellard 	    return -E2BIG;
75431e31b8aSbellard 	}
75531e31b8aSbellard     }
75631e31b8aSbellard 
75731e31b8aSbellard     /* OK, This is the point of no return */
75831e31b8aSbellard     info->end_data = 0;
75931e31b8aSbellard     info->end_code = 0;
76031e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
76131e31b8aSbellard     info->mmap = 0;
76231e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
76331e31b8aSbellard 
76431e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
76531e31b8aSbellard        change some of these later */
76631e31b8aSbellard     info->rss = 0;
76731e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
76831e31b8aSbellard     info->start_stack = bprm->p;
76931e31b8aSbellard 
77031e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
77131e31b8aSbellard      * the correct location in memory.  At this point, we assume that
77231e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
77331e31b8aSbellard      * address.
77431e31b8aSbellard      */
77531e31b8aSbellard 
77631e31b8aSbellard 
77731e31b8aSbellard 
77831e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
77931e31b8aSbellard 	if (elf_ppnt->p_type == PT_LOAD) {
78031e31b8aSbellard 	    int elf_prot = 0;
78131e31b8aSbellard 	    if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
78231e31b8aSbellard 	    if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
78331e31b8aSbellard 	    if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
78431e31b8aSbellard 
78531e31b8aSbellard 	    mapped_addr = mmap4k(X86_ELF_PAGESTART(elf_ppnt->p_vaddr),
78631e31b8aSbellard 		    (elf_ppnt->p_filesz +
78731e31b8aSbellard 			    X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
78831e31b8aSbellard 		    elf_prot,
78931e31b8aSbellard 		    (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
79031e31b8aSbellard 		    bprm->fd,
79131e31b8aSbellard 		    (elf_ppnt->p_offset -
79231e31b8aSbellard 			    X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
79331e31b8aSbellard 
79431e31b8aSbellard 	    if((unsigned long)mapped_addr == 0xffffffffffffffff) {
79531e31b8aSbellard 		perror("mmap");
79631e31b8aSbellard 		exit(-1);
79731e31b8aSbellard 	    }
79831e31b8aSbellard 
79931e31b8aSbellard 
80031e31b8aSbellard 
80131e31b8aSbellard #ifdef LOW_ELF_STACK
80231e31b8aSbellard 	    if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
80331e31b8aSbellard 		    elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
80431e31b8aSbellard #endif
80531e31b8aSbellard 
80631e31b8aSbellard 	    if (!load_addr_set) {
80731e31b8aSbellard 	        load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
80831e31b8aSbellard 	        load_addr_set = 1;
80931e31b8aSbellard 	    }
81031e31b8aSbellard 	    k = elf_ppnt->p_vaddr;
81131e31b8aSbellard 	    if (k < start_code) start_code = k;
81231e31b8aSbellard 	    k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
81331e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
81431e31b8aSbellard #if 1
81531e31b8aSbellard 	    if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
81631e31b8aSbellard #else
81731e31b8aSbellard 	    if ( !(elf_ppnt->p_flags & PF_W) && end_code <  k)
81831e31b8aSbellard #endif
81931e31b8aSbellard 		    end_code = k;
82031e31b8aSbellard 	    if (end_data < k) end_data = k;
82131e31b8aSbellard 	    k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
82231e31b8aSbellard 	    if (k > elf_brk) elf_brk = k;
82331e31b8aSbellard 	}
82431e31b8aSbellard     }
82531e31b8aSbellard 
82631e31b8aSbellard     if (elf_interpreter) {
82731e31b8aSbellard 	if (interpreter_type & 1) {
82831e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
82931e31b8aSbellard 	}
83031e31b8aSbellard 	else if (interpreter_type & 2) {
83131e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
83231e31b8aSbellard 					    &interp_load_addr);
83331e31b8aSbellard 	}
83431e31b8aSbellard 
83531e31b8aSbellard 	close(interpreter_fd);
83631e31b8aSbellard 	free(elf_interpreter);
83731e31b8aSbellard 
83831e31b8aSbellard 	if (elf_entry == ~0UL) {
83931e31b8aSbellard 	    printf("Unable to load interpreter\n");
84031e31b8aSbellard 	    free(elf_phdata);
84131e31b8aSbellard 	    exit(-1);
84231e31b8aSbellard 	    return 0;
84331e31b8aSbellard 	}
84431e31b8aSbellard     }
84531e31b8aSbellard 
84631e31b8aSbellard     free(elf_phdata);
84731e31b8aSbellard 
84831e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
84931e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
85031e31b8aSbellard 
85131e31b8aSbellard #ifdef LOW_ELF_STACK
85231e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
85331e31b8aSbellard #endif
85431e31b8aSbellard     bprm->p = (unsigned long)
85531e31b8aSbellard       create_elf_tables((char *)bprm->p,
85631e31b8aSbellard 		    bprm->argc,
85731e31b8aSbellard 		    bprm->envc,
85831e31b8aSbellard 		    (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
85931e31b8aSbellard 		    load_addr,
86031e31b8aSbellard 		    interp_load_addr,
86131e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
86231e31b8aSbellard 		    info);
86331e31b8aSbellard     if (interpreter_type == INTERPRETER_AOUT)
86431e31b8aSbellard       info->arg_start += strlen(passed_fileno) + 1;
86531e31b8aSbellard     info->start_brk = info->brk = elf_brk;
86631e31b8aSbellard     info->end_code = end_code;
86731e31b8aSbellard     info->start_code = start_code;
86831e31b8aSbellard     info->end_data = end_data;
86931e31b8aSbellard     info->start_stack = bprm->p;
87031e31b8aSbellard 
87131e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
87231e31b8aSbellard        sections */
87331e31b8aSbellard     set_brk(elf_bss, elf_brk);
87431e31b8aSbellard 
87531e31b8aSbellard     padzero(elf_bss);
87631e31b8aSbellard 
87731e31b8aSbellard #if 0
87831e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
87931e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
88031e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
88131e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
88231e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
88331e31b8aSbellard     printf("(brk) %x\n" , info->brk);
88431e31b8aSbellard #endif
88531e31b8aSbellard 
88631e31b8aSbellard     if ( info->personality == PER_SVR4 )
88731e31b8aSbellard     {
88831e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
88931e31b8aSbellard 	       and some applications "depend" upon this behavior.
89031e31b8aSbellard 	       Since we do not have the power to recompile these, we
89131e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
89231e31b8aSbellard 	    mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC,
89331e31b8aSbellard 			    MAP_FIXED | MAP_PRIVATE, -1, 0);
89431e31b8aSbellard     }
89531e31b8aSbellard 
89631e31b8aSbellard #ifdef ELF_PLAT_INIT
89731e31b8aSbellard     /*
89831e31b8aSbellard      * The ABI may specify that certain registers be set up in special
89931e31b8aSbellard      * ways (on i386 %edx is the address of a DT_FINI function, for
90031e31b8aSbellard      * example.  This macro performs whatever initialization to
90131e31b8aSbellard      * the regs structure is required.
90231e31b8aSbellard      */
90331e31b8aSbellard     ELF_PLAT_INIT(regs);
90431e31b8aSbellard #endif
90531e31b8aSbellard 
90631e31b8aSbellard 
90731e31b8aSbellard     info->entry = elf_entry;
90831e31b8aSbellard 
90931e31b8aSbellard     return 0;
91031e31b8aSbellard }
91131e31b8aSbellard 
91231e31b8aSbellard 
91331e31b8aSbellard 
91431e31b8aSbellard int elf_exec(const char * filename, char ** argv, char ** envp,
915b17780d5Sbellard              struct target_pt_regs * regs, struct image_info *infop)
91631e31b8aSbellard {
91731e31b8aSbellard         struct linux_binprm bprm;
91831e31b8aSbellard         int retval;
91931e31b8aSbellard         int i;
92031e31b8aSbellard 
92131e31b8aSbellard         bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
92231e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
92331e31b8aSbellard                 bprm.page[i] = 0;
92431e31b8aSbellard         retval = open(filename, O_RDONLY);
92531e31b8aSbellard         if (retval == -1) {
92631e31b8aSbellard 	    perror(filename);
92731e31b8aSbellard 	    exit(-1);
92831e31b8aSbellard             /* return retval; */
92931e31b8aSbellard 	}
93031e31b8aSbellard 	else {
93131e31b8aSbellard 	    bprm.fd = retval;
93231e31b8aSbellard 	}
93331e31b8aSbellard         bprm.filename = (char *)filename;
93431e31b8aSbellard         bprm.sh_bang = 0;
93531e31b8aSbellard         bprm.loader = 0;
93631e31b8aSbellard         bprm.exec = 0;
93731e31b8aSbellard         bprm.dont_iput = 0;
93831e31b8aSbellard 	bprm.argc = count(argv);
93931e31b8aSbellard 	bprm.envc = count(envp);
94031e31b8aSbellard 
94131e31b8aSbellard         retval = prepare_binprm(&bprm);
94231e31b8aSbellard 
94331e31b8aSbellard         if(retval>=0) {
94431e31b8aSbellard 	    bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
94531e31b8aSbellard 	    bprm.exec = bprm.p;
94631e31b8aSbellard 	    bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
94731e31b8aSbellard 	    bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
94831e31b8aSbellard 	    if (!bprm.p) {
94931e31b8aSbellard 		retval = -E2BIG;
95031e31b8aSbellard 	    }
95131e31b8aSbellard         }
95231e31b8aSbellard 
95331e31b8aSbellard         if(retval>=0) {
95431e31b8aSbellard 	    retval = load_elf_binary(&bprm,regs,infop);
95531e31b8aSbellard 	}
95631e31b8aSbellard         if(retval>=0) {
95731e31b8aSbellard 	    /* success.  Initialize important registers */
95831e31b8aSbellard 	    regs->esp = infop->start_stack;
95931e31b8aSbellard 	    regs->eip = infop->entry;
96031e31b8aSbellard 	    return retval;
96131e31b8aSbellard 	}
96231e31b8aSbellard 
96331e31b8aSbellard         /* Something went wrong, return the inode and free the argument pages*/
96431e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++) {
96531e31b8aSbellard 	    free_page((void *)bprm.page[i]);
96631e31b8aSbellard 	}
96731e31b8aSbellard         return(retval);
96831e31b8aSbellard }
96931e31b8aSbellard 
97031e31b8aSbellard 
97131e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
97231e31b8aSbellard {
97331e31b8aSbellard     printf("a.out interpreter not yet supported\n");
97431e31b8aSbellard     return(0);
97531e31b8aSbellard }
97631e31b8aSbellard 
977