diff options
author | Roland McGrath <roland@gnu.org> | 1995-06-05 10:42:18 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 1995-06-05 10:42:18 +0000 |
commit | 46a665402ece79f8adecf1f46b743135eda590ad (patch) | |
tree | 54740886b6c3f392710be3187a928c5c45842d45 /exec/exec.c | |
parent | 3f25a5329a4a11b5b37b09647f7034b59937858d (diff) |
Majorly revamped: Now supports the ELF format directly.
Secondarily uses the BFD library #ifdef BFD.
Supports gunzipping only #ifdef GZIP.
Diffstat (limited to 'exec/exec.c')
-rw-r--r-- | exec/exec.c | 693 |
1 files changed, 396 insertions, 297 deletions
diff --git a/exec/exec.c b/exec/exec.c index d04ba172..c6762465 100644 --- a/exec/exec.c +++ b/exec/exec.c @@ -2,13 +2,14 @@ Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Written by Roland McGrath. + Can exec ELF format directly. + #ifdef GZIP + Can gunzip executables into core on the fly. + #endif #ifdef BFD Can exec any executable format the BFD library understands to be for this flavor of machine. #endif - #ifdef AOUT - Can exec a.out format. - #endif This file is part of the GNU Hurd. @@ -45,23 +46,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "fsys_S.h" #include "notify_S.h" -/* Default: BFD or a.out? */ -#if !defined (BFD) && !defined (AOUT) -#define AOUT -#endif - - -#ifdef BFD #include <bfd.h> +#include <elf.h> -extern error_t bfd_mach_host_arch_mach (host_t host, - enum bfd_architecture *arch, - long int *machine); -#else -#include A_OUT_H -extern error_t aout_mach_host_machine (host_t host, int *host_machine); -#endif +extern error_t bfd_mach_host_arch_mach (host_t host, + enum bfd_architecture *bfd_arch, + long int *bfd_machine, + Elf32_Half *elf_machine); /* Data shared between check, check_section, @@ -75,12 +67,15 @@ struct execdata vm_address_t entry; FILE stream; file_t file; -#ifdef BFD + +#ifdef BFD bfd *bfd; - asection *interp_section; /* Interpreter section giving name of file. */ -#else - struct exec *header, headbuf; #endif + union /* Interpreter section giving name of file. */ + { + asection *section; + const Elf32_Phdr *phdr; + } interp; memory_object_t filemap, cntlmap; struct shared_io *cntl; char *file_data; /* File data if already copied in core. */ @@ -90,21 +85,28 @@ struct execdata /* Set by caller of load. */ task_t task; -#ifdef BFD - /* Vector indexed by section index, - information passed from check_section to load_section. - Set by caller of check_section and load. */ - vm_offset_t *locations; -#endif + union + { + /* Vector indexed by section index, + information passed from check_section to load_section. + Set by caller of check_section and load. */ + vm_offset_t *bfd_locations; + struct + { + /* Program header table read from the executable. + After `check' this is a pointer into the mapping window. + By `load' it is local alloca'd storage. */ + Elf32_Phdr *phdr; + Elf32_Word phnum; /* Number of program header table elements. */ + } elf; + } info; }; -#ifdef BFD + /* A BFD whose architecture and machine type are those of the host system. */ static bfd_arch_info_type host_bfd_arch_info; static bfd host_bfd = { arch_info: &host_bfd_arch_info }; -#else -static enum machine_type host_machine; /* a.out machine_type of the host. */ -#endif +static Elf32_Half elf_machine; /* ELF e_machine for the host. */ static file_t realnode; static mach_port_t execserver; /* Port doing exec protocol. */ @@ -141,7 +143,9 @@ b2he (error_t deflt) #define b2he() a2he (errno) #endif +#ifdef GZIP static void check_gzip (struct execdata *); +#endif #ifdef BFD @@ -162,7 +166,7 @@ check_section (bfd *bfd, asection *sec, void *userdata) /* Fast strcmp for this 8-byte constant string. */ if (*(const __typeof (interp.quadword) *) sec->name == interp.quadword) - u->interp_section = sec; + u->interp.section = sec; if (!(sec->flags & (SEC_ALLOC|SEC_LOAD)) || (sec->flags & SEC_NEVER_LOAD)) @@ -173,36 +177,32 @@ check_section (bfd *bfd, asection *sec, void *userdata) if (sec->flags & SEC_LOAD) { - u->locations[sec->index] = sec->filepos; + u->info.bfd_locations[sec->index] = sec->filepos; if ((off_t) sec->filepos < 0 || (off_t) sec->filepos > u->file_size) u->error = EINVAL; } } #endif -enum section { text, data, bss }; /* Load or allocate a section. */ static void -#ifdef BFD -load_section (bfd *bfd, asection *sec, void *userdata) -#else -load_section (enum section section, struct execdata *u) -#endif +load_section (void *section, struct execdata *u) { -#ifdef BFD - struct execdata *u = userdata; -#endif vm_address_t addr = 0; vm_offset_t filepos = 0; - vm_size_t secsize = 0; + vm_size_t filesz = 0, memsz = 0; vm_prot_t vm_prot; +#ifdef BFD + asection *const sec = section; +#endif + const Elf32_Phdr *const ph = section; if (u->error) return; -#ifdef BFD - if (sec->flags & SEC_NEVER_LOAD) +#ifdef BFD + if (u->bfd && sec->flags & SEC_NEVER_LOAD) /* Nothing to do for this section. */ return; #endif @@ -210,43 +210,35 @@ load_section (enum section section, struct execdata *u) vm_prot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; #ifdef BFD - addr = (vm_address_t) sec->vma; - filepos = u->locations[sec->index]; - secsize = sec->_raw_size; - if (sec->flags & (SEC_READONLY|SEC_ROM)) - vm_prot &= ~VM_PROT_WRITE; -#else - switch (section) + if (u->bfd) { - case text: - addr = (vm_address_t) N_TXTADDR (*u->header); - filepos = (vm_offset_t) N_TXTOFF (*u->header); - secsize = N_TXTLEN (*u->header); - vm_prot &= ~VM_PROT_WRITE; - break; - case data: - addr = (vm_address_t) N_DATADDR (*u->header); - filepos = (vm_offset_t) N_DATOFF (*u->header); - secsize = N_DATLEN (*u->header); - break; - case bss: - addr = (vm_address_t) N_BSSADDR (*u->header); - secsize = N_BSSLEN (*u->header); - break; + addr = (vm_address_t) sec->vma; + filepos = u->info.bfd_locations[sec->index]; + memsz = sec->_raw_size; + filesz = (sec->flags & SEC_LOAD) ? memsz : 0; + if (sec->flags & (SEC_READONLY|SEC_ROM)) + vm_prot &= ~VM_PROT_WRITE; } + else #endif + { + addr = ph->p_vaddr & ~(ph->p_align - 1); + memsz = ph->p_vaddr + ph->p_memsz - addr; + filepos = ph->p_offset & ~(ph->p_align - 1); + filesz = ph->p_offset + ph->p_filesz - filepos; + if ((ph->p_flags & PF_R) == 0) + vm_prot &= ~VM_PROT_READ; + if ((ph->p_flags & PF_W) == 0) + vm_prot &= ~VM_PROT_WRITE; + if ((ph->p_flags & PF_X) == 0) + vm_prot &= ~VM_PROT_EXECUTE; + } - if (secsize == 0) + if (memsz == 0) /* This section is empty; ignore it. */ return; - if ( -#ifdef BFD - sec->flags & SEC_LOAD -#else - section != bss -#endif - ) + if (filesz != 0) { vm_address_t mapstart = round_page (addr); @@ -284,27 +276,22 @@ load_section (enum section section, struct execdata *u) u->error = vm_protect (u->task, mapstart, size, 0, vm_prot); } - if (mapstart - addr < secsize) + if (mapstart - addr < filesz) { /* MAPSTART is the first page that starts inside the section. Map all the pages that start inside the section. */ -#ifdef BFD -#define SECTION_IN_MEMORY_P (sec->flags & SEC_IN_MEMORY) -#define SECTION_CONTENTS sec->contents -#else #define SECTION_IN_MEMORY_P (u->file_data != NULL) #define SECTION_CONTENTS (u->file_data + filepos) -#endif if (SECTION_IN_MEMORY_P) /* Data is already in memory; write it into the task. */ - write_to_task (mapstart, secsize - (mapstart - addr), vm_prot, + write_to_task (mapstart, filesz - (mapstart - addr), vm_prot, (vm_address_t) SECTION_CONTENTS + (mapstart - addr)); else if (u->filemap != MACH_PORT_NULL) /* Map the data into the task directly from the file. */ u->error = vm_map (u->task, - &mapstart, secsize - (mapstart - addr), 0, 0, + &mapstart, filesz - (mapstart - addr), 0, 0, u->filemap, filepos + (mapstart - addr), 1, vm_prot, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, @@ -314,7 +301,7 @@ load_section (enum section section, struct execdata *u) /* Cannot map the data. Read it into a buffer and vm_write it into the task. */ void *buf; - const vm_size_t size = secsize - (mapstart - addr); + const vm_size_t size = filesz - (mapstart - addr); u->error = vm_allocate (mach_task_self (), (vm_address_t *) &buf, size, 1); if (! u->error) @@ -343,14 +330,6 @@ load_section (enum section section, struct execdata *u) void *readaddr; size_t readsize; -#ifdef AOUT - if (N_MAGIC (*u->header) == NMAGIC || N_MAGIC (*u->header) == ZMAGIC) - { - u->error = ENOEXEC; - goto maplose; - } -#endif - if (u->error = vm_read (u->task, overlap_page, vm_page_size, &ourpage, &size)) { @@ -367,15 +346,15 @@ load_section (enum section section, struct execdata *u) if (u->error) { maplose: - vm_deallocate (u->task, mapstart, secsize); + vm_deallocate (u->task, mapstart, filesz); return; } } readaddr = (void *) (ourpage + (addr - overlap_page)); readsize = size - (addr - overlap_page); - if (readsize > secsize) - readsize = secsize; + if (readsize > filesz) + readsize = filesz; if (SECTION_IN_MEMORY_P) bcopy (SECTION_CONTENTS, readaddr, readsize); @@ -409,24 +388,25 @@ load_section (enum section section, struct execdata *u) if (u->cntl) u->cntl->accessed = 1; + + /* Tell the code below to zero-fill the remaining area. */ + addr += filesz; + memsz -= filesz; } -#ifdef BFD - else if (sec->flags & SEC_ALLOC) -#else - else -#endif + + if (memsz != 0) { /* SEC_ALLOC: Allocate zero-filled memory for the section. */ vm_address_t mapstart = round_page (addr); - if (mapstart - addr < secsize) + if (mapstart - addr < memsz) { /* MAPSTART is the first page that starts inside the section. Allocate all the pages that start inside the section. */ if (u->error = vm_allocate (u->task, &mapstart, - secsize - (mapstart - addr), 0)) + memsz - (mapstart - addr), 0)) return; } @@ -439,110 +419,47 @@ load_section (enum section section, struct execdata *u) if (u->error = vm_read (u->task, overlap_page, vm_page_size, &ourpage, &size)) { - vm_deallocate (u->task, mapstart, secsize); + vm_deallocate (u->task, mapstart, memsz); return; } bzero ((void *) (ourpage + (addr - overlap_page)), size - (addr - overlap_page)); - u->error = vm_write (u->task, overlap_page, ourpage, size); + if (!(vm_prot & VM_PROT_WRITE)) + u->error = vm_protect (u->task, overlap_page, size, + 0, VM_PROT_WRITE); + if (! u->error) + u->error = vm_write (u->task, overlap_page, ourpage, size); + if (! u->error && !(vm_prot & VM_PROT_WRITE)) + u->error = vm_protect (u->task, overlap_page, size, 0, vm_prot); vm_deallocate (mach_task_self (), ourpage, size); } } } + +/* Make sure our mapping window (or read buffer) covers + LEN bytes of the file starting at POSN. */ -/* Do post-loading processing for a section. This consists of peeking the - pages of non-demand-paged executables. */ - -static void -#ifdef BFD -postload_section (bfd *bfd, asection *sec, void *userdata) -#else -postload_section (enum section section, struct execdata *u) -#endif -{ -#ifdef BFD - struct execdata *u = userdata; -#endif - vm_address_t addr = 0; - vm_size_t secsize = 0; - -#ifdef BFD - addr = (vm_address_t) sec->vma; - secsize = sec->_raw_size; -#else - switch (section) - { - case text: - addr = (vm_address_t) N_TXTADDR (*u->header); - secsize = N_TXTLEN (*u->header); - break; - case data: - addr = (vm_address_t) N_DATADDR (*u->header); - secsize = N_DATLEN (*u->header); - break; - case bss: - addr = (vm_address_t) N_BSSADDR (*u->header); - secsize = N_BSSLEN (*u->header); - break; - } -#endif - - if ( -#ifdef AOUT - section != bss && N_MAGIC (*u->header) == NMAGIC -#else - (sec->flags & SEC_LOAD) && !(bfd->flags & D_PAGED) -#endif - ) - { - /* Pre-load the section by peeking every mapped page. */ - vm_address_t myaddr, a; - vm_size_t mysize; - myaddr = 0; - - /* We have already mapped the file into the task in load_section. - Now read from the task's memory into our own address space so we - can peek each page and cause it to be paged in. */ - if (u->error = vm_read (u->task, trunc_page (addr), round_page (secsize), - &myaddr, &mysize)) - return; - - /* Peek at the first word of each page. */ - for (a = ((myaddr + mysize) & ~(vm_page_size - 1)); - a >= myaddr; a -= vm_page_size) - /* Force it to be paged in. */ - (void) *(volatile int *) a; - - vm_deallocate (mach_task_self (), myaddr, mysize); - } -} - - - -/* stdio input-room function. */ -static int -input_room (FILE *f) +static void * +map (struct execdata *e, off_t posn, size_t len) { - struct execdata *e = f->__cookie; + FILE *f = &e->stream; const size_t size = e->file_size; size_t offset = 0; - if (f->__target >= size) - { - f->__eof = 1; - return EOF; - } + f->__target = posn; if (e->filemap == MACH_PORT_NULL) { - mach_msg_type_number_t nread = f->__bufsize; char *buffer = f->__buffer; + mach_msg_type_number_t nread = f->__bufsize; + while (nread < len) + nread += __vm_page_size; if (e->error = io_read (e->file, &buffer, &nread, f->__target, e->optimal_block)) { errno = e->error; f->__error = 1; - return EOF; + return NULL; } if (buffer != f->__buffer) { @@ -554,6 +471,12 @@ input_room (FILE *f) } f->__get_limit = f->__buffer + nread; + + if (nread < len) + { + f->__eof = 1; + return NULL; + } } else { @@ -567,18 +490,18 @@ input_room (FILE *f) offset = f->__target % vm_page_size; if (offset != 0) f->__target -= offset; + f->__bufsize = round_page (posn + len) - f->__target; /* Map the data from the file. */ if (vm_map (mach_task_self (), - (vm_address_t *) &f->__buffer, vm_page_size, 0, 1, + (vm_address_t *) &f->__buffer, f->__bufsize, 0, 1, e->filemap, f->__target, 1, VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE)) { - errno = EIO; + errno = e->error = EIO; f->__error = 1; - return EOF; + return NULL; } - f->__bufsize = vm_page_size; if (e->cntl) e->cntl->accessed = 1; @@ -592,13 +515,28 @@ input_room (FILE *f) f->__offset = f->__target; f->__bufp = f->__buffer + offset; - if (f->__get_limit == f->__buffer) + if (f->__bufp + len >= f->__get_limit) + { + f->__eof = 1; + return NULL; + } + + return f->__bufp; +} + +/* stdio input-room function. */ +static int +input_room (FILE *f) +{ + struct execdata *e = f->__cookie; + if (f->__target >= e->file_size) { f->__eof = 1; return EOF; } - return (unsigned char) *f->__bufp++; + return (map (e, f->__target, 1) == NULL ? EOF : + (unsigned char) *f->__bufp++); } static int @@ -615,7 +553,7 @@ close_exec_stream (void *cookie) /* Prepare to check and load FILE. */ -static inline void +static void prepare (file_t file, struct execdata *e) { e->file = file; @@ -701,26 +639,26 @@ prepare (file_t file, struct execdata *e) e->stream.__cookie = e; e->stream.__seen = 1; -#ifdef BFD - e->bfd = bfd_openstreamr (NULL, NULL, &e->stream); - if (e->bfd == NULL) - { - e->error = b2he (ENOEXEC); - return; - } - e->interp_section = NULL; -#endif + e->interp.section = NULL; } /* Check the magic number, etc. of the file. On successful return, the caller must allocate the E->locations vector, and map check_section over the BFD. */ +#ifdef BFD static void -check (struct execdata *e) +check_bfd (struct execdata *e) { -#ifdef BFD bfd_set_error (bfd_error_no_error); + + e->bfd = bfd_openstreamr (NULL, NULL, &e->stream); + if (e->bfd == NULL) + { + e->error = b2he (ENOEXEC); + return; + } + if (!bfd_check_format (e->bfd, bfd_object)) { e->error = b2he (ENOEXEC); @@ -737,45 +675,105 @@ check (struct execdata *e) } e->entry = e->bfd->start_address; -#else - /* Map in the a.out header. */ - if (e->file_size < sizeof (*e->header)) +} +#endif + +#include <endian.h> +#if BYTE_ORDER == BIG_ENDIAN +#define host_ELFDATA ELFDATA2MSB +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#define host_ELFDATA ELFDATA2LSB +#endif + +static void +check_elf (struct execdata *e) +{ + Elf32_Ehdr *ehdr = map (e, 0, sizeof (Elf32_Ehdr)); + Elf32_Phdr *phdr; + + if (! ehdr) { - e->error = EINVAL; + if (! ferror (&e->stream)) + e->error = ENOEXEC; return; } - e->header = NULL; - if (e->file_data) - /* Data already in core. Just use it. */ - e->header = (void *) e->file_data; - else if (e->filemap == MACH_PORT_NULL) - { - /* Cannot map the file. Read the header into a buffer. */ - if (fread (&e->headbuf, sizeof e->headbuf, 1, &e->stream) != 1) - { - e->error = errno; - return; - } - e->header = &e->headbuf; - } - else - if (e->error = vm_map (mach_task_self (), - (vm_address_t *) &e->header, sizeof (*e->header), - 0, 1, e->filemap, 0, 1, VM_PROT_READ, VM_PROT_READ, - VM_INHERIT_NONE)) - return; - if (N_BADMAG (*e->header)) + + if (*(Elf32_Word *) ehdr != ((union { Elf32_Word word; + unsigned char string[SELFMAG]; }) + { string: ELFMAG }).word) { e->error = ENOEXEC; return; } - if (N_MACHTYPE (*e->header) && N_MACHTYPE (*e->header) != host_machine) + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 || + ehdr->e_ident[EI_DATA] != host_ELFDATA || + ehdr->e_ident[EI_VERSION] != EV_CURRENT || + ehdr->e_version != EV_CURRENT || + ehdr->e_machine != elf_machine || + ehdr->e_ehsize < sizeof *ehdr || + ehdr->e_phentsize != sizeof (Elf32_Phdr)) { e->error = EINVAL; return; } - e->entry = e->header->a_entry; + e->entry = ehdr->e_entry; + e->info.elf.phnum = ehdr->e_phnum; + phdr = map (e, ehdr->e_phoff, ehdr->e_phnum * sizeof (Elf32_Phdr)); + if (! phdr) + { + if (! ferror (&e->stream)) + e->error = EINVAL; + return; + } + e->info.elf.phdr = phdr; +} + +static void +check_elf_phdr (struct execdata *e, const Elf32_Phdr *mapped_phdr, + vm_address_t *phdr_addr, vm_size_t *phdr_size) +{ + const Elf32_Phdr *phdr; + + memcpy (e->info.elf.phdr, mapped_phdr, + e->info.elf.phnum * sizeof (Elf32_Phdr)); + + for (phdr = e->info.elf.phdr; + phdr < &e->info.elf.phdr[e->info.elf.phnum]; + ++phdr) + switch (phdr->p_type) + { + case PT_INTERP: + e->interp.phdr = phdr; + break; + case PT_PHDR: + if (phdr_addr) + *phdr_addr = phdr->p_vaddr & ~(phdr->p_align - 1); + if (phdr_size) + *phdr_size = phdr->p_memsz; + break; + case PT_LOAD: + /* Sanity check. */ + if (e->file_size <= (off_t) (phdr->p_offset + + phdr->p_filesz)) + e->error = EINVAL; + break; + } +} + + +static void +check (struct execdata *e) +{ + check_elf (e); +#ifdef BFD + if (e->error == ENOEXEC) + { + e->error = 0; + check_bfd (e); + } #endif } @@ -789,12 +787,22 @@ load (task_t usertask, struct execdata *e) e->task = usertask; #ifdef BFD - bfd_map_over_sections (e->bfd, load_section, e); -#else - load_section (text, e); - load_section (data, e); - load_section (bss, e); + if (e->bfd) + { + void load_bfd_section (bfd *bfd, asection *sec, void *userdata) + { + load_section (sec, userdata); + } + bfd_map_over_sections (e->bfd, &load_bfd_section, e); + } + else #endif + { + Elf32_Word i; + for (i = 0; i < e->info.elf.phnum; ++i) + if (e->info.elf.phdr[i].p_type == PT_LOAD) + load_section (&e->info.elf.phdr[i], e); + } } /* Do post-loading processing on the task. */ @@ -805,11 +813,48 @@ postload (struct execdata *e) return; #ifdef BFD - bfd_map_over_sections (e->bfd, postload_section, e); -#else - postload_section (text, e); - postload_section (data, e); - postload_section (bss, e); + if (e->bfd) + { + /* Do post-loading processing for a section. This consists of + peeking the pages of non-demand-paged executables. */ + + void postload_section (bfd *bfd, asection *sec, void *userdata) + { + struct execdata *u = userdata; + vm_address_t addr = 0; + vm_size_t secsize = 0; + + addr = (vm_address_t) sec->vma; + secsize = sec->_raw_size; + + if ((sec->flags & SEC_LOAD) && !(bfd->flags & D_PAGED)) + { + /* Pre-load the section by peeking every mapped page. */ + vm_address_t myaddr, a; + vm_size_t mysize; + myaddr = 0; + + /* We have already mapped the file into the task in + load_section. Now read from the task's memory into our + own address space so we can peek each page and cause it to + be paged in. */ + if (u->error = vm_read (u->task, + trunc_page (addr), round_page (secsize), + &myaddr, &mysize)) + return; + + /* Peek at the first word of each page. */ + for (a = ((myaddr + mysize) & ~(vm_page_size - 1)); + a >= myaddr; a -= vm_page_size) + /* Force it to be paged in. */ + (void) *(volatile int *) a; + + vm_deallocate (mach_task_self (), myaddr, mysize); + } + } + + bfd_map_over_sections (e->bfd, postload_section, e); + } #endif } @@ -855,15 +900,8 @@ finish (struct execdata *e) if (e->bfd != NULL) bfd_close (e->bfd); else - fclose (&e->stream); -#else - fclose (&e->stream); - if (e->header != NULL && e->header != &e->headbuf && - e->header != (void *) e->file_data) - vm_deallocate (mach_task_self (), - (vm_address_t) e->header, sizeof (*e->header)); - e->header = NULL; #endif + fclose (&e->stream); if (e->file != MACH_PORT_NULL) { mach_port_deallocate (mach_task_self (), e->file); @@ -871,6 +909,7 @@ finish (struct execdata *e) } } +#ifdef GZIP /* Check the file for being a gzip'd image. Return with ENOEXEC means not a valid gzip file; return with another error means lossage in decoding; return with zero means the file was uncompressed into memory which E now @@ -970,11 +1009,8 @@ check_gzip (struct execdata *earg) e->stream.__get_limit = e->stream.__buffer + e->stream.__bufsize; e->stream.__bufp = e->stream.__buffer; e->stream.__seen = 1; - - e->bfd = bfd_openstreamr (NULL, NULL, &e->stream); - e->error = e->bfd ? 0 : b2he (ENOEXEC); } - +#endif static int request_server (mach_msg_header_t *inp, @@ -1089,10 +1125,22 @@ do_exec (mach_port_t execserver, thread_t thread = MACH_PORT_NULL; struct bootinfo *boot = 0; int secure, defaults; + vm_address_t phdr_addr = 0; + vm_size_t phdr_size = 0; - void check_maybe_gzip (struct execdata *e) + /* Prime E for executing FILE and check its validity. This must be an + inline function because it stores pointers into alloca'd storage in E + for later use in `load'. */ + void prepare_and_check (file_t file, struct execdata *e) { + /* Prepare E to read the file. */ + prepare (file, e); + + /* Check the file for validity first. */ + check (e); + +#ifdef GZIP if (e->error == ENOEXEC) { /* See if it is a compressed image. */ @@ -1103,52 +1151,94 @@ do_exec (mach_port_t execserver, for a valid magic number. */ check (e); } +#endif + +#if 0 + if (e->error == ENOEXEC) + /* Check for a #! executable file. */ + check_hashbang (e, replyport, + file, oldtask, flags, + argv, argvlen, argv_copy, + envp, envplen, envp_copy, + dtable, dtablesize, dtable_copy, + portarray, nports, portarray_copy, + intarray, nints, intarray_copy, + deallocnames, ndeallocnames, + destroynames, ndestroynames); +#endif } + + /* Here is the main body of the function. */ + + /* Catch this error now, rather than later. */ if ((!std_ports || !std_ints) && (flags & (EXEC_SECURE|EXEC_DEFAULTS))) return EIEIO; - interp.file = MACH_PORT_NULL; - - /* Prepare E to read the file. */ - prepare (file, &e); - /* Check the file for validity first. */ - - check_maybe_gzip (&e); -#if 0 - if (e.error == ENOEXEC) - /* Check for a #! executable file. */ - check_hashbang (&e, replyport, - file, oldtask, flags, - argv, argvlen, argv_copy, - envp, envplen, envp_copy, - dtable, dtablesize, dtable_copy, - portarray, nports, portarray_copy, - intarray, nints, intarray_copy, - deallocnames, ndeallocnames, - destroynames, ndestroynames); -#endif -#ifdef BFD + /* Prime E for executing FILE and check its validity. */ + prepare_and_check (file, &e); if (! e.error) { - e.locations = alloca (e.bfd->section_count * sizeof (vm_offset_t)); - bfd_map_over_sections (e.bfd, check_section, &e); +#ifdef BFD + if (e.bfd) + { + e.info.bfd_locations = alloca (e.bfd->section_count * + sizeof (vm_offset_t)); + bfd_map_over_sections (e.bfd, check_section, &e); + } + else +#endif + { + const Elf32_Phdr *phdr = e.info.elf.phdr; + e.info.elf.phdr = alloca (e.info.elf.phnum * sizeof (Elf32_Phdr)); + check_elf_phdr (&e, phdr, &phdr_addr, &phdr_size); + } } - if (! e.error && e.interp_section) + + + interp.file = MACH_PORT_NULL; + if (! e.error && e.interp.section) { /* There is an interpreter section specifying another file to load - along with this executable. */ - char name[e.interp_section->_raw_size]; - if (! bfd_get_section_contents (e.bfd, e.interp_section, - name, 0, e.interp_section->_raw_size)) + along with this executable. Find the name of the file and open + it. */ + +#ifdef BFD + char namebuf[e.bfd ? e.interp.section->_raw_size : 0]; +#endif + char *name; + +#ifdef BFD + if (e.bfd) { - e.error = b2he (errno); - e.interp_section = NULL; + if (! bfd_get_section_contents (e.bfd, e.interp.section, + namebuf, 0, + e.interp.section->_raw_size)) + { + e.error = b2he (errno); + name = NULL; + } + else + name = namebuf; } else +#endif { + name = map (&e, (e.interp.phdr->p_offset + & ~(e.interp.phdr->p_align - 1)), + e.interp.phdr->p_filesz); + if (! name && ! ferror (&e.stream)) + e.error = EINVAL; + } + + if (! name) + e.interp.section = NULL; + else + { + /* Open the named file using the appropriate directory ports for + the user. */ inline mach_port_t user_port (unsigned int idx) { return (((flags & (EXEC_SECURE|EXEC_DEFAULTS)) || idx >= nports) @@ -1163,17 +1253,29 @@ do_exec (mach_port_t execserver, } if (interp.file != MACH_PORT_NULL) { - prepare (interp.file, &interp); - check_maybe_gzip (&interp); + /* We opened an interpreter file. Prepare it for loading too. */ + prepare_and_check (interp.file, &interp); if (! interp.error) { - interp.locations = alloca (interp.bfd->section_count * - sizeof (vm_offset_t)); - bfd_map_over_sections (interp.bfd, check_section, &interp); +#ifdef BFD + if (interp.bfd) + { + interp.info.bfd_locations = alloca (interp.bfd->section_count * + sizeof (vm_offset_t)); + bfd_map_over_sections (interp.bfd, check_section, &e); + } + else +#endif + { + const Elf32_Phdr *phdr = interp.info.elf.phdr; + interp.info.elf.phdr = alloca (interp.info.elf.phnum * + sizeof (Elf32_Phdr)); + check_elf_phdr (&interp, phdr, NULL, NULL); + } } e.error = interp.error; } -#endif + if (e.error) { if (interp.file != MACH_PORT_NULL) @@ -1304,6 +1406,8 @@ do_exec (mach_port_t execserver, mach_port_deallocate (mach_task_self (), (mach_port_t) boot); #ifdef XXX + boot->phdr_addr = phdr_addr; + boot->phdr_size = phdr_size; boot->user_entry = e.entry; #endif @@ -1435,10 +1539,8 @@ do_exec (mach_port_t execserver, /* Start up the initial thread at the entry point. */ boot->stack_base = 0, boot->stack_size = 0; /* Don't care about values. */ if (e.error = mach_setup_thread (newtask, thread, -#ifdef BFD - e.interp_section ? (void *) interp.entry : -#endif - (void *) e.entry, + (void *) (e.interp.section ? interp.entry : + e.entry), &boot->stack_base, &boot->stack_size)) goto bootout; @@ -1936,15 +2038,12 @@ main (int argc, char **argv) save_argv = argv; -#ifdef BFD /* Put the Mach kernel's idea of what flavor of machine this is into the fake BFD against which architecture compatibility checks are made. */ err = bfd_mach_host_arch_mach (mach_host_self (), &host_bfd.arch_info->arch, - &host_bfd.arch_info->mach); -#else - err = aout_mach_host_machine (mach_host_self (), (int *)&host_machine); -#endif + &host_bfd.arch_info->mach, + &elf_machine); if (err) return err; |