xref: /qemu/linux-user/elfload.c (revision 32ce63371a6b4d7ad8786ac5d2f95a1e6cdd1af4)
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 
1530ac07d4Sbellard #ifdef TARGET_I386
1630ac07d4Sbellard 
1730ac07d4Sbellard #define ELF_START_MMAP 0x80000000
1830ac07d4Sbellard 
1930ac07d4Sbellard typedef uint32_t  elf_greg_t;
2030ac07d4Sbellard 
2130ac07d4Sbellard #define ELF_NGREG (sizeof (struct target_pt_regs) / sizeof(elf_greg_t))
2230ac07d4Sbellard typedef elf_greg_t elf_gregset_t[ELF_NGREG];
2330ac07d4Sbellard 
2430ac07d4Sbellard typedef struct user_i387_struct elf_fpregset_t;
2530ac07d4Sbellard 
2630ac07d4Sbellard /*
2730ac07d4Sbellard  * This is used to ensure we don't load something for the wrong architecture.
2830ac07d4Sbellard  */
2930ac07d4Sbellard #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
3030ac07d4Sbellard 
3130ac07d4Sbellard /*
3230ac07d4Sbellard  * These are used to set parameters in the core dumps.
3330ac07d4Sbellard  */
3430ac07d4Sbellard #define ELF_CLASS	ELFCLASS32
3530ac07d4Sbellard #define ELF_DATA	ELFDATA2LSB
3630ac07d4Sbellard #define ELF_ARCH	EM_386
3730ac07d4Sbellard 
3830ac07d4Sbellard 	/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
3930ac07d4Sbellard 	   starts %edx contains a pointer to a function which might be
4030ac07d4Sbellard 	   registered using `atexit'.  This provides a mean for the
4130ac07d4Sbellard 	   dynamic linker to call DT_FINI functions for shared libraries
4230ac07d4Sbellard 	   that have been loaded before the code runs.
4330ac07d4Sbellard 
4430ac07d4Sbellard 	   A value of 0 tells we have no such handler.  */
4530ac07d4Sbellard #define ELF_PLAT_INIT(_r)	_r->edx = 0
4630ac07d4Sbellard 
4730ac07d4Sbellard #define USE_ELF_CORE_DUMP
4830ac07d4Sbellard #define ELF_EXEC_PAGESIZE	4096
4930ac07d4Sbellard 
5030ac07d4Sbellard #endif
5130ac07d4Sbellard 
5231e31b8aSbellard #include "elf.h"
5309bfb054Sbellard 
5409bfb054Sbellard /*
5509bfb054Sbellard  * MAX_ARG_PAGES defines the number of pages allocated for arguments
5609bfb054Sbellard  * and envelope for the new program. 32 should suffice, this gives
5709bfb054Sbellard  * a maximum env+arg of 128kB w/4KB pages!
5809bfb054Sbellard  */
5909bfb054Sbellard #define MAX_ARG_PAGES 32
6009bfb054Sbellard 
6109bfb054Sbellard /*
6209bfb054Sbellard  * This structure is used to hold the arguments that are
6309bfb054Sbellard  * used when loading binaries.
6409bfb054Sbellard  */
6509bfb054Sbellard struct linux_binprm {
6609bfb054Sbellard         char buf[128];
6709bfb054Sbellard         unsigned long page[MAX_ARG_PAGES];
6809bfb054Sbellard         unsigned long p;
6909bfb054Sbellard         int sh_bang;
7009bfb054Sbellard 	int fd;
7109bfb054Sbellard         int e_uid, e_gid;
7209bfb054Sbellard         int argc, envc;
7309bfb054Sbellard         char * filename;        /* Name of binary */
7409bfb054Sbellard         unsigned long loader, exec;
7509bfb054Sbellard         int dont_iput;          /* binfmt handler has put inode */
7609bfb054Sbellard };
7709bfb054Sbellard 
7809bfb054Sbellard struct exec
7909bfb054Sbellard {
8009bfb054Sbellard   unsigned int a_info;   /* Use macros N_MAGIC, etc for access */
8109bfb054Sbellard   unsigned int a_text;   /* length of text, in bytes */
8209bfb054Sbellard   unsigned int a_data;   /* length of data, in bytes */
8309bfb054Sbellard   unsigned int a_bss;    /* length of uninitialized data area, in bytes */
8409bfb054Sbellard   unsigned int a_syms;   /* length of symbol table data in file, in bytes */
8509bfb054Sbellard   unsigned int a_entry;  /* start address */
8609bfb054Sbellard   unsigned int a_trsize; /* length of relocation info for text, in bytes */
8709bfb054Sbellard   unsigned int a_drsize; /* length of relocation info for data, in bytes */
8809bfb054Sbellard };
8909bfb054Sbellard 
9009bfb054Sbellard 
9109bfb054Sbellard #define N_MAGIC(exec) ((exec).a_info & 0xffff)
9209bfb054Sbellard #define OMAGIC 0407
9309bfb054Sbellard #define NMAGIC 0410
9409bfb054Sbellard #define ZMAGIC 0413
9509bfb054Sbellard #define QMAGIC 0314
9609bfb054Sbellard 
9709bfb054Sbellard #define X86_STACK_TOP 0x7d000000
9809bfb054Sbellard 
9909bfb054Sbellard /* max code+data+bss space allocated to elf interpreter */
10009bfb054Sbellard #define INTERP_MAP_SIZE (32 * 1024 * 1024)
10109bfb054Sbellard 
10209bfb054Sbellard /* max code+data+bss+brk space allocated to ET_DYN executables */
10309bfb054Sbellard #define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
10409bfb054Sbellard 
10509bfb054Sbellard /* from personality.h */
10609bfb054Sbellard 
10709bfb054Sbellard /* Flags for bug emulation. These occupy the top three bytes. */
10809bfb054Sbellard #define STICKY_TIMEOUTS		0x4000000
10909bfb054Sbellard #define WHOLE_SECONDS		0x2000000
11009bfb054Sbellard 
11109bfb054Sbellard /* Personality types. These go in the low byte. Avoid using the top bit,
11209bfb054Sbellard  * it will conflict with error returns.
11309bfb054Sbellard  */
11409bfb054Sbellard #define PER_MASK		(0x00ff)
11509bfb054Sbellard #define PER_LINUX		(0x0000)
11609bfb054Sbellard #define PER_SVR4		(0x0001 | STICKY_TIMEOUTS)
11709bfb054Sbellard #define PER_SVR3		(0x0002 | STICKY_TIMEOUTS)
11809bfb054Sbellard #define PER_SCOSVR3		(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
11909bfb054Sbellard #define PER_WYSEV386		(0x0004 | STICKY_TIMEOUTS)
12009bfb054Sbellard #define PER_ISCR4		(0x0005 | STICKY_TIMEOUTS)
12109bfb054Sbellard #define PER_BSD			(0x0006)
12209bfb054Sbellard #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
12331e31b8aSbellard 
12431e31b8aSbellard /* Necessary parameters */
12531e31b8aSbellard #define	ALPHA_PAGE_SIZE 4096
12631e31b8aSbellard #define	X86_PAGE_SIZE 4096
12731e31b8aSbellard 
12831e31b8aSbellard #define ALPHA_PAGE_MASK (~(ALPHA_PAGE_SIZE-1))
12931e31b8aSbellard #define X86_PAGE_MASK (~(X86_PAGE_SIZE-1))
13031e31b8aSbellard 
13131e31b8aSbellard #define ALPHA_PAGE_ALIGN(addr) ((((addr)+ALPHA_PAGE_SIZE)-1)&ALPHA_PAGE_MASK)
13231e31b8aSbellard #define X86_PAGE_ALIGN(addr) ((((addr)+X86_PAGE_SIZE)-1)&X86_PAGE_MASK)
13331e31b8aSbellard 
13431e31b8aSbellard #define NGROUPS 32
13531e31b8aSbellard 
13631e31b8aSbellard #define X86_ELF_EXEC_PAGESIZE X86_PAGE_SIZE
13731e31b8aSbellard #define X86_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(X86_ELF_EXEC_PAGESIZE-1))
13831e31b8aSbellard #define X86_ELF_PAGEOFFSET(_v) ((_v) & (X86_ELF_EXEC_PAGESIZE-1))
13931e31b8aSbellard 
14031e31b8aSbellard #define ALPHA_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ALPHA_PAGE_SIZE-1))
14131e31b8aSbellard #define ALPHA_ELF_PAGEOFFSET(_v) ((_v) & (ALPHA_PAGE_SIZE-1))
14231e31b8aSbellard 
14331e31b8aSbellard #define INTERPRETER_NONE 0
14431e31b8aSbellard #define INTERPRETER_AOUT 1
14531e31b8aSbellard #define INTERPRETER_ELF 2
14631e31b8aSbellard 
14731e31b8aSbellard #define DLINFO_ITEMS 12
14831e31b8aSbellard 
14909bfb054Sbellard #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x))
15009bfb054Sbellard #define get_user(ptr) (typeof(*ptr))(*(ptr))
151d691f669Sbellard 
15209bfb054Sbellard static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
15309bfb054Sbellard {
15409bfb054Sbellard 	memcpy(to, from, n);
15509bfb054Sbellard }
15609bfb054Sbellard 
15709bfb054Sbellard static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
15809bfb054Sbellard {
15909bfb054Sbellard 	memcpy(to, from, n);
16009bfb054Sbellard }
16131e31b8aSbellard 
16231e31b8aSbellard //extern void * mmap4k();
16331e31b8aSbellard #define mmap4k(a, b, c, d, e, f) mmap((void *)(a), b, c, d, e, f)
16431e31b8aSbellard 
16531e31b8aSbellard extern unsigned long x86_stack_size;
16631e31b8aSbellard 
16731e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd);
16831e31b8aSbellard 
16931e31b8aSbellard #ifdef BSWAP_NEEDED
17031e31b8aSbellard static void bswap_ehdr(Elf32_Ehdr *ehdr)
17131e31b8aSbellard {
17231e31b8aSbellard     bswap16s(&ehdr->e_type);			/* Object file type */
17331e31b8aSbellard     bswap16s(&ehdr->e_machine);		/* Architecture */
17431e31b8aSbellard     bswap32s(&ehdr->e_version);		/* Object file version */
17531e31b8aSbellard     bswap32s(&ehdr->e_entry);		/* Entry point virtual address */
17631e31b8aSbellard     bswap32s(&ehdr->e_phoff);		/* Program header table file offset */
17731e31b8aSbellard     bswap32s(&ehdr->e_shoff);		/* Section header table file offset */
17831e31b8aSbellard     bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
17931e31b8aSbellard     bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
18031e31b8aSbellard     bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
18131e31b8aSbellard     bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
18231e31b8aSbellard     bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
18331e31b8aSbellard     bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
18431e31b8aSbellard     bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
18531e31b8aSbellard }
18631e31b8aSbellard 
18731e31b8aSbellard static void bswap_phdr(Elf32_Phdr *phdr)
18831e31b8aSbellard {
18931e31b8aSbellard     bswap32s(&phdr->p_type);			/* Segment type */
19031e31b8aSbellard     bswap32s(&phdr->p_offset);		/* Segment file offset */
19131e31b8aSbellard     bswap32s(&phdr->p_vaddr);		/* Segment virtual address */
19231e31b8aSbellard     bswap32s(&phdr->p_paddr);		/* Segment physical address */
19331e31b8aSbellard     bswap32s(&phdr->p_filesz);		/* Segment size in file */
19431e31b8aSbellard     bswap32s(&phdr->p_memsz);		/* Segment size in memory */
19531e31b8aSbellard     bswap32s(&phdr->p_flags);		/* Segment flags */
19631e31b8aSbellard     bswap32s(&phdr->p_align);		/* Segment alignment */
19731e31b8aSbellard }
19831e31b8aSbellard #endif
19931e31b8aSbellard 
20031e31b8aSbellard static void * get_free_page(void)
20131e31b8aSbellard {
20231e31b8aSbellard     void *	retval;
20331e31b8aSbellard 
20431e31b8aSbellard     /* User-space version of kernel get_free_page.  Returns a page-aligned
20531e31b8aSbellard      * page-sized chunk of memory.
20631e31b8aSbellard      */
20731e31b8aSbellard     retval = mmap4k(0, ALPHA_PAGE_SIZE, PROT_READ|PROT_WRITE,
20831e31b8aSbellard 			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
20931e31b8aSbellard 
21031e31b8aSbellard     if((long)retval == -1) {
21131e31b8aSbellard 	perror("get_free_page");
21231e31b8aSbellard 	exit(-1);
21331e31b8aSbellard     }
21431e31b8aSbellard     else {
21531e31b8aSbellard 	return(retval);
21631e31b8aSbellard     }
21731e31b8aSbellard }
21831e31b8aSbellard 
21931e31b8aSbellard static void free_page(void * pageaddr)
22031e31b8aSbellard {
22131e31b8aSbellard     (void)munmap(pageaddr, ALPHA_PAGE_SIZE);
22231e31b8aSbellard }
22331e31b8aSbellard 
22431e31b8aSbellard /*
22531e31b8aSbellard  * 'copy_string()' copies argument/envelope strings from user
22631e31b8aSbellard  * memory to free pages in kernel mem. These are in a format ready
22731e31b8aSbellard  * to be put directly into the top of new user memory.
22831e31b8aSbellard  *
22931e31b8aSbellard  */
23031e31b8aSbellard static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
23131e31b8aSbellard                 unsigned long p)
23231e31b8aSbellard {
23331e31b8aSbellard     char *tmp, *tmp1, *pag = NULL;
23431e31b8aSbellard     int len, offset = 0;
23531e31b8aSbellard 
23631e31b8aSbellard     if (!p) {
23731e31b8aSbellard 	return 0;       /* bullet-proofing */
23831e31b8aSbellard     }
23931e31b8aSbellard     while (argc-- > 0) {
24031e31b8aSbellard 	if (!(tmp1 = tmp = get_user(argv+argc))) {
24131e31b8aSbellard 	    fprintf(stderr, "VFS: argc is wrong");
24231e31b8aSbellard 	    exit(-1);
24331e31b8aSbellard 	}
24431e31b8aSbellard 	while (get_user(tmp++));
24531e31b8aSbellard 	len = tmp - tmp1;
24631e31b8aSbellard 	if (p < len) {  /* this shouldn't happen - 128kB */
24731e31b8aSbellard 		return 0;
24831e31b8aSbellard 	}
24931e31b8aSbellard 	while (len) {
25031e31b8aSbellard 	    --p; --tmp; --len;
25131e31b8aSbellard 	    if (--offset < 0) {
25231e31b8aSbellard 		offset = p % X86_PAGE_SIZE;
25331e31b8aSbellard 		if (!(pag = (char *) page[p/X86_PAGE_SIZE]) &&
25431e31b8aSbellard 		    !(pag = (char *) page[p/X86_PAGE_SIZE] =
25531e31b8aSbellard 		      (unsigned long *) get_free_page())) {
25631e31b8aSbellard 			return 0;
25731e31b8aSbellard 		}
25831e31b8aSbellard 	    }
25931e31b8aSbellard 	    if (len == 0 || offset == 0) {
26031e31b8aSbellard 	        *(pag + offset) = get_user(tmp);
26131e31b8aSbellard 	    }
26231e31b8aSbellard 	    else {
26331e31b8aSbellard 	      int bytes_to_copy = (len > offset) ? offset : len;
26431e31b8aSbellard 	      tmp -= bytes_to_copy;
26531e31b8aSbellard 	      p -= bytes_to_copy;
26631e31b8aSbellard 	      offset -= bytes_to_copy;
26731e31b8aSbellard 	      len -= bytes_to_copy;
26831e31b8aSbellard 	      memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
26931e31b8aSbellard 	    }
27031e31b8aSbellard 	}
27131e31b8aSbellard     }
27231e31b8aSbellard     return p;
27331e31b8aSbellard }
27431e31b8aSbellard 
27531e31b8aSbellard static int in_group_p(gid_t g)
27631e31b8aSbellard {
27731e31b8aSbellard     /* return TRUE if we're in the specified group, FALSE otherwise */
27831e31b8aSbellard     int		ngroup;
27931e31b8aSbellard     int		i;
28031e31b8aSbellard     gid_t	grouplist[NGROUPS];
28131e31b8aSbellard 
28231e31b8aSbellard     ngroup = getgroups(NGROUPS, grouplist);
28331e31b8aSbellard     for(i = 0; i < ngroup; i++) {
28431e31b8aSbellard 	if(grouplist[i] == g) {
28531e31b8aSbellard 	    return 1;
28631e31b8aSbellard 	}
28731e31b8aSbellard     }
28831e31b8aSbellard     return 0;
28931e31b8aSbellard }
29031e31b8aSbellard 
29131e31b8aSbellard static int count(char ** vec)
29231e31b8aSbellard {
29331e31b8aSbellard     int		i;
29431e31b8aSbellard 
29531e31b8aSbellard     for(i = 0; *vec; i++) {
29631e31b8aSbellard         vec++;
29731e31b8aSbellard     }
29831e31b8aSbellard 
29931e31b8aSbellard     return(i);
30031e31b8aSbellard }
30131e31b8aSbellard 
30231e31b8aSbellard static int prepare_binprm(struct linux_binprm *bprm)
30331e31b8aSbellard {
30431e31b8aSbellard     struct stat		st;
30531e31b8aSbellard     int mode;
30631e31b8aSbellard     int retval, id_change;
30731e31b8aSbellard 
30831e31b8aSbellard     if(fstat(bprm->fd, &st) < 0) {
30931e31b8aSbellard 	return(-errno);
31031e31b8aSbellard     }
31131e31b8aSbellard 
31231e31b8aSbellard     mode = st.st_mode;
31331e31b8aSbellard     if(!S_ISREG(mode)) {	/* Must be regular file */
31431e31b8aSbellard 	return(-EACCES);
31531e31b8aSbellard     }
31631e31b8aSbellard     if(!(mode & 0111)) {	/* Must have at least one execute bit set */
31731e31b8aSbellard 	return(-EACCES);
31831e31b8aSbellard     }
31931e31b8aSbellard 
32031e31b8aSbellard     bprm->e_uid = geteuid();
32131e31b8aSbellard     bprm->e_gid = getegid();
32231e31b8aSbellard     id_change = 0;
32331e31b8aSbellard 
32431e31b8aSbellard     /* Set-uid? */
32531e31b8aSbellard     if(mode & S_ISUID) {
32631e31b8aSbellard     	bprm->e_uid = st.st_uid;
32731e31b8aSbellard 	if(bprm->e_uid != geteuid()) {
32831e31b8aSbellard 	    id_change = 1;
32931e31b8aSbellard 	}
33031e31b8aSbellard     }
33131e31b8aSbellard 
33231e31b8aSbellard     /* Set-gid? */
33331e31b8aSbellard     /*
33431e31b8aSbellard      * If setgid is set but no group execute bit then this
33531e31b8aSbellard      * is a candidate for mandatory locking, not a setgid
33631e31b8aSbellard      * executable.
33731e31b8aSbellard      */
33831e31b8aSbellard     if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
33931e31b8aSbellard 	bprm->e_gid = st.st_gid;
34031e31b8aSbellard 	if (!in_group_p(bprm->e_gid)) {
34131e31b8aSbellard 		id_change = 1;
34231e31b8aSbellard 	}
34331e31b8aSbellard     }
34431e31b8aSbellard 
34531e31b8aSbellard     memset(bprm->buf, 0, sizeof(bprm->buf));
34631e31b8aSbellard     retval = lseek(bprm->fd, 0L, SEEK_SET);
34731e31b8aSbellard     if(retval >= 0) {
34831e31b8aSbellard         retval = read(bprm->fd, bprm->buf, 128);
34931e31b8aSbellard     }
35031e31b8aSbellard     if(retval < 0) {
35131e31b8aSbellard 	perror("prepare_binprm");
35231e31b8aSbellard 	exit(-1);
35331e31b8aSbellard 	/* return(-errno); */
35431e31b8aSbellard     }
35531e31b8aSbellard     else {
35631e31b8aSbellard 	return(retval);
35731e31b8aSbellard     }
35831e31b8aSbellard }
35931e31b8aSbellard 
36031e31b8aSbellard unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
36131e31b8aSbellard 						struct image_info * info)
36231e31b8aSbellard {
36309bfb054Sbellard     unsigned long stack_base, size, error;
36431e31b8aSbellard     int i;
36531e31b8aSbellard 
36631e31b8aSbellard     /* Create enough stack to hold everything.  If we don't use
36731e31b8aSbellard      * it for args, we'll use it for something else...
36831e31b8aSbellard      */
36909bfb054Sbellard     size = x86_stack_size;
37009bfb054Sbellard     if (size < MAX_ARG_PAGES*X86_PAGE_SIZE)
37109bfb054Sbellard         size = MAX_ARG_PAGES*X86_PAGE_SIZE;
37209bfb054Sbellard     error = (unsigned long)mmap4k(NULL,
37309bfb054Sbellard                                   size + X86_PAGE_SIZE,
37431e31b8aSbellard                                   PROT_READ | PROT_WRITE,
37509bfb054Sbellard                                   MAP_PRIVATE | MAP_ANONYMOUS,
37609bfb054Sbellard                                   -1, 0);
37709bfb054Sbellard     if (error == -1) {
37831e31b8aSbellard         perror("stk mmap");
37931e31b8aSbellard         exit(-1);
38031e31b8aSbellard     }
38109bfb054Sbellard     /* we reserve one extra page at the top of the stack as guard */
38209bfb054Sbellard     mprotect((void *)(error + size), X86_PAGE_SIZE, PROT_NONE);
38331e31b8aSbellard 
38409bfb054Sbellard     stack_base = error + size - MAX_ARG_PAGES*X86_PAGE_SIZE;
38509bfb054Sbellard     p += stack_base;
38609bfb054Sbellard 
38709bfb054Sbellard     if (bprm->loader) {
38809bfb054Sbellard 	bprm->loader += stack_base;
38909bfb054Sbellard     }
39009bfb054Sbellard     bprm->exec += stack_base;
39131e31b8aSbellard 
39231e31b8aSbellard     for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
39331e31b8aSbellard 	if (bprm->page[i]) {
39431e31b8aSbellard 	    info->rss++;
39531e31b8aSbellard 
39631e31b8aSbellard 	    memcpy((void *)stack_base, (void *)bprm->page[i], X86_PAGE_SIZE);
39731e31b8aSbellard 	    free_page((void *)bprm->page[i]);
39831e31b8aSbellard 	}
39931e31b8aSbellard 	stack_base += X86_PAGE_SIZE;
40031e31b8aSbellard     }
40131e31b8aSbellard     return p;
40231e31b8aSbellard }
40331e31b8aSbellard 
40431e31b8aSbellard static void set_brk(unsigned long start, unsigned long end)
40531e31b8aSbellard {
40631e31b8aSbellard 	/* page-align the start and end addresses... */
40731e31b8aSbellard         start = ALPHA_PAGE_ALIGN(start);
40831e31b8aSbellard         end = ALPHA_PAGE_ALIGN(end);
40931e31b8aSbellard         if (end <= start)
41031e31b8aSbellard                 return;
41131e31b8aSbellard         if((long)mmap4k(start, end - start,
41231e31b8aSbellard                 PROT_READ | PROT_WRITE | PROT_EXEC,
41331e31b8aSbellard                 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
41431e31b8aSbellard 	    perror("cannot mmap brk");
41531e31b8aSbellard 	    exit(-1);
41631e31b8aSbellard 	}
41731e31b8aSbellard }
41831e31b8aSbellard 
41931e31b8aSbellard 
42031e31b8aSbellard /* We need to explicitly zero any fractional pages
42131e31b8aSbellard    after the data section (i.e. bss).  This would
42231e31b8aSbellard    contain the junk from the file that should not
42331e31b8aSbellard    be in memory */
42431e31b8aSbellard 
42531e31b8aSbellard 
42631e31b8aSbellard static void padzero(unsigned long elf_bss)
42731e31b8aSbellard {
42831e31b8aSbellard         unsigned long nbyte;
42931e31b8aSbellard         char * fpnt;
43031e31b8aSbellard 
43131e31b8aSbellard         nbyte = elf_bss & (ALPHA_PAGE_SIZE-1);	/* was X86_PAGE_SIZE - JRP */
43231e31b8aSbellard         if (nbyte) {
43331e31b8aSbellard 	    nbyte = ALPHA_PAGE_SIZE - nbyte;
43431e31b8aSbellard 	    fpnt = (char *) elf_bss;
43531e31b8aSbellard 	    do {
43631e31b8aSbellard 		*fpnt++ = 0;
43731e31b8aSbellard 	    } while (--nbyte);
43831e31b8aSbellard         }
43931e31b8aSbellard }
44031e31b8aSbellard 
44131e31b8aSbellard static unsigned int * create_elf_tables(char *p, int argc, int envc,
44231e31b8aSbellard                                         struct elfhdr * exec,
44331e31b8aSbellard                                         unsigned long load_addr,
44409bfb054Sbellard                                         unsigned long load_bias,
44531e31b8aSbellard                                         unsigned long interp_load_addr, int ibcs,
44631e31b8aSbellard                                         struct image_info *info)
44731e31b8aSbellard {
448b17780d5Sbellard         target_ulong *argv, *envp, *dlinfo;
449b17780d5Sbellard         target_ulong *sp;
45031e31b8aSbellard 
45131e31b8aSbellard         /*
45231e31b8aSbellard          * Force 16 byte alignment here for generality.
45331e31b8aSbellard          */
45431e31b8aSbellard         sp = (unsigned int *) (~15UL & (unsigned long) p);
45531e31b8aSbellard         sp -= exec ? DLINFO_ITEMS*2 : 2;
45631e31b8aSbellard         dlinfo = sp;
45731e31b8aSbellard         sp -= envc+1;
45831e31b8aSbellard         envp = sp;
45931e31b8aSbellard         sp -= argc+1;
46031e31b8aSbellard         argv = sp;
46131e31b8aSbellard         if (!ibcs) {
462b17780d5Sbellard                 put_user(tswapl((target_ulong)envp),--sp);
463b17780d5Sbellard                 put_user(tswapl((target_ulong)argv),--sp);
46431e31b8aSbellard         }
46531e31b8aSbellard 
46631e31b8aSbellard #define NEW_AUX_ENT(id, val) \
467b17780d5Sbellard           put_user (tswapl(id), dlinfo++); \
468b17780d5Sbellard           put_user (tswapl(val), dlinfo++)
46931e31b8aSbellard 
47031e31b8aSbellard         if (exec) { /* Put this here for an ELF program interpreter */
47109bfb054Sbellard           NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
47209bfb054Sbellard           NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
47309bfb054Sbellard           NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum));
47409bfb054Sbellard           NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(ALPHA_PAGE_SIZE));
47509bfb054Sbellard           NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr));
47609bfb054Sbellard           NEW_AUX_ENT (AT_FLAGS, (target_ulong)0);
47709bfb054Sbellard           NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry);
47809bfb054Sbellard           NEW_AUX_ENT (AT_UID, (target_ulong) getuid());
47909bfb054Sbellard           NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid());
48009bfb054Sbellard           NEW_AUX_ENT (AT_GID, (target_ulong) getgid());
48109bfb054Sbellard           NEW_AUX_ENT (AT_EGID, (target_ulong) getegid());
48231e31b8aSbellard         }
48331e31b8aSbellard         NEW_AUX_ENT (AT_NULL, 0);
48431e31b8aSbellard #undef NEW_AUX_ENT
485b17780d5Sbellard         put_user(tswapl(argc),--sp);
48631e31b8aSbellard         info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
48731e31b8aSbellard         while (argc-->0) {
488b17780d5Sbellard                 put_user(tswapl((target_ulong)p),argv++);
48931e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
49031e31b8aSbellard         }
49131e31b8aSbellard         put_user(0,argv);
49231e31b8aSbellard         info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
49331e31b8aSbellard         while (envc-->0) {
494b17780d5Sbellard                 put_user(tswapl((target_ulong)p),envp++);
49531e31b8aSbellard                 while (get_user(p++)) /* nothing */ ;
49631e31b8aSbellard         }
49731e31b8aSbellard         put_user(0,envp);
49831e31b8aSbellard         info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
49931e31b8aSbellard         return sp;
50031e31b8aSbellard }
50131e31b8aSbellard 
50231e31b8aSbellard 
50331e31b8aSbellard 
50431e31b8aSbellard static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
50531e31b8aSbellard 				     int interpreter_fd,
50631e31b8aSbellard 				     unsigned long *interp_load_addr)
50731e31b8aSbellard {
50831e31b8aSbellard 	struct elf_phdr *elf_phdata  =  NULL;
50931e31b8aSbellard 	struct elf_phdr *eppnt;
51009bfb054Sbellard 	unsigned long load_addr = 0;
51131e31b8aSbellard 	int load_addr_set = 0;
51231e31b8aSbellard 	int retval;
51331e31b8aSbellard 	unsigned long last_bss, elf_bss;
51431e31b8aSbellard 	unsigned long error;
51531e31b8aSbellard 	int i;
51631e31b8aSbellard 
51731e31b8aSbellard 	elf_bss = 0;
51831e31b8aSbellard 	last_bss = 0;
51931e31b8aSbellard 	error = 0;
52031e31b8aSbellard 
521644c433cSbellard #ifdef BSWAP_NEEDED
522644c433cSbellard         bswap_ehdr(interp_elf_ex);
523644c433cSbellard #endif
52431e31b8aSbellard 	/* First of all, some simple consistency checks */
52531e31b8aSbellard 	if ((interp_elf_ex->e_type != ET_EXEC &&
52631e31b8aSbellard              interp_elf_ex->e_type != ET_DYN) ||
52731e31b8aSbellard 	   !elf_check_arch(interp_elf_ex->e_machine)) {
52831e31b8aSbellard 		return ~0UL;
52931e31b8aSbellard 	}
53031e31b8aSbellard 
531644c433cSbellard 
53231e31b8aSbellard 	/* Now read in all of the header information */
53331e31b8aSbellard 
53431e31b8aSbellard 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
53531e31b8aSbellard 	    return ~0UL;
53631e31b8aSbellard 
53731e31b8aSbellard 	elf_phdata =  (struct elf_phdr *)
53831e31b8aSbellard 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
53931e31b8aSbellard 
54031e31b8aSbellard 	if (!elf_phdata)
54131e31b8aSbellard 	  return ~0UL;
54231e31b8aSbellard 
54331e31b8aSbellard 	/*
54431e31b8aSbellard 	 * If the size of this structure has changed, then punt, since
54531e31b8aSbellard 	 * we will be doing the wrong thing.
54631e31b8aSbellard 	 */
54709bfb054Sbellard 	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
54831e31b8aSbellard 	    free(elf_phdata);
54931e31b8aSbellard 	    return ~0UL;
55031e31b8aSbellard         }
55131e31b8aSbellard 
55231e31b8aSbellard 	retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
55331e31b8aSbellard 	if(retval >= 0) {
55431e31b8aSbellard 	    retval = read(interpreter_fd,
55531e31b8aSbellard 			   (char *) elf_phdata,
55631e31b8aSbellard 			   sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
55731e31b8aSbellard 	}
55831e31b8aSbellard 	if (retval < 0) {
55931e31b8aSbellard 		perror("load_elf_interp");
56031e31b8aSbellard 		exit(-1);
56131e31b8aSbellard 		free (elf_phdata);
56231e31b8aSbellard 		return retval;
56331e31b8aSbellard  	}
56431e31b8aSbellard #ifdef BSWAP_NEEDED
56531e31b8aSbellard 	eppnt = elf_phdata;
56631e31b8aSbellard 	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
56731e31b8aSbellard             bswap_phdr(eppnt);
56831e31b8aSbellard         }
56931e31b8aSbellard #endif
57009bfb054Sbellard 
57109bfb054Sbellard         if (interp_elf_ex->e_type == ET_DYN) {
57209bfb054Sbellard             /* in order to avoid harcoding the interpreter load
57309bfb054Sbellard                address in qemu, we allocate a big enough memory zone */
57409bfb054Sbellard             error = (unsigned long)mmap4k(NULL, INTERP_MAP_SIZE,
57509bfb054Sbellard                                           PROT_NONE, MAP_PRIVATE | MAP_ANON,
57609bfb054Sbellard                                           -1, 0);
57709bfb054Sbellard             if (error == -1) {
57809bfb054Sbellard                 perror("mmap");
57909bfb054Sbellard                 exit(-1);
58009bfb054Sbellard             }
58109bfb054Sbellard             load_addr = error;
58209bfb054Sbellard             load_addr_set = 1;
58309bfb054Sbellard         }
58409bfb054Sbellard 
58531e31b8aSbellard 	eppnt = elf_phdata;
58631e31b8aSbellard 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
58731e31b8aSbellard 	  if (eppnt->p_type == PT_LOAD) {
58831e31b8aSbellard 	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
58931e31b8aSbellard 	    int elf_prot = 0;
59031e31b8aSbellard 	    unsigned long vaddr = 0;
59131e31b8aSbellard 	    unsigned long k;
59231e31b8aSbellard 
59331e31b8aSbellard 	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
59431e31b8aSbellard 	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
59531e31b8aSbellard 	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
59631e31b8aSbellard 	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
59731e31b8aSbellard 	    	elf_type |= MAP_FIXED;
59831e31b8aSbellard 	    	vaddr = eppnt->p_vaddr;
59931e31b8aSbellard 	    }
60031e31b8aSbellard 	    error = (unsigned long)mmap4k(load_addr+X86_ELF_PAGESTART(vaddr),
60131e31b8aSbellard 		 eppnt->p_filesz + X86_ELF_PAGEOFFSET(eppnt->p_vaddr),
60231e31b8aSbellard 		 elf_prot,
60331e31b8aSbellard 		 elf_type,
60431e31b8aSbellard 		 interpreter_fd,
60531e31b8aSbellard 		 eppnt->p_offset - X86_ELF_PAGEOFFSET(eppnt->p_vaddr));
60631e31b8aSbellard 
60731e31b8aSbellard 	    if (error > -1024UL) {
60831e31b8aSbellard 	      /* Real error */
60931e31b8aSbellard 	      close(interpreter_fd);
61031e31b8aSbellard 	      free(elf_phdata);
61131e31b8aSbellard 	      return ~0UL;
61231e31b8aSbellard 	    }
61331e31b8aSbellard 
61431e31b8aSbellard 	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
61531e31b8aSbellard 	      load_addr = error;
61631e31b8aSbellard 	      load_addr_set = 1;
61731e31b8aSbellard 	    }
61831e31b8aSbellard 
61931e31b8aSbellard 	    /*
62031e31b8aSbellard 	     * Find the end of the file  mapping for this phdr, and keep
62131e31b8aSbellard 	     * track of the largest address we see for this.
62231e31b8aSbellard 	     */
62331e31b8aSbellard 	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
62431e31b8aSbellard 	    if (k > elf_bss) elf_bss = k;
62531e31b8aSbellard 
62631e31b8aSbellard 	    /*
62731e31b8aSbellard 	     * Do the same thing for the memory mapping - between
62831e31b8aSbellard 	     * elf_bss and last_bss is the bss section.
62931e31b8aSbellard 	     */
63031e31b8aSbellard 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
63131e31b8aSbellard 	    if (k > last_bss) last_bss = k;
63231e31b8aSbellard 	  }
63331e31b8aSbellard 
63431e31b8aSbellard 	/* Now use mmap to map the library into memory. */
63531e31b8aSbellard 
63631e31b8aSbellard 	close(interpreter_fd);
63731e31b8aSbellard 
63831e31b8aSbellard 	/*
63931e31b8aSbellard 	 * Now fill out the bss section.  First pad the last page up
64031e31b8aSbellard 	 * to the page boundary, and then perform a mmap to make sure
64131e31b8aSbellard 	 * that there are zeromapped pages up to and including the last
64231e31b8aSbellard 	 * bss page.
64331e31b8aSbellard 	 */
64431e31b8aSbellard 	padzero(elf_bss);
64531e31b8aSbellard 	elf_bss = X86_ELF_PAGESTART(elf_bss + ALPHA_PAGE_SIZE - 1); /* What we have mapped so far */
64631e31b8aSbellard 
64731e31b8aSbellard 	/* Map the last of the bss segment */
64831e31b8aSbellard 	if (last_bss > elf_bss) {
64931e31b8aSbellard 	  mmap4k(elf_bss, last_bss-elf_bss,
65031e31b8aSbellard 		  PROT_READ|PROT_WRITE|PROT_EXEC,
65131e31b8aSbellard 		  MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
65231e31b8aSbellard 	}
65331e31b8aSbellard 	free(elf_phdata);
65431e31b8aSbellard 
65531e31b8aSbellard 	*interp_load_addr = load_addr;
65631e31b8aSbellard 	return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
65731e31b8aSbellard }
65831e31b8aSbellard 
65931e31b8aSbellard 
66031e31b8aSbellard 
661b17780d5Sbellard static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
66231e31b8aSbellard                            struct image_info * info)
66331e31b8aSbellard {
66431e31b8aSbellard     struct elfhdr elf_ex;
66531e31b8aSbellard     struct elfhdr interp_elf_ex;
66631e31b8aSbellard     struct exec interp_ex;
66731e31b8aSbellard     int interpreter_fd = -1; /* avoid warning */
66809bfb054Sbellard     unsigned long load_addr, load_bias;
66931e31b8aSbellard     int load_addr_set = 0;
67031e31b8aSbellard     unsigned int interpreter_type = INTERPRETER_NONE;
67131e31b8aSbellard     unsigned char ibcs2_interpreter;
67231e31b8aSbellard     int i;
67331e31b8aSbellard     void * mapped_addr;
67431e31b8aSbellard     struct elf_phdr * elf_ppnt;
67531e31b8aSbellard     struct elf_phdr *elf_phdata;
67631e31b8aSbellard     unsigned long elf_bss, k, elf_brk;
67731e31b8aSbellard     int retval;
67831e31b8aSbellard     char * elf_interpreter;
67931e31b8aSbellard     unsigned long elf_entry, interp_load_addr = 0;
68031e31b8aSbellard     int status;
68131e31b8aSbellard     unsigned long start_code, end_code, end_data;
68231e31b8aSbellard     unsigned long elf_stack;
68331e31b8aSbellard     char passed_fileno[6];
68431e31b8aSbellard 
68531e31b8aSbellard     ibcs2_interpreter = 0;
68631e31b8aSbellard     status = 0;
68731e31b8aSbellard     load_addr = 0;
68809bfb054Sbellard     load_bias = 0;
68931e31b8aSbellard     elf_ex = *((struct elfhdr *) bprm->buf);          /* exec-header */
69031e31b8aSbellard #ifdef BSWAP_NEEDED
69131e31b8aSbellard     bswap_ehdr(&elf_ex);
69231e31b8aSbellard #endif
69331e31b8aSbellard 
69431e31b8aSbellard     if (elf_ex.e_ident[0] != 0x7f ||
69531e31b8aSbellard 	strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
69631e31b8aSbellard 	    return  -ENOEXEC;
69731e31b8aSbellard     }
69831e31b8aSbellard 
69931e31b8aSbellard     /* First of all, some simple consistency checks */
70031e31b8aSbellard     if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
70131e31b8aSbellard        				(! elf_check_arch(elf_ex.e_machine))) {
70231e31b8aSbellard 	    return -ENOEXEC;
70331e31b8aSbellard     }
70431e31b8aSbellard 
70531e31b8aSbellard     /* Now read in all of the header information */
70631e31b8aSbellard 
70731e31b8aSbellard     elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
70831e31b8aSbellard     if (elf_phdata == NULL) {
70931e31b8aSbellard 	return -ENOMEM;
71031e31b8aSbellard     }
71131e31b8aSbellard 
71231e31b8aSbellard     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
71331e31b8aSbellard     if(retval > 0) {
71431e31b8aSbellard 	retval = read(bprm->fd, (char *) elf_phdata,
71531e31b8aSbellard 				elf_ex.e_phentsize * elf_ex.e_phnum);
71631e31b8aSbellard     }
71731e31b8aSbellard 
71831e31b8aSbellard     if (retval < 0) {
71931e31b8aSbellard 	perror("load_elf_binary");
72031e31b8aSbellard 	exit(-1);
72131e31b8aSbellard 	free (elf_phdata);
72231e31b8aSbellard 	return -errno;
72331e31b8aSbellard     }
72431e31b8aSbellard 
725b17780d5Sbellard #ifdef BSWAP_NEEDED
726b17780d5Sbellard     elf_ppnt = elf_phdata;
727b17780d5Sbellard     for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
728b17780d5Sbellard         bswap_phdr(elf_ppnt);
729b17780d5Sbellard     }
730b17780d5Sbellard #endif
73131e31b8aSbellard     elf_ppnt = elf_phdata;
73231e31b8aSbellard 
73331e31b8aSbellard     elf_bss = 0;
73431e31b8aSbellard     elf_brk = 0;
73531e31b8aSbellard 
73631e31b8aSbellard 
73731e31b8aSbellard     elf_stack = ~0UL;
73831e31b8aSbellard     elf_interpreter = NULL;
73931e31b8aSbellard     start_code = ~0UL;
74031e31b8aSbellard     end_code = 0;
74131e31b8aSbellard     end_data = 0;
74231e31b8aSbellard 
74331e31b8aSbellard     for(i=0;i < elf_ex.e_phnum; i++) {
74431e31b8aSbellard 	if (elf_ppnt->p_type == PT_INTERP) {
74531e31b8aSbellard 	    if ( elf_interpreter != NULL )
74631e31b8aSbellard 	    {
74731e31b8aSbellard 		free (elf_phdata);
74831e31b8aSbellard 		free(elf_interpreter);
74931e31b8aSbellard 		close(bprm->fd);
75031e31b8aSbellard 		return -EINVAL;
75131e31b8aSbellard 	    }
75231e31b8aSbellard 
75331e31b8aSbellard 	    /* This is the program interpreter used for
75431e31b8aSbellard 	     * shared libraries - for now assume that this
75531e31b8aSbellard 	     * is an a.out format binary
75631e31b8aSbellard 	     */
75731e31b8aSbellard 
758*32ce6337Sbellard 	    elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
75931e31b8aSbellard 
76031e31b8aSbellard 	    if (elf_interpreter == NULL) {
76131e31b8aSbellard 		free (elf_phdata);
76231e31b8aSbellard 		close(bprm->fd);
76331e31b8aSbellard 		return -ENOMEM;
76431e31b8aSbellard 	    }
76531e31b8aSbellard 
76631e31b8aSbellard 	    retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
76731e31b8aSbellard 	    if(retval >= 0) {
768*32ce6337Sbellard 		retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
76931e31b8aSbellard 	    }
77031e31b8aSbellard 	    if(retval < 0) {
77131e31b8aSbellard 	 	perror("load_elf_binary2");
77231e31b8aSbellard 		exit(-1);
77331e31b8aSbellard 	    }
77431e31b8aSbellard 
77531e31b8aSbellard 	    /* If the program interpreter is one of these two,
77631e31b8aSbellard 	       then assume an iBCS2 image. Otherwise assume
77731e31b8aSbellard 	       a native linux image. */
77831e31b8aSbellard 
77931e31b8aSbellard 	    /* JRP - Need to add X86 lib dir stuff here... */
78031e31b8aSbellard 
78131e31b8aSbellard 	    if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
78231e31b8aSbellard 		strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
78331e31b8aSbellard 	      ibcs2_interpreter = 1;
78431e31b8aSbellard 	    }
78531e31b8aSbellard 
78631e31b8aSbellard #if 0
78731e31b8aSbellard 	    printf("Using ELF interpreter %s\n", elf_interpreter);
78831e31b8aSbellard #endif
78931e31b8aSbellard 	    if (retval >= 0) {
790*32ce6337Sbellard 		retval = open(path(elf_interpreter), O_RDONLY);
79131e31b8aSbellard 		if(retval >= 0) {
79231e31b8aSbellard 		    interpreter_fd = retval;
79331e31b8aSbellard 		}
79431e31b8aSbellard 		else {
79531e31b8aSbellard 		    perror(elf_interpreter);
79631e31b8aSbellard 		    exit(-1);
79731e31b8aSbellard 		    /* retval = -errno; */
79831e31b8aSbellard 		}
79931e31b8aSbellard 	    }
80031e31b8aSbellard 
80131e31b8aSbellard 	    if (retval >= 0) {
80231e31b8aSbellard 		retval = lseek(interpreter_fd, 0, SEEK_SET);
80331e31b8aSbellard 		if(retval >= 0) {
80431e31b8aSbellard 		    retval = read(interpreter_fd,bprm->buf,128);
80531e31b8aSbellard 		}
80631e31b8aSbellard 	    }
80731e31b8aSbellard 	    if (retval >= 0) {
80831e31b8aSbellard 		interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
80931e31b8aSbellard 		interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
81031e31b8aSbellard 	    }
81131e31b8aSbellard 	    if (retval < 0) {
81231e31b8aSbellard 		perror("load_elf_binary3");
81331e31b8aSbellard 		exit(-1);
81431e31b8aSbellard 		free (elf_phdata);
81531e31b8aSbellard 		free(elf_interpreter);
81631e31b8aSbellard 		close(bprm->fd);
81731e31b8aSbellard 		return retval;
81831e31b8aSbellard 	    }
81931e31b8aSbellard 	}
82031e31b8aSbellard 	elf_ppnt++;
82131e31b8aSbellard     }
82231e31b8aSbellard 
82331e31b8aSbellard     /* Some simple consistency checks for the interpreter */
82431e31b8aSbellard     if (elf_interpreter){
82531e31b8aSbellard 	interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
82631e31b8aSbellard 
82731e31b8aSbellard 	/* Now figure out which format our binary is */
82831e31b8aSbellard 	if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
82931e31b8aSbellard 	    	(N_MAGIC(interp_ex) != QMAGIC)) {
83031e31b8aSbellard 	  interpreter_type = INTERPRETER_ELF;
83131e31b8aSbellard 	}
83231e31b8aSbellard 
83331e31b8aSbellard 	if (interp_elf_ex.e_ident[0] != 0x7f ||
83431e31b8aSbellard 	    	strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
83531e31b8aSbellard 	    interpreter_type &= ~INTERPRETER_ELF;
83631e31b8aSbellard 	}
83731e31b8aSbellard 
83831e31b8aSbellard 	if (!interpreter_type) {
83931e31b8aSbellard 	    free(elf_interpreter);
84031e31b8aSbellard 	    free(elf_phdata);
84131e31b8aSbellard 	    close(bprm->fd);
84231e31b8aSbellard 	    return -ELIBBAD;
84331e31b8aSbellard 	}
84431e31b8aSbellard     }
84531e31b8aSbellard 
84631e31b8aSbellard     /* OK, we are done with that, now set up the arg stuff,
84731e31b8aSbellard        and then start this sucker up */
84831e31b8aSbellard 
84931e31b8aSbellard     if (!bprm->sh_bang) {
85031e31b8aSbellard 	char * passed_p;
85131e31b8aSbellard 
85231e31b8aSbellard 	if (interpreter_type == INTERPRETER_AOUT) {
85331e31b8aSbellard 	    sprintf(passed_fileno, "%d", bprm->fd);
85431e31b8aSbellard 	    passed_p = passed_fileno;
85531e31b8aSbellard 
85631e31b8aSbellard 	    if (elf_interpreter) {
85731e31b8aSbellard 		bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
85831e31b8aSbellard 		bprm->argc++;
85931e31b8aSbellard 	    }
86031e31b8aSbellard 	}
86131e31b8aSbellard 	if (!bprm->p) {
86231e31b8aSbellard 	    if (elf_interpreter) {
86331e31b8aSbellard 	        free(elf_interpreter);
86431e31b8aSbellard 	    }
86531e31b8aSbellard 	    free (elf_phdata);
86631e31b8aSbellard 	    close(bprm->fd);
86731e31b8aSbellard 	    return -E2BIG;
86831e31b8aSbellard 	}
86931e31b8aSbellard     }
87031e31b8aSbellard 
87131e31b8aSbellard     /* OK, This is the point of no return */
87231e31b8aSbellard     info->end_data = 0;
87331e31b8aSbellard     info->end_code = 0;
87431e31b8aSbellard     info->start_mmap = (unsigned long)ELF_START_MMAP;
87531e31b8aSbellard     info->mmap = 0;
87631e31b8aSbellard     elf_entry = (unsigned long) elf_ex.e_entry;
87731e31b8aSbellard 
87831e31b8aSbellard     /* Do this so that we can load the interpreter, if need be.  We will
87931e31b8aSbellard        change some of these later */
88031e31b8aSbellard     info->rss = 0;
88131e31b8aSbellard     bprm->p = setup_arg_pages(bprm->p, bprm, info);
88231e31b8aSbellard     info->start_stack = bprm->p;
88331e31b8aSbellard 
88431e31b8aSbellard     /* Now we do a little grungy work by mmaping the ELF image into
88531e31b8aSbellard      * the correct location in memory.  At this point, we assume that
88631e31b8aSbellard      * the image should be loaded at fixed address, not at a variable
88731e31b8aSbellard      * address.
88831e31b8aSbellard      */
88931e31b8aSbellard 
89031e31b8aSbellard     for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
89131e31b8aSbellard         int elf_prot = 0;
89209bfb054Sbellard         int elf_flags = 0;
89309bfb054Sbellard         unsigned long error;
89409bfb054Sbellard 
89509bfb054Sbellard 	if (elf_ppnt->p_type != PT_LOAD)
89609bfb054Sbellard             continue;
89709bfb054Sbellard 
89831e31b8aSbellard         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
89931e31b8aSbellard         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
90031e31b8aSbellard         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
90109bfb054Sbellard         elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
90209bfb054Sbellard         if (elf_ex.e_type == ET_EXEC || load_addr_set) {
90309bfb054Sbellard             elf_flags |= MAP_FIXED;
90409bfb054Sbellard         } else if (elf_ex.e_type == ET_DYN) {
90509bfb054Sbellard             /* Try and get dynamic programs out of the way of the default mmap
90609bfb054Sbellard                base, as well as whatever program they might try to exec.  This
90709bfb054Sbellard                is because the brk will follow the loader, and is not movable.  */
90809bfb054Sbellard             /* NOTE: for qemu, we do a big mmap to get enough space
90909bfb054Sbellard                without harcoding any address */
91009bfb054Sbellard             error = (unsigned long)mmap4k(NULL, ET_DYN_MAP_SIZE,
91109bfb054Sbellard                                           PROT_NONE, MAP_PRIVATE | MAP_ANON,
91209bfb054Sbellard                                           -1, 0);
91309bfb054Sbellard             if (error == -1) {
91409bfb054Sbellard                 perror("mmap");
91509bfb054Sbellard                 exit(-1);
91609bfb054Sbellard             }
91709bfb054Sbellard             load_bias = X86_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
91809bfb054Sbellard         }
91931e31b8aSbellard 
92009bfb054Sbellard         error = (unsigned long)mmap4k(
92109bfb054Sbellard                                       X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
92231e31b8aSbellard                                       (elf_ppnt->p_filesz +
92331e31b8aSbellard                                        X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
92431e31b8aSbellard                                       elf_prot,
92531e31b8aSbellard                                       (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
92631e31b8aSbellard                                       bprm->fd,
92731e31b8aSbellard                                       (elf_ppnt->p_offset -
92831e31b8aSbellard                                        X86_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
92909bfb054Sbellard         if (error == -1) {
93031e31b8aSbellard             perror("mmap");
93131e31b8aSbellard             exit(-1);
93231e31b8aSbellard         }
93331e31b8aSbellard 
93431e31b8aSbellard #ifdef LOW_ELF_STACK
93531e31b8aSbellard         if (X86_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
93631e31b8aSbellard             elf_stack = X86_ELF_PAGESTART(elf_ppnt->p_vaddr);
93731e31b8aSbellard #endif
93831e31b8aSbellard 
93931e31b8aSbellard         if (!load_addr_set) {
94031e31b8aSbellard             load_addr_set = 1;
94109bfb054Sbellard             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
94209bfb054Sbellard             if (elf_ex.e_type == ET_DYN) {
94309bfb054Sbellard                 load_bias += error -
94409bfb054Sbellard                     X86_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
94509bfb054Sbellard                 load_addr += load_bias;
94609bfb054Sbellard             }
94731e31b8aSbellard         }
94831e31b8aSbellard         k = elf_ppnt->p_vaddr;
94909bfb054Sbellard         if (k < start_code)
95009bfb054Sbellard             start_code = k;
95131e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
95209bfb054Sbellard         if (k > elf_bss)
95309bfb054Sbellard             elf_bss = k;
95431e31b8aSbellard         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
95531e31b8aSbellard             end_code = k;
95609bfb054Sbellard         if (end_data < k)
95709bfb054Sbellard             end_data = k;
95831e31b8aSbellard         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
95931e31b8aSbellard         if (k > elf_brk) elf_brk = k;
96031e31b8aSbellard     }
96109bfb054Sbellard 
96209bfb054Sbellard     elf_entry += load_bias;
96309bfb054Sbellard     elf_bss += load_bias;
96409bfb054Sbellard     elf_brk += load_bias;
96509bfb054Sbellard     start_code += load_bias;
96609bfb054Sbellard     end_code += load_bias;
96709bfb054Sbellard     //    start_data += load_bias;
96809bfb054Sbellard     end_data += load_bias;
96931e31b8aSbellard 
97031e31b8aSbellard     if (elf_interpreter) {
97131e31b8aSbellard 	if (interpreter_type & 1) {
97231e31b8aSbellard 	    elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
97331e31b8aSbellard 	}
97431e31b8aSbellard 	else if (interpreter_type & 2) {
97531e31b8aSbellard 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
97631e31b8aSbellard 					    &interp_load_addr);
97731e31b8aSbellard 	}
97831e31b8aSbellard 
97931e31b8aSbellard 	close(interpreter_fd);
98031e31b8aSbellard 	free(elf_interpreter);
98131e31b8aSbellard 
98231e31b8aSbellard 	if (elf_entry == ~0UL) {
98331e31b8aSbellard 	    printf("Unable to load interpreter\n");
98431e31b8aSbellard 	    free(elf_phdata);
98531e31b8aSbellard 	    exit(-1);
98631e31b8aSbellard 	    return 0;
98731e31b8aSbellard 	}
98831e31b8aSbellard     }
98931e31b8aSbellard 
99031e31b8aSbellard     free(elf_phdata);
99131e31b8aSbellard 
99231e31b8aSbellard     if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
99331e31b8aSbellard     info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
99431e31b8aSbellard 
99531e31b8aSbellard #ifdef LOW_ELF_STACK
99631e31b8aSbellard     info->start_stack = bprm->p = elf_stack - 4;
99731e31b8aSbellard #endif
99831e31b8aSbellard     bprm->p = (unsigned long)
99931e31b8aSbellard       create_elf_tables((char *)bprm->p,
100031e31b8aSbellard 		    bprm->argc,
100131e31b8aSbellard 		    bprm->envc,
100231e31b8aSbellard 		    (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
100309bfb054Sbellard                     load_addr, load_bias,
100431e31b8aSbellard 		    interp_load_addr,
100531e31b8aSbellard 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
100631e31b8aSbellard 		    info);
100731e31b8aSbellard     if (interpreter_type == INTERPRETER_AOUT)
100831e31b8aSbellard       info->arg_start += strlen(passed_fileno) + 1;
100931e31b8aSbellard     info->start_brk = info->brk = elf_brk;
101031e31b8aSbellard     info->end_code = end_code;
101131e31b8aSbellard     info->start_code = start_code;
101231e31b8aSbellard     info->end_data = end_data;
101331e31b8aSbellard     info->start_stack = bprm->p;
101431e31b8aSbellard 
101531e31b8aSbellard     /* Calling set_brk effectively mmaps the pages that we need for the bss and break
101631e31b8aSbellard        sections */
101731e31b8aSbellard     set_brk(elf_bss, elf_brk);
101831e31b8aSbellard 
101931e31b8aSbellard     padzero(elf_bss);
102031e31b8aSbellard 
102131e31b8aSbellard #if 0
102231e31b8aSbellard     printf("(start_brk) %x\n" , info->start_brk);
102331e31b8aSbellard     printf("(end_code) %x\n" , info->end_code);
102431e31b8aSbellard     printf("(start_code) %x\n" , info->start_code);
102531e31b8aSbellard     printf("(end_data) %x\n" , info->end_data);
102631e31b8aSbellard     printf("(start_stack) %x\n" , info->start_stack);
102731e31b8aSbellard     printf("(brk) %x\n" , info->brk);
102831e31b8aSbellard #endif
102931e31b8aSbellard 
103031e31b8aSbellard     if ( info->personality == PER_SVR4 )
103131e31b8aSbellard     {
103231e31b8aSbellard 	    /* Why this, you ask???  Well SVr4 maps page 0 as read-only,
103331e31b8aSbellard 	       and some applications "depend" upon this behavior.
103431e31b8aSbellard 	       Since we do not have the power to recompile these, we
103531e31b8aSbellard 	       emulate the SVr4 behavior.  Sigh.  */
103631e31b8aSbellard 	    mapped_addr = mmap4k(NULL, ALPHA_PAGE_SIZE, PROT_READ | PROT_EXEC,
103731e31b8aSbellard 			    MAP_FIXED | MAP_PRIVATE, -1, 0);
103831e31b8aSbellard     }
103931e31b8aSbellard 
104031e31b8aSbellard #ifdef ELF_PLAT_INIT
104131e31b8aSbellard     /*
104231e31b8aSbellard      * The ABI may specify that certain registers be set up in special
104331e31b8aSbellard      * ways (on i386 %edx is the address of a DT_FINI function, for
104431e31b8aSbellard      * example.  This macro performs whatever initialization to
104531e31b8aSbellard      * the regs structure is required.
104631e31b8aSbellard      */
104731e31b8aSbellard     ELF_PLAT_INIT(regs);
104831e31b8aSbellard #endif
104931e31b8aSbellard 
105031e31b8aSbellard 
105131e31b8aSbellard     info->entry = elf_entry;
105231e31b8aSbellard 
105331e31b8aSbellard     return 0;
105431e31b8aSbellard }
105531e31b8aSbellard 
105631e31b8aSbellard 
105731e31b8aSbellard 
1058*32ce6337Sbellard int elf_exec(const char * filename, char ** argv, char ** envp,
1059b17780d5Sbellard              struct target_pt_regs * regs, struct image_info *infop)
106031e31b8aSbellard {
106131e31b8aSbellard         struct linux_binprm bprm;
106231e31b8aSbellard         int retval;
106331e31b8aSbellard         int i;
106431e31b8aSbellard 
106531e31b8aSbellard         bprm.p = X86_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
106631e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++)       /* clear page-table */
106731e31b8aSbellard                 bprm.page[i] = 0;
106831e31b8aSbellard         retval = open(filename, O_RDONLY);
106931e31b8aSbellard         if (retval == -1) {
107031e31b8aSbellard 	    perror(filename);
107131e31b8aSbellard 	    exit(-1);
107231e31b8aSbellard             /* return retval; */
107331e31b8aSbellard 	}
107431e31b8aSbellard 	else {
107531e31b8aSbellard 	    bprm.fd = retval;
107631e31b8aSbellard 	}
107731e31b8aSbellard         bprm.filename = (char *)filename;
107831e31b8aSbellard         bprm.sh_bang = 0;
107931e31b8aSbellard         bprm.loader = 0;
108031e31b8aSbellard         bprm.exec = 0;
108131e31b8aSbellard         bprm.dont_iput = 0;
108231e31b8aSbellard 	bprm.argc = count(argv);
108331e31b8aSbellard 	bprm.envc = count(envp);
108431e31b8aSbellard 
108531e31b8aSbellard         retval = prepare_binprm(&bprm);
108631e31b8aSbellard 
108731e31b8aSbellard         if(retval>=0) {
108831e31b8aSbellard 	    bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
108931e31b8aSbellard 	    bprm.exec = bprm.p;
109031e31b8aSbellard 	    bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
109131e31b8aSbellard 	    bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
109231e31b8aSbellard 	    if (!bprm.p) {
109331e31b8aSbellard 		retval = -E2BIG;
109431e31b8aSbellard 	    }
109531e31b8aSbellard         }
109631e31b8aSbellard 
109731e31b8aSbellard         if(retval>=0) {
109831e31b8aSbellard 	    retval = load_elf_binary(&bprm,regs,infop);
109931e31b8aSbellard 	}
110031e31b8aSbellard         if(retval>=0) {
110131e31b8aSbellard 	    /* success.  Initialize important registers */
110231e31b8aSbellard 	    regs->esp = infop->start_stack;
110331e31b8aSbellard 	    regs->eip = infop->entry;
110431e31b8aSbellard 	    return retval;
110531e31b8aSbellard 	}
110631e31b8aSbellard 
110731e31b8aSbellard         /* Something went wrong, return the inode and free the argument pages*/
110831e31b8aSbellard         for (i=0 ; i<MAX_ARG_PAGES ; i++) {
110931e31b8aSbellard 	    free_page((void *)bprm.page[i]);
111031e31b8aSbellard 	}
111131e31b8aSbellard         return(retval);
111231e31b8aSbellard }
111331e31b8aSbellard 
111431e31b8aSbellard 
111531e31b8aSbellard static int load_aout_interp(void * exptr, int interp_fd)
111631e31b8aSbellard {
111731e31b8aSbellard     printf("a.out interpreter not yet supported\n");
111831e31b8aSbellard     return(0);
111931e31b8aSbellard }
112031e31b8aSbellard 
1121