xref: /qemu/linux-user/elfload.c (revision 644c433cb3759599aa1440b412964f8e49cc0b71)
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 
133ef693a0Sbellard #include "qemu.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... */
45d691f669Sbellard 
4631e31b8aSbellard 
4731e31b8aSbellard //extern void * mmap4k();
4831e31b8aSbellard #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
4931e31b8aSbellard 
5031e31b8aSbellard extern unsigned long x86_stack_size;
5131e31b8aSbellard 
5231e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
5331e31b8aSbellard 
5431e31b8aSbellard #ifdef BSWAP_NEEDED
5531e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr)
5631e31b8aSbellard {
5731e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
5831e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
5931e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
6031e31b8aSbellard     bswap32s(&ehdr->e_entry);		/* Entry point virtual address */
6131e31b8aSbellard     bswap32s(&ehdr->e_phoff);		/* Program header table file offset */
6231e31b8aSbellard     bswap32s(&ehdr->e_shoff);		/* Section header table file offset */
6331e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
6431e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
6531e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
6631e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
6731e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
6831e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
6931e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
7031e31b8aSbellard }
7131e31b8aSbellard 
7231e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr)
7331e31b8aSbellard {
7431e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
7531e31b8aSbellard     bswap32s(&phdr->p_offset);		/* Segment file offset */
7631e31b8aSbellard     bswap32s(&phdr->p_vaddr);		/* Segment virtual address */
7731e31b8aSbellard     bswap32s(&phdr->p_paddr);		/* Segment physical address */
7831e31b8aSbellard     bswap32s(&phdr->p_filesz);		/* Segment size in file */
7931e31b8aSbellard     bswap32s(&phdr->p_memsz);		/* Segment size in memory */
8031e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
8131e31b8aSbellard     bswap32s(&phdr->p_align);		/* Segment alignment */
8231e31b8aSbellard }
8331e31b8aSbellard #endif
8431e31b8aSbellard 
8531e31b8aSbellard static void * get_free_page(void)
8631e31b8aSbellard {
8731e31b8aSbellard     void *	retval;
8831e31b8aSbellard 
8931e31b8aSbellard     /* User-space version of kernel get_free_page.  Returns a page-aligned
9031e31b8aSbellard      * page-sized chunk of memory.
9131e31b8aSbellard      */
9231e31b8aSbellard     retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
9331e31b8aSbellard 			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
9431e31b8aSbellard 
9531e31b8aSbellard     if((long)retval == -1) {
9631e31b8aSbellard 	perror("get_free_page");
9731e31b8aSbellard 	exit(-1);
9831e31b8aSbellard     }
9931e31b8aSbellard     else {
10031e31b8aSbellard 	return(retval);
10131e31b8aSbellard     }
10231e31b8aSbellard }
10331e31b8aSbellard 
10431e31b8aSbellard static void free_page(void * pageaddr)
10531e31b8aSbellard {
10631e31b8aSbellard     (void)munmap(pageaddr, ALPHA_PAGE_SIZE);
10731e31b8aSbellard }
10831e31b8aSbellard 
10931e31b8aSbellard /*
11031e31b8aSbellard  * 'copy_string()' copies argument/envelope strings from user
11131e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
11231e31b8aSbellard  * to be put directly into the top of new user memory.
11331e31b8aSbellard  *
11431e31b8aSbellard  */
11531e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
11631e31b8aSbellard                 unsigned long p)
11731e31b8aSbellard {
11831e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
11931e31b8aSbellard     int len, offset = 0;
12031e31b8aSbellard 
12131e31b8aSbellard     if (!p) {
12231e31b8aSbellard 	return 0;       /* bullet-proofing */
12331e31b8aSbellard     }
12431e31b8aSbellard     while (argc-- > 0) {
12531e31b8aSbellard 	if (!(tmp1 = tmp = get_user(argv+argc))) {
12631e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
12731e31b8aSbellard 	    exit(-1);
12831e31b8aSbellard 	}
12931e31b8aSbellard 	while (get_user(tmp++));
13031e31b8aSbellard 	len = tmp - tmp1;
13131e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
13231e31b8aSbellard 		return 0;
13331e31b8aSbellard 	}
13431e31b8aSbellard 	while (len) {
13531e31b8aSbellard 	    --p; --tmp; --len;
13631e31b8aSbellard 	    if (--offset < 0) {
13731e31b8aSbellard 		offset = p % X86_PAGE_SIZE;
13831e31b8aSbellard 		if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
13931e31b8aSbellard 		    !(pag = (char *) page[p/X86_PAGE_SIZE] =
14031e31b8aSbellard 		      (unsigned long *) get_free_page())) {
14131e31b8aSbellard 			return 0;
14231e31b8aSbellard 		}
14331e31b8aSbellard 	    }
14431e31b8aSbellard 	    if (len == 0 || offset == 0) {
14531e31b8aSbellard 	        *(pag + offset) = get_user(tmp);
14631e31b8aSbellard 	    }
14731e31b8aSbellard 	    else {
14831e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
14931e31b8aSbellard 	      tmp -= bytes_to_copy;
15031e31b8aSbellard 	      p -= bytes_to_copy;
15131e31b8aSbellard 	      offset -= bytes_to_copy;
15231e31b8aSbellard 	      len -= bytes_to_copy;
15331e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
15431e31b8aSbellard 	    }
15531e31b8aSbellard 	}
15631e31b8aSbellard     }
15731e31b8aSbellard     return p;
15831e31b8aSbellard }
15931e31b8aSbellard 
16031e31b8aSbellard static int in_group_p(gid_t g)
16131e31b8aSbellard {
16231e31b8aSbellard     /* return TRUE if we're in the specified group, FALSE otherwise */
16331e31b8aSbellard     int		ngroup;
16431e31b8aSbellard     int		i;
16531e31b8aSbellard     gid_t	grouplist[NGROUPS];
16631e31b8aSbellard 
16731e31b8aSbellard     ngroup = getgroups(NGROUPS, grouplist);
16831e31b8aSbellard     for(i = 0; i < ngroup; i++) {
16931e31b8aSbellard 	if(grouplist[i] == g) {
17031e31b8aSbellard 	    return 1;
17131e31b8aSbellard 	}
17231e31b8aSbellard     }
17331e31b8aSbellard     return 0;
17431e31b8aSbellard }
17531e31b8aSbellard 
17631e31b8aSbellard static int count(char ** vec)
17731e31b8aSbellard {
17831e31b8aSbellard     int		i;
17931e31b8aSbellard 
18031e31b8aSbellard     for(i = 0; *vec; i++) {
18131e31b8aSbellard         vec++;
18231e31b8aSbellard     }
18331e31b8aSbellard 
18431e31b8aSbellard     return(i);
18531e31b8aSbellard }
18631e31b8aSbellard 
18731e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm)
18831e31b8aSbellard {
18931e31b8aSbellard     struct stat		st;
19031e31b8aSbellard     int mode;
19131e31b8aSbellard     int retval, id_change;
19231e31b8aSbellard 
19331e31b8aSbellard     if(fstat(bprm->fd, &st) < 0) {
19431e31b8aSbellard 	return(-errno);
19531e31b8aSbellard     }
19631e31b8aSbellard 
19731e31b8aSbellard     mode = st.st_mode;
19831e31b8aSbellard     if(!S_ISREG(mode)) {	/* Must be regular file */
19931e31b8aSbellard 	return(-EACCES);
20031e31b8aSbellard     }
20131e31b8aSbellard     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
20231e31b8aSbellard 	return(-EACCES);
20331e31b8aSbellard     }
20431e31b8aSbellard 
20531e31b8aSbellard     bprm->e_uid = geteuid();
20631e31b8aSbellard     bprm->e_gid = getegid();
20731e31b8aSbellard     id_change = 0;
20831e31b8aSbellard 
20931e31b8aSbellard     /* Set-uid? */
21031e31b8aSbellard     if(mode & S_ISUID) {
21131e31b8aSbellard     	bprm->e_uid = st.st_uid;
21231e31b8aSbellard 	if(bprm->e_uid != geteuid()) {
21331e31b8aSbellard 	    id_change = 1;
21431e31b8aSbellard 	}
21531e31b8aSbellard     }
21631e31b8aSbellard 
21731e31b8aSbellard     /* Set-gid? */
21831e31b8aSbellard     /*
21931e31b8aSbellard      * If setgid is set but no group execute bit then this
22031e31b8aSbellard      * is a candidate for mandatory locking, not a setgid
22131e31b8aSbellard      * executable.
22231e31b8aSbellard      */
22331e31b8aSbellard     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
22431e31b8aSbellard 	bprm->e_gid = st.st_gid;
22531e31b8aSbellard 	if (!in_group_p(bprm->e_gid)) {
22631e31b8aSbellard 		id_change = 1;
22731e31b8aSbellard 	}
22831e31b8aSbellard     }
22931e31b8aSbellard 
23031e31b8aSbellard     memset(bprm->buf, 0, sizeof(bprm->buf));
23131e31b8aSbellard     retval = lseek(bprm->fd, 0L, SEEK_SET);
23231e31b8aSbellard     if(retval >= 0) {
23331e31b8aSbellard         retval = read(bprm->fd, bprm->buf, 128);
23431e31b8aSbellard     }
23531e31b8aSbellard     if(retval < 0) {
23631e31b8aSbellard 	perror("prepare_binprm");
23731e31b8aSbellard 	exit(-1);
23831e31b8aSbellard 	/* return(-errno); */
23931e31b8aSbellard     }
24031e31b8aSbellard     else {
24131e31b8aSbellard 	return(retval);
24231e31b8aSbellard     }
24331e31b8aSbellard }
24431e31b8aSbellard 
24531e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
24631e31b8aSbellard 						struct image_info * info)
24731e31b8aSbellard {
24831e31b8aSbellard     unsigned long stack_base;
24931e31b8aSbellard     int i;
25031e31b8aSbellard     extern unsigned long stktop;
25131e31b8aSbellard 
25231e31b8aSbellard     stack_base = X86_STACK_TOP - MAX_ARG_PAGES*X86_PAGE_SIZE;
25331e31b8aSbellard 
25431e31b8aSbellard     p += stack_base;
25531e31b8aSbellard     if (bprm->loader) {
25631e31b8aSbellard 	bprm->loader += stack_base;
25731e31b8aSbellard     }
25831e31b8aSbellard     bprm->exec += stack_base;
25931e31b8aSbellard 
26031e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
26131e31b8aSbellard      * it for args, we'll use it for something else...
26231e31b8aSbellard      */
2639de5e440Sbellard     /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
2649de5e440Sbellard        we allocate a bigger stack. Need a better solution, for example
2659de5e440Sbellard        by remapping the process stack directly at the right place */
26631e31b8aSbellard     if(x86_stack_size >  MAX_ARG_PAGES*X86_PAGE_SIZE) {
26731e31b8aSbellard         if((long)mmap4k((void *)(X86_STACK_TOP-x86_stack_size), x86_stack_size + X86_PAGE_SIZE,
26831e31b8aSbellard     		     PROT_READ | PROT_WRITE,
26931e31b8aSbellard 		     MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
27031e31b8aSbellard 	    perror("stk mmap");
27131e31b8aSbellard 	    exit(-1);
27231e31b8aSbellard 	}
27331e31b8aSbellard     }
27431e31b8aSbellard     else {
27531e31b8aSbellard         if((long)mmap4k((void *)stack_base, (MAX_ARG_PAGES+1)*X86_PAGE_SIZE,
27631e31b8aSbellard     		     PROT_READ | PROT_WRITE,
27731e31b8aSbellard 		     MAP_GROWSDOWN | MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
27831e31b8aSbellard 	    perror("stk mmap");
27931e31b8aSbellard 	    exit(-1);
28031e31b8aSbellard 	}
28131e31b8aSbellard     }
28231e31b8aSbellard 
28331e31b8aSbellard     stktop = stack_base;
28431e31b8aSbellard 
28531e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
28631e31b8aSbellard 	if (bprm->page[i]) {
28731e31b8aSbellard 	    info->rss++;
28831e31b8aSbellard 
28931e31b8aSbellard 	    memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
29031e31b8aSbellard 	    free_page((void *)bprm->page[i]);
29131e31b8aSbellard 	}
29231e31b8aSbellard 	stack_base += X86_PAGE_SIZE;
29331e31b8aSbellard     }
29431e31b8aSbellard     return p;
29531e31b8aSbellard }
29631e31b8aSbellard 
29731e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
29831e31b8aSbellard {
29931e31b8aSbellard 	/* page-align the start and end addresses... */
30031e31b8aSbellard         start = ALPHA_PAGE_ALIGN(start);
30131e31b8aSbellard         end = ALPHA_PAGE_ALIGN(end);
30231e31b8aSbellard         if (end <= start)
30331e31b8aSbellard                 return;
30431e31b8aSbellard         if((long)mmap4k(start, end - start,
30531e31b8aSbellard                 PROT_READ | PROT_WRITE | PROT_EXEC,
30631e31b8aSbellard                 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
30731e31b8aSbellard 	    perror("cannot mmap brk");
30831e31b8aSbellard 	    exit(-1);
30931e31b8aSbellard 	}
31031e31b8aSbellard }
31131e31b8aSbellard 
31231e31b8aSbellard 
31331e31b8aSbellard /* We need to explicitly zero any fractional pages
31431e31b8aSbellard    after the data section (i.e. bss).  This would
31531e31b8aSbellard    contain the junk from the file that should not
31631e31b8aSbellard    be in memory */
31731e31b8aSbellard 
31831e31b8aSbellard 
31931e31b8aSbellard static void padzero(unsigned long elf_bss)
32031e31b8aSbellard {
32131e31b8aSbellard         unsigned long nbyte;
32231e31b8aSbellard         char * fpnt;
32331e31b8aSbellard 
32431e31b8aSbellard         nbyte = elf_bss & (ALPHA_PAGE_SIZE-1);	/* was X86_PAGE_SIZE - JRP */
32531e31b8aSbellard         if (nbyte) {
32631e31b8aSbellard 	    nbyte = ALPHA_PAGE_SIZE - nbyte;
32731e31b8aSbellard 	    fpnt = (char *) elf_bss;
32831e31b8aSbellard 	    do {
32931e31b8aSbellard 		*fpnt++ = 0;
33031e31b8aSbellard 	    } while (--nbyte);
33131e31b8aSbellard         }
33231e31b8aSbellard }
33331e31b8aSbellard 
33431e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc,
33531e31b8aSbellard                                   struct elfhdr * exec,
33631e31b8aSbellard                                   unsigned long load_addr,
33731e31b8aSbellard                                   unsigned long interp_load_addr, int ibcs,
33831e31b8aSbellard 				  struct image_info *info)
33931e31b8aSbellard {
340b17780d5Sbellard         target_ulong *argv, *envp, *dlinfo;
341b17780d5Sbellard         target_ulong *sp;
34231e31b8aSbellard 
34331e31b8aSbellard         /*
34431e31b8aSbellard          * Force 16 byte alignment here for generality.
34531e31b8aSbellard          */
34631e31b8aSbellard         sp = (unsigned int *) (~15UL & (unsigned long) p);
34731e31b8aSbellard         sp -= exec ? DLINFO_ITEMS*2 : 2;
34831e31b8aSbellard         dlinfo = sp;
34931e31b8aSbellard         sp -= envc+1;
35031e31b8aSbellard         envp = sp;
35131e31b8aSbellard         sp -= argc+1;
35231e31b8aSbellard         argv = sp;
35331e31b8aSbellard         if (!ibcs) {
354b17780d5Sbellard                 put_user(tswapl((target_ulong)envp),--sp);
355b17780d5Sbellard                 put_user(tswapl((target_ulong)argv),--sp);
35631e31b8aSbellard         }
35731e31b8aSbellard 
35831e31b8aSbellard #define NEW_AUX_ENT(id, val) \
359b17780d5Sbellard           put_user (tswapl(id), dlinfo++); \
360b17780d5Sbellard           put_user (tswapl(val), dlinfo++)
36131e31b8aSbellard 
36231e31b8aSbellard         if (exec) { /* Put this here for an ELF program interpreter */
36331e31b8aSbellard           NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
36431e31b8aSbellard           NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
36531e31b8aSbellard           NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
36631e31b8aSbellard           NEW_AUX_ENT (AT_PAGESZ, (unsigned int)(ALPHA_PAGE_SIZE));
36731e31b8aSbellard           NEW_AUX_ENT (AT_BASE, (unsigned int)(interp_load_addr));
36831e31b8aSbellard           NEW_AUX_ENT (AT_FLAGS, (unsigned int)0);
36931e31b8aSbellard           NEW_AUX_ENT (AT_ENTRY, (unsigned int) exec->e_entry);
37031e31b8aSbellard           NEW_AUX_ENT (AT_UID, (unsigned int) getuid());
37131e31b8aSbellard           NEW_AUX_ENT (AT_EUID, (unsigned int) geteuid());
37231e31b8aSbellard           NEW_AUX_ENT (AT_GID, (unsigned int) getgid());
37331e31b8aSbellard           NEW_AUX_ENT (AT_EGID, (unsigned int) getegid());
37431e31b8aSbellard         }
37531e31b8aSbellard         NEW_AUX_ENT (AT_NULL, 0);
37631e31b8aSbellard #undef NEW_AUX_ENT
377b17780d5Sbellard         put_user(tswapl(argc),--sp);
37831e31b8aSbellard         info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
37931e31b8aSbellard         while (argc-->0) {
380b17780d5Sbellard                 put_user(tswapl((target_ulong)p),argv++);
38131e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
38231e31b8aSbellard         }
38331e31b8aSbellard         put_user(0,argv);
38431e31b8aSbellard         info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
38531e31b8aSbellard         while (envc-->0) {
386b17780d5Sbellard                 put_user(tswapl((target_ulong)p),envp++);
38731e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
38831e31b8aSbellard         }
38931e31b8aSbellard         put_user(0,envp);
39031e31b8aSbellard         info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
39131e31b8aSbellard         return sp;
39231e31b8aSbellard }
39331e31b8aSbellard 
39431e31b8aSbellard 
39531e31b8aSbellard 
39631e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
39731e31b8aSbellard 				     int interpreter_fd,
39831e31b8aSbellard 				     unsigned long *interp_load_addr)
39931e31b8aSbellard {
40031e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
40131e31b8aSbellard 	struct elf_phdr *eppnt;
40231e31b8aSbellard 	unsigned long load_addr;
40331e31b8aSbellard 	int load_addr_set = 0;
40431e31b8aSbellard 	int retval;
40531e31b8aSbellard 	unsigned long last_bss, elf_bss;
40631e31b8aSbellard 	unsigned long error;
40731e31b8aSbellard 	int i;
40831e31b8aSbellard 
40931e31b8aSbellard 	elf_bss = 0;
41031e31b8aSbellard 	last_bss = 0;
41131e31b8aSbellard 	error = 0;
41231e31b8aSbellard 
41331e31b8aSbellard 	/* We put this here so that mmap will search for the *first*
41431e31b8aSbellard 	 * available memory...
41531e31b8aSbellard 	 */
41631e31b8aSbellard 	load_addr = INTERP_LOADADDR;
41731e31b8aSbellard 
418*644c433cSbellard #ifdef BSWAP_NEEDED
419*644c433cSbellard         bswap_ehdr(interp_elf_ex);
420*644c433cSbellard #endif
42131e31b8aSbellard 	/* First of all, some simple consistency checks */
42231e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
42331e31b8aSbellard 	    interp_elf_ex->e_type != ET_DYN) ||
42431e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
42531e31b8aSbellard 		return ~0UL;
42631e31b8aSbellard 	}
42731e31b8aSbellard 
428*644c433cSbellard 
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 	if (retval < 0) {
45731e31b8aSbellard 		perror("load_elf_interp");
45831e31b8aSbellard 		exit(-1);
45931e31b8aSbellard 		free (elf_phdata);
46031e31b8aSbellard 		return retval;
46131e31b8aSbellard  	}
46231e31b8aSbellard #ifdef BSWAP_NEEDED
46331e31b8aSbellard 	eppnt = elf_phdata;
46431e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
46531e31b8aSbellard             bswap_phdr(eppnt);
46631e31b8aSbellard         }
46731e31b8aSbellard #endif
46831e31b8aSbellard 	eppnt = elf_phdata;
46931e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
47031e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
47131e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
47231e31b8aSbellard 	    int elf_prot = 0;
47331e31b8aSbellard 	    unsigned long vaddr = 0;
47431e31b8aSbellard 	    unsigned long k;
47531e31b8aSbellard 
47631e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
47731e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
47831e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
47931e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
48031e31b8aSbellard 	    	elf_type |= MAP_FIXED;
48131e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
48231e31b8aSbellard 	    }
48331e31b8aSbellard 	    error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
48431e31b8aSbellard 		 eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
48531e31b8aSbellard 		 elf_prot,
48631e31b8aSbellard 		 elf_type,
48731e31b8aSbellard 		 interpreter_fd,
48831e31b8aSbellard 		 eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
48931e31b8aSbellard 
49031e31b8aSbellard 	    if (error > -1024UL) {
49131e31b8aSbellard 	      /* Real error */
49231e31b8aSbellard 	      close(interpreter_fd);
49331e31b8aSbellard 	      free(elf_phdata);
49431e31b8aSbellard 	      return ~0UL;
49531e31b8aSbellard 	    }
49631e31b8aSbellard 
49731e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
49831e31b8aSbellard 	      load_addr = error;
49931e31b8aSbellard 	      load_addr_set = 1;
50031e31b8aSbellard 	    }
50131e31b8aSbellard 
50231e31b8aSbellard 	    /*
50331e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
50431e31b8aSbellard 	     * track of the largest address we see for this.
50531e31b8aSbellard 	     */
50631e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
50731e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
50831e31b8aSbellard 
50931e31b8aSbellard 	    /*
51031e31b8aSbellard 	     * Do the same thing for the memory mapping - between
51131e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
51231e31b8aSbellard 	     */
51331e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
51431e31b8aSbellard 	    if (k > last_bss) last_bss = k;
51531e31b8aSbellard 	  }
51631e31b8aSbellard 
51731e31b8aSbellard 	/* Now use mmap to map the library into memory. */
51831e31b8aSbellard 
51931e31b8aSbellard 	close(interpreter_fd);
52031e31b8aSbellard 
52131e31b8aSbellard 	/*
52231e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
52331e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
52431e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
52531e31b8aSbellard 	 * bss page.
52631e31b8aSbellard 	 */
52731e31b8aSbellard 	padzero(elf_bss);
52831e31b8aSbellard 	elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
52931e31b8aSbellard 
53031e31b8aSbellard 	/* Map the last of the bss segment */
53131e31b8aSbellard 	if (last_bss > elf_bss) {
53231e31b8aSbellard 	  mmap4k(elf_bss, last_bss-elf_bss,
53331e31b8aSbellard 		  PROT_READ|PROT_WRITE|PROT_EXEC,
53431e31b8aSbellard 		  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
53531e31b8aSbellard 	}
53631e31b8aSbellard 	free(elf_phdata);
53731e31b8aSbellard 
53831e31b8aSbellard 	*interp_load_addr = load_addr;
53931e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
54031e31b8aSbellard }
54131e31b8aSbellard 
54231e31b8aSbellard 
54331e31b8aSbellard 
544b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
54531e31b8aSbellard                            struct image_info * info)
54631e31b8aSbellard {
54731e31b8aSbellard     struct elfhdr elf_ex;
54831e31b8aSbellard     struct elfhdr interp_elf_ex;
54931e31b8aSbellard     struct exec interp_ex;
55031e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
55131e31b8aSbellard     unsigned long load_addr;
55231e31b8aSbellard     int load_addr_set = 0;
55331e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
55431e31b8aSbellard     unsigned char ibcs2_interpreter;
55531e31b8aSbellard     int i;
55631e31b8aSbellard     void * mapped_addr;
55731e31b8aSbellard     struct elf_phdr * elf_ppnt;
55831e31b8aSbellard     struct elf_phdr *elf_phdata;
55931e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
56031e31b8aSbellard     int retval;
56131e31b8aSbellard     char * elf_interpreter;
56231e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
56331e31b8aSbellard     int status;
56431e31b8aSbellard     unsigned long start_code, end_code, end_data;
56531e31b8aSbellard     unsigned long elf_stack;
56631e31b8aSbellard     char passed_fileno[6];
56731e31b8aSbellard 
56831e31b8aSbellard     ibcs2_interpreter = 0;
56931e31b8aSbellard     status = 0;
57031e31b8aSbellard     load_addr = 0;
57131e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
57231e31b8aSbellard #ifdef BSWAP_NEEDED
57331e31b8aSbellard     bswap_ehdr(&elf_ex);
57431e31b8aSbellard #endif
57531e31b8aSbellard 
57631e31b8aSbellard     if (elf_ex.e_ident[0] != 0x7f ||
57731e31b8aSbellard 	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
57831e31b8aSbellard 	    return  -ENOEXEC;
57931e31b8aSbellard     }
58031e31b8aSbellard 
58131e31b8aSbellard     /* First of all, some simple consistency checks */
58231e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
58331e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
58431e31b8aSbellard 	    return -ENOEXEC;
58531e31b8aSbellard     }
58631e31b8aSbellard 
58731e31b8aSbellard     /* Now read in all of the header information */
58831e31b8aSbellard 
58931e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
59031e31b8aSbellard     if (elf_phdata == NULL) {
59131e31b8aSbellard 	return -ENOMEM;
59231e31b8aSbellard     }
59331e31b8aSbellard 
59431e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
59531e31b8aSbellard     if(retval > 0) {
59631e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
59731e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
59831e31b8aSbellard     }
59931e31b8aSbellard 
60031e31b8aSbellard     if (retval < 0) {
60131e31b8aSbellard 	perror("load_elf_binary");
60231e31b8aSbellard 	exit(-1);
60331e31b8aSbellard 	free (elf_phdata);
60431e31b8aSbellard 	return -errno;
60531e31b8aSbellard     }
60631e31b8aSbellard 
607b17780d5Sbellard #ifdef BSWAP_NEEDED
608b17780d5Sbellard     elf_ppnt = elf_phdata;
609b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
610b17780d5Sbellard         bswap_phdr(elf_ppnt);
611b17780d5Sbellard     }
612b17780d5Sbellard #endif
61331e31b8aSbellard     elf_ppnt = elf_phdata;
61431e31b8aSbellard 
61531e31b8aSbellard     elf_bss = 0;
61631e31b8aSbellard     elf_brk = 0;
61731e31b8aSbellard 
61831e31b8aSbellard 
61931e31b8aSbellard     elf_stack = ~0UL;
62031e31b8aSbellard     elf_interpreter = NULL;
62131e31b8aSbellard     start_code = ~0UL;
62231e31b8aSbellard     end_code = 0;
62331e31b8aSbellard     end_data = 0;
62431e31b8aSbellard 
62531e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
62631e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
62731e31b8aSbellard 	    if ( elf_interpreter != NULL )
62831e31b8aSbellard 	    {
62931e31b8aSbellard 		free (elf_phdata);
63031e31b8aSbellard 		free(elf_interpreter);
63131e31b8aSbellard 		close(bprm->fd);
63231e31b8aSbellard 		return -EINVAL;
63331e31b8aSbellard 	    }
63431e31b8aSbellard 
63531e31b8aSbellard 	    /* This is the program interpreter used for
63631e31b8aSbellard 	     * shared libraries - for now assume that this
63731e31b8aSbellard 	     * is an a.out format binary
63831e31b8aSbellard 	     */
63931e31b8aSbellard 
640d691f669Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz+
641d691f669Sbellard                                              strlen(bprm->interp_prefix));
64231e31b8aSbellard 
64331e31b8aSbellard 	    if (elf_interpreter == NULL) {
64431e31b8aSbellard 		free (elf_phdata);
64531e31b8aSbellard 		close(bprm->fd);
64631e31b8aSbellard 		return -ENOMEM;
64731e31b8aSbellard 	    }
64831e31b8aSbellard 
649d691f669Sbellard 	    strcpy(elf_interpreter, bprm->interp_prefix);
65031e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
65131e31b8aSbellard 	    if(retval >= 0) {
65231e31b8aSbellard 		retval = read(bprm->fd,
653d691f669Sbellard 			      elf_interpreter+strlen(bprm->interp_prefix),
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 
914d691f669Sbellard int elf_exec(const char *interp_prefix,
915d691f669Sbellard              const char * filename, char ** argv, char ** envp,
916b17780d5Sbellard              struct target_pt_regs * regs, struct image_info *infop)
91731e31b8aSbellard {
91831e31b8aSbellard         struct linux_binprm bprm;
91931e31b8aSbellard         int retval;
92031e31b8aSbellard         int i;
92131e31b8aSbellard 
92231e31b8aSbellard         bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
92331e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
92431e31b8aSbellard                 bprm.page[i] = 0;
92531e31b8aSbellard         retval = open(filename, O_RDONLY);
92631e31b8aSbellard         if (retval == -1) {
92731e31b8aSbellard 	    perror(filename);
92831e31b8aSbellard 	    exit(-1);
92931e31b8aSbellard             /* return retval; */
93031e31b8aSbellard 	}
93131e31b8aSbellard 	else {
93231e31b8aSbellard 	    bprm.fd = retval;
93331e31b8aSbellard 	}
934d691f669Sbellard         bprm.interp_prefix = (char *)interp_prefix;
93531e31b8aSbellard         bprm.filename = (char *)filename;
93631e31b8aSbellard         bprm.sh_bang = 0;
93731e31b8aSbellard         bprm.loader = 0;
93831e31b8aSbellard         bprm.exec = 0;
93931e31b8aSbellard         bprm.dont_iput = 0;
94031e31b8aSbellard 	bprm.argc = count(argv);
94131e31b8aSbellard 	bprm.envc = count(envp);
94231e31b8aSbellard 
94331e31b8aSbellard         retval = prepare_binprm(&bprm);
94431e31b8aSbellard 
94531e31b8aSbellard         if(retval>=0) {
94631e31b8aSbellard 	    bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
94731e31b8aSbellard 	    bprm.exec = bprm.p;
94831e31b8aSbellard 	    bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
94931e31b8aSbellard 	    bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
95031e31b8aSbellard 	    if (!bprm.p) {
95131e31b8aSbellard 		retval = -E2BIG;
95231e31b8aSbellard 	    }
95331e31b8aSbellard         }
95431e31b8aSbellard 
95531e31b8aSbellard         if(retval>=0) {
95631e31b8aSbellard 	    retval = load_elf_binary(&bprm,regs,infop);
95731e31b8aSbellard 	}
95831e31b8aSbellard         if(retval>=0) {
95931e31b8aSbellard 	    /* success.  Initialize important registers */
96031e31b8aSbellard 	    regs->esp = infop->start_stack;
96131e31b8aSbellard 	    regs->eip = infop->entry;
96231e31b8aSbellard 	    return retval;
96331e31b8aSbellard 	}
96431e31b8aSbellard 
96531e31b8aSbellard         /* Something went wrong, return the inode and free the argument pages*/
96631e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++) {
96731e31b8aSbellard 	    free_page((void *)bprm.page[i]);
96831e31b8aSbellard 	}
96931e31b8aSbellard         return(retval);
97031e31b8aSbellard }
97131e31b8aSbellard 
97231e31b8aSbellard 
97331e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
97431e31b8aSbellard {
97531e31b8aSbellard     printf("a.out interpreter not yet supported\n");
97631e31b8aSbellard     return(0);
97731e31b8aSbellard }
97831e31b8aSbellard 
979