summaryrefslogtreecommitdiffstats
path: root/ibcs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
committer <ralf@linux-mips.org>1994-11-28 11:59:19 +0000
commit1513ff9b7899ab588401c89db0e99903dbf5f886 (patch)
treef69cc81a940a502ea23d664c3ffb2d215a479667 /ibcs
Import of Linus's Linux 1.1.68
Diffstat (limited to 'ibcs')
-rw-r--r--ibcs/Makefile37
-rw-r--r--ibcs/binfmt_coff.c784
-rw-r--r--ibcs/binfmt_elf.c656
-rw-r--r--ibcs/emulate.c10
4 files changed, 1487 insertions, 0 deletions
diff --git a/ibcs/Makefile b/ibcs/Makefile
new file mode 100644
index 000000000..7b81ff2bc
--- /dev/null
+++ b/ibcs/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for the iBCS emulator files
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) -traditional $< -o $*.s
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+SUBDIRS =
+
+OBJS = emulate.o
+
+ibcs.o: $(OBJS)
+ $(LD) -r -o ibcs.o $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.c > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/ibcs/binfmt_coff.c b/ibcs/binfmt_coff.c
new file mode 100644
index 000000000..1a7c760cd
--- /dev/null
+++ b/ibcs/binfmt_coff.c
@@ -0,0 +1,784 @@
+/*
+ * These are the functions used to load COFF IBSC style executables.
+ * Information on COFF format may be obtained in either the Intel Binary
+ * Compatibility Specification 2 or O'Rilley's book on COFF. The shared
+ * libraries are defined only the in the Intel book.
+ *
+ * This file is based upon code written by Eric Youngdale for the ELF object
+ * file format.
+ *
+ * Author: Al Longyear (longyear@sii.com)
+ *
+ * Latest Revision:
+ * 3 February 1994
+ * Al Longyear (longyear@sii.com)
+ * Cleared first page of bss section using put_fs_byte.
+ */
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <asm/segment.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/coff.h>
+#include <linux/malloc.h>
+
+asmlinkage int sys_exit (int exit_code);
+asmlinkage int sys_close (unsigned fd);
+asmlinkage int sys_open (const char *, int, int);
+asmlinkage int sys_uselib(const char * library);
+
+static int preload_library (struct linux_binprm *exe_bprm,
+ COFF_SCNHDR * sect,
+ struct file *fp);
+
+static int load_object (struct linux_binprm *bprm,
+ struct pt_regs *regs,
+ int lib_ok);
+
+/*
+ * Small procedure to test for the proper file alignment.
+ */
+
+static inline int
+is_properly_aligned (COFF_SCNHDR *sect)
+{
+ long scnptr = COFF_LONG (sect->s_scnptr);
+ long vaddr = COFF_LONG (sect->s_vaddr);
+/*
+ * Print the section information if needed
+ */
+
+#ifdef COFF_DEBUG
+ printk ("%s, scnptr = %d, vaddr = %d\n",
+ sect->s_name,
+ scnptr, vaddr);
+#endif
+
+/*
+ * Return the error code if the section is not properly aligned.
+ */
+
+#ifdef COFF_DEBUG
+ if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
+ printk ("bad alignment in %s\n", sect->s_name);
+#endif
+ return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
+}
+
+/*
+ * Clear the bytes in the last page of data.
+ */
+
+static
+int clear_memory (unsigned long addr, unsigned long size)
+{
+ int status;
+
+ size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
+ if (size == 0)
+ status = 0;
+ else {
+
+#ifdef COFF_DEBUG
+ printk ("un-initialized storage in last page %d\n", size);
+#endif
+
+ status = verify_area (VERIFY_WRITE,
+ (void *) addr, size);
+#ifdef COFF_DEBUG
+ printk ("result from verify_area = %d\n", status);
+#endif
+
+ if (status >= 0)
+ while (size-- != 0)
+ put_fs_byte (0, addr++);
+ }
+ return status;
+}
+
+/*
+ * Helper function to process the load operation.
+ */
+
+static int
+load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
+{
+ COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */
+ COFF_SCNHDR *sect_bufr; /* Pointer to section table */
+ COFF_SCNHDR *text_sect; /* Pointer to the text section */
+ COFF_SCNHDR *data_sect; /* Pointer to the data section */
+ COFF_SCNHDR *bss_sect; /* Pointer to the bss section */
+ int text_count; /* Number of text sections */
+ int data_count; /* Number of data sections */
+ int bss_count; /* Number of bss sections */
+ int lib_count; /* Number of lib sections */
+ unsigned int start_addr = 0;/* Starting location for program */
+ int status = 0; /* Result status register */
+ int fd = -1; /* Open file descriptor */
+ struct file *fp = NULL; /* Pointer to the file at "fd" */
+ short int sections = 0; /* Number of sections in the file */
+ short int aout_size = 0; /* Size of the a.out header area */
+ short int flags; /* Flag bits from the COFF header */
+
+#ifdef COFF_DEBUG
+ printk ("binfmt_coff entry: %s\n", bprm->filename);
+#endif
+
+/*
+ * Validate the magic value for the object file.
+ */
+ do {
+ if (COFF_I386BADMAG (*coff_hdr)) {
+#ifdef COFF_DEBUG
+ printk ("bad filehdr magic\n");
+#endif
+ status = -ENOEXEC;
+ break;
+ }
+/*
+ * The object file should have 32 BIT little endian format. Do not allow
+ * it to have the 16 bit object file flag set as Linux is not able to run
+ * on the 80286/80186/8086.
+ */
+ flags = COFF_SHORT (coff_hdr->f_flags);
+ if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
+#ifdef COFF_DEBUG
+ printk ("invalid f_flags bits\n");
+#endif
+ status = -ENOEXEC;
+ break;
+ }
+/*
+ * Extract the header information which we need.
+ */
+ sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */
+ aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */
+/*
+ * If the file is not executable then reject the execution. This means
+ * that there must not be external references.
+ */
+ if ((flags & COFF_F_EXEC) == 0) {
+#ifdef COFF_DEBUG
+ printk ("not executable bit\n");
+#endif
+ status = -ENOEXEC;
+ break;
+ }
+/*
+ * There must be at least one section.
+ */
+ if (sections == 0) {
+#ifdef COFF_DEBUG
+ printk ("no sections\n");
+#endif
+ status = -ENOEXEC;
+ break;
+ }
+/*
+ * Do some additional consistency checks.
+ * The system requires mapping for this loader. If you try
+ * to use a file system with no mapping, the format is not valid.
+ */
+ if (!bprm->inode->i_op ||
+ !bprm->inode->i_op->default_file_ops->mmap) {
+#ifdef COFF_DEBUG
+ printk ("no mmap in fs\n");
+#endif
+ status = -ENOEXEC;
+ }
+ }
+ while (0);
+/*
+ * Allocate a buffer to hold the entire coff section list.
+ */
+ if (status >= 0) {
+ int nbytes = sections * COFF_SCNHSZ;
+
+ sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
+ if (0 == sect_bufr) {
+#ifdef COFF_DEBUG
+ printk ("kmalloc failed\n");
+#endif
+ status = -ENOEXEC;
+ }
+/*
+ * Read the section list from the disk file.
+ */
+ else {
+ int old_fs = get_fs ();
+ set_fs (get_ds ()); /* Make it point to the proper location */
+ status = read_exec (bprm->inode, /* INODE for file */
+ aout_size + COFF_FILHSZ, /* Offset in the file */
+ (char *) sect_bufr, /* Buffer for read */
+ nbytes); /* Byte count reqd. */
+ set_fs (old_fs); /* Restore the selector */
+#ifdef COFF_DEBUG
+ if (status < 0)
+ printk ("read aout hdr, status = %d\n", status);
+#endif
+ }
+ }
+ else
+ sect_bufr = NULL; /* Errors do not have a section buffer */
+/*
+ * Count the number of sections for the required types and store the location
+ * of the last section for the three primary types.
+ */
+ text_count = 0;
+ data_count = 0;
+ bss_count = 0;
+ lib_count = 0;
+
+ text_sect = NULL;
+ data_sect = NULL;
+ bss_sect = NULL;
+/*
+ * Loop through the sections and find the various types
+ */
+ if (status >= 0) {
+ int nIndex;
+ COFF_SCNHDR *sect_ptr = sect_bufr;
+
+ for (nIndex = 0; nIndex < sections; ++nIndex) {
+ long int sect_flags = COFF_LONG (sect_ptr->s_flags);
+
+ switch (sect_flags) {
+ case COFF_STYP_TEXT:
+ text_sect = sect_ptr;
+ ++text_count;
+ status = is_properly_aligned (sect_ptr);
+ break;
+
+ case COFF_STYP_DATA:
+ data_sect = sect_ptr;
+ ++data_count;
+ status = is_properly_aligned (sect_ptr);
+ break;
+
+ case COFF_STYP_BSS:
+ bss_sect = sect_ptr;
+ ++bss_count;
+ break;
+
+ case COFF_STYP_LIB:
+#ifdef COFF_DEBUG
+ printk (".lib section found\n");
+#endif
+ ++lib_count;
+ break;
+
+ default:
+ break;
+ }
+ sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
+ }
+/*
+ * Ensure that there are the required sections. There must be one text
+ * sections and one each of the data and bss sections for an executable.
+ * A library may or may not have a data / bss section.
+ */
+ if (text_count != 1) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("no text sections\n");
+#endif
+ }
+ else {
+ if (lib_ok) {
+ if (data_count != 1 || bss_count != 1) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("no .data nor .bss sections\n");
+#endif
+ }
+ }
+ }
+ }
+/*
+ * If there is no additional header then assume the file starts at
+ * the first byte of the text section. This may not be the proper place,
+ * so the best solution is to include the optional header. A shared library
+ * __MUST__ have an optional header to indicate that it is a shared library.
+ */
+ if (status >= 0) {
+ if (aout_size == 0) {
+ if (!lib_ok) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("no header in library\n");
+#endif
+ }
+ start_addr = COFF_LONG (text_sect->s_vaddr);
+ }
+/*
+ * There is some header. Ensure that it is sufficient.
+ */
+ else {
+ if (aout_size < COFF_AOUTSZ) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("header too small\n");
+#endif
+ }
+ else {
+ COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */
+ (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
+ short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
+/*
+ * Validate the magic number in the a.out header. If it is valid then
+ * update the starting symbol location. Do not accept these file formats
+ * when loading a shared library.
+ */
+ switch (aout_magic) {
+ case COFF_OMAGIC:
+ case COFF_ZMAGIC:
+ case COFF_STMAGIC:
+ if (!lib_ok) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("wrong a.out header magic\n");
+#endif
+ }
+ start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
+ break;
+/*
+ * Magic value for a shared library. This is valid only when loading a
+ * shared library. (There is no need for a start_addr. It won't be used.)
+ */
+ case COFF_SHMAGIC:
+ if (lib_ok) {
+#ifdef COFF_DEBUG
+ printk ("wrong a.out header magic\n");
+#endif
+ status = -ENOEXEC;
+ }
+ break;
+
+ default:
+#ifdef COFF_DEBUG
+ printk ("wrong a.out header magic\n");
+#endif
+ status = -ENOEXEC;
+ break;
+ }
+ }
+ }
+ }
+/*
+ * Fetch a file pointer to the executable.
+ */
+ if (status >= 0) {
+ fd = open_inode (bprm->inode, O_RDONLY);
+ if (fd < 0) {
+#ifdef COFF_DEBUG
+ printk ("can not open inode, result = %d\n", fd);
+#endif
+ status = fd;
+ }
+ else
+ fp = current->files->fd[fd];
+ }
+ else
+ fd = -1; /* Invalidate the open file descriptor */
+/*
+ * Generate the proper values for the text fields
+ *
+ * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
+ * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
+ */
+ if (status >= 0) {
+ long text_scnptr = COFF_LONG (text_sect->s_scnptr);
+ long text_size = COFF_LONG (text_sect->s_size);
+ long text_vaddr = COFF_LONG (text_sect->s_vaddr);
+
+ long data_scnptr;
+ long data_size;
+ long data_vaddr;
+
+ long bss_size;
+ long bss_vaddr;
+/*
+ * Generate the proper values for the data fields
+ */
+ if (data_sect != NULL) {
+ data_scnptr = COFF_LONG (data_sect->s_scnptr);
+ data_size = COFF_LONG (data_sect->s_size);
+ data_vaddr = COFF_LONG (data_sect->s_vaddr);
+ }
+ else {
+ data_scnptr = 0;
+ data_size = 0;
+ data_vaddr = 0;
+ }
+/*
+ * Generate the proper values for the bss fields
+ */
+ if (bss_sect != NULL) {
+ bss_size = COFF_LONG (bss_sect->s_size);
+ bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
+ }
+ else {
+ bss_size = 0;
+ bss_vaddr = 0;
+ }
+/*
+ * Flush the executable from memory. At this point the executable is
+ * committed to being defined or a segmentation violation will occur.
+ */
+ if (lib_ok) {
+#ifdef COFF_DEBUG
+ printk ("flushing executable\n");
+#endif
+ flush_old_exec (bprm);
+/*
+ * Define the initial locations for the various items in the new process
+ */
+ current->mm->mmap = NULL;
+ current->mm->rss = 0;
+/*
+ * Construct the parameter and environment string table entries.
+ */
+ bprm->p += change_ldt (0, bprm->page);
+ bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
+ bprm->p = (unsigned long) create_tables ((char *) bprm->p,
+ bprm->argc,
+ bprm->envc,
+ 1);
+/*
+ * Do the end processing once the stack has been constructed
+ */
+ current->mm->start_code = text_vaddr & PAGE_MASK;
+ current->mm->end_code = text_vaddr + text_size;
+ current->mm->end_data = data_vaddr + data_size;
+ current->mm->start_brk =
+ current->mm->brk = bss_vaddr + bss_size;
+ current->suid =
+ current->euid = bprm->e_uid;
+ current->sgid =
+ current->egid = bprm->e_gid;
+ current->executable = bprm->inode; /* Store inode for file */
+ ++bprm->inode->i_count; /* Count the open inode */
+ regs->eip = start_addr; /* Current EIP register */
+ regs->esp =
+ current->mm->start_stack = bprm->p;
+ }
+/*
+ * Map the text pages
+ */
+
+#ifdef COFF_DEBUG
+ printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
+ text_vaddr,
+ text_size,
+ text_scnptr);
+#endif
+ status = do_mmap (fp,
+ text_vaddr & PAGE_MASK,
+ text_size + (text_vaddr & ~PAGE_MASK),
+ PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_SHARED,
+ text_scnptr & PAGE_MASK);
+
+ status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
+/*
+ * Map the data pages
+ */
+ if (status >= 0 && data_size != 0) {
+#ifdef COFF_DEBUG
+ printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
+ data_vaddr,
+ data_size,
+ data_scnptr);
+#endif
+ status = do_mmap (fp,
+ data_vaddr & PAGE_MASK,
+ data_size + (data_vaddr & ~PAGE_MASK),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE,
+ data_scnptr & PAGE_MASK);
+
+ status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
+ }
+/*
+ * Construct the bss data for the process. The bss ranges from the
+ * end of the data (which may not be on a page boundary) to the end
+ * of the bss section. Allocate any necessary pages for the data.
+ */
+ if (status >= 0 && bss_size != 0) {
+#ifdef COFF_DEBUG
+ printk (".bss: vaddr = %d, size = %d\n",
+ bss_vaddr,
+ bss_size);
+#endif
+ zeromap_page_range (PAGE_ALIGN (bss_vaddr),
+ PAGE_ALIGN (bss_size),
+ PAGE_COPY);
+
+ status = clear_memory (bss_vaddr, bss_size);
+ }
+/*
+ * Load any shared library for the executable.
+ */
+ if (status >= 0 && lib_ok && lib_count != 0) {
+ int nIndex;
+ COFF_SCNHDR *sect_ptr = sect_bufr;
+/*
+ * Find the library sections. (There should be at least one. It was counted
+ * earlier.) This will eventually recurse to our code and load the shared
+ * library with our own procedures.
+ */
+ for (nIndex = 0; nIndex < sections; ++nIndex) {
+ long int sect_flags = COFF_LONG (sect_ptr->s_flags);
+ if (sect_flags == COFF_STYP_LIB) {
+ status = preload_library (bprm, sect_ptr, fp);
+ if (status != 0)
+ break;
+ }
+ sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
+ }
+ }
+/*
+ * Generate any needed trap for this process. If an error occurred then
+ * generate a segmentation violation. If the process is being debugged
+ * then generate the load trap. (Note: If this is a library load then
+ * do not generate the trap here. Pass the error to the caller who
+ * will do it for the process in the outer lay of this procedure call.)
+ */
+ if (lib_ok) {
+ if (status < 0)
+ send_sig (SIGSEGV, current, 0); /* Generate the error trap */
+ else {
+ if (current->flags & PF_PTRACED)
+ send_sig (SIGTRAP, current, 0);
+ }
+ status = 0; /* We are committed. It can't fail */
+ }
+ }
+/*
+ * Do any cleanup processing
+ */
+ if (fd >= 0)
+ sys_close (fd); /* Close unused code file */
+
+ if (sect_bufr != NULL)
+ kfree (sect_bufr); /* Release section list buffer */
+/*
+ * Return the completion status.
+ */
+#ifdef COFF_DEBUG
+ printk ("binfmt_coff: result = %d\n", status);
+#endif
+ return (status);
+}
+
+/*
+ * This procedure will load the library listed in the file name given
+ * as the parameter. The result will be non-zero should something fail
+ * to load.
+ */
+
+static int
+preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
+{
+ int status;
+ int old_fs = get_fs();
+/*
+ * If debugging then print "we have arrived"
+ */
+#ifdef COFF_DEBUG
+ printk ("%s loading shared library %s\n",
+ exe_bprm->filename,
+ lib_name);
+#endif
+/*
+ * Change the FS register to the proper kernel address space and attempt
+ * to load the library. The library name is allocated from the kernel
+ * pool.
+ */
+ set_fs (get_ds ());
+ status = sys_uselib (lib_name);
+ set_fs (old_fs);
+/*
+ * Return the success/failure to the caller.
+ */
+ return (status);
+}
+
+/*
+ * This procedure is called to load a library section. The various
+ * libraries are loaded from the list given in the section data.
+ */
+
+static int
+preload_library (struct linux_binprm *exe_bprm,
+ COFF_SCNHDR * sect, struct file *fp)
+{
+ int status = 0; /* Completion status */
+ long nbytes; /* Count of bytes in the header area */
+/*
+ * Fetch the size of the section. There must be enough room for at least
+ * one entry.
+ */
+ nbytes = COFF_LONG (sect->s_size);
+ if (nbytes < COFF_SLIBSZ) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("library section too small\n");
+#endif
+ }
+/*
+ * Allocate a buffer to hold the section data
+ */
+ else {
+ COFF_SLIBHD *phdr;
+ char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
+
+ if (0 == buffer) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("kmalloc failed\n");
+#endif
+ }
+ else {
+ int old_fs = get_fs ();
+/*
+ * Read the section data from the disk file.
+ */
+ set_fs (get_ds ()); /* Make it point to the proper location */
+ status = read_exec (exe_bprm->inode, /* INODE for file */
+ COFF_LONG (sect->s_scnptr), /* Disk location */
+ buffer, /* Buffer for read */
+ nbytes); /* Byte count reqd. */
+ set_fs (old_fs); /* Restore the selector */
+/*
+ * Check the result. The value returned is the byte count actually read.
+ */
+ if (status >= 0 && status != nbytes) {
+#ifdef COFF_DEBUG
+ printk ("read of lib section was short\n");
+#endif
+ status = -ENOEXEC;
+ }
+ }
+/*
+ * At this point, go through the list of libraries in the data area.
+ */
+ phdr = (COFF_SLIBHD *) buffer;
+ while (status >= 0 && nbytes > COFF_SLIBSZ) {
+ int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
+ int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
+/*
+ * Validate the sizes of the various items. I don't trust the linker!!
+ */
+ if ((unsigned) header_size >= (unsigned) nbytes ||
+ entry_size <= 0 ||
+ (unsigned) entry_size <= (unsigned) header_size) {
+ status = -ENOEXEC;
+#ifdef COFF_DEBUG
+ printk ("header count is invalid\n");
+#endif
+ }
+/*
+ * Load the library. Stop the load process on the first error.
+ */
+ else {
+ status = preload_this_library (exe_bprm,
+ &((char *) phdr)[header_size]);
+#ifdef COFF_DEBUG
+ printk ("preload_this_library result = %d\n", status);
+#endif
+ }
+/*
+ * Point to the next library in the section data.
+ */
+ nbytes -= entry_size;
+ phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
+ }
+/*
+ * Release the space for the library list.
+ */
+ if (buffer != NULL)
+ kfree (buffer);
+ }
+/*
+ * Return the resulting status to the caller.
+ */
+ return (status);
+}
+
+/*
+ * This procedure is called by the main load sequence. It will load
+ * the executable and prepare it for execution. It provides the additional
+ * parameters used by the recursive coff loader and tells the loader that
+ * this is the main executable. How simple it is . . . .
+ */
+
+int
+load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
+{
+ return (load_object (bprm, regs, 1));
+}
+
+/*
+ * Load the image for any shared library.
+ *
+ * This is called when we need to load a library based upon a file name.
+ */
+
+int
+load_coff_library (int fd)
+{
+ struct linux_binprm *bprm; /* Parameters for the load operation */
+ int status; /* Status of the request */
+/*
+ * Read the first portion of the file.
+ */
+ bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
+ GFP_KERNEL);
+ if (0 == bprm) {
+#ifdef COFF_DEBUG
+ printk ("kmalloc failed\n");
+#endif
+ status = -ENOEXEC;
+ }
+ else {
+ struct file *file; /* Pointer to the file table */
+ struct pt_regs regs; /* Register work area */
+ int old_fs = get_fs (); /* Previous FS register value */
+
+ memset (bprm, '\0', sizeof (struct linux_binprm));
+
+ file = current->files->fd[fd];
+ bprm->inode = file->f_inode; /* The only item _really_ needed */
+ bprm->filename = ""; /* Make it a legal string */
+/*
+ * Read the section list from the disk file.
+ */
+ set_fs (get_ds ()); /* Make it point to the proper location */
+ status = read_exec (bprm->inode, /* INODE for file */
+ 0L, /* Offset in the file */
+ bprm->buf, /* Buffer for read */
+ sizeof (bprm->buf)); /* Size of the buffer */
+ set_fs (old_fs); /* Restore the selector */
+/*
+ * Try to load the library.
+ */
+ status = load_object (bprm, &regs, 0);
+/*
+ * Release the work buffer and return the result.
+ */
+ kfree (bprm); /* Release the buffer area */
+ }
+/*
+ * Return the result of the load operation
+ */
+ return (status);
+}
diff --git a/ibcs/binfmt_elf.c b/ibcs/binfmt_elf.c
new file mode 100644
index 000000000..1b33470cc
--- /dev/null
+++ b/ibcs/binfmt_elf.c
@@ -0,0 +1,656 @@
+/*
+ * linux/fs/binfmt_elf.c
+ *
+ * These are the functions used to load ELF format executables as used
+ * on SVr4 machines. Information on the format may be found in the book
+ * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
+ * Tools".
+ *
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/binfmts.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+
+#include <asm/segment.h>
+
+asmlinkage int sys_exit(int exit_code);
+asmlinkage int sys_close(unsigned fd);
+asmlinkage int sys_open(const char *, int, int);
+asmlinkage int sys_brk(unsigned long);
+
+#define DLINFO_ITEMS 8
+
+#include <linux/elf.h>
+
+/* We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). This would
+ contain the junk from the file that should not
+ be in memory */
+
+static void padzero(int elf_bss){
+ unsigned int fpnt, nbyte;
+
+ if(elf_bss & 0xfff) {
+
+ nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
+ if(nbyte){
+ verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
+
+ fpnt = elf_bss;
+ while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
+ };
+ };
+}
+
+unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
+{
+ unsigned long *argv,*envp, *dlinfo;
+ unsigned long * sp;
+ struct vm_area_struct *mpnt;
+
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+ if (mpnt) {
+ mpnt->vm_task = current;
+ mpnt->vm_start = PAGE_MASK & (unsigned long) p;
+ mpnt->vm_end = TASK_SIZE;
+ mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+ mpnt->vm_flags = VM_STACK_FLAGS;
+ mpnt->vm_share = NULL;
+ mpnt->vm_ops = NULL;
+ mpnt->vm_inode = NULL;
+ mpnt->vm_offset = 0;
+ mpnt->vm_pte = 0;
+ insert_vm_struct(current, mpnt);
+ }
+ sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
+ if(exec) sp -= DLINFO_ITEMS*2;
+ dlinfo = sp;
+ sp -= envc+1;
+ envp = sp;
+ sp -= argc+1;
+ argv = sp;
+ if (!ibcs) {
+ put_fs_long((unsigned long)envp,--sp);
+ put_fs_long((unsigned long)argv,--sp);
+ }
+
+ /* The constant numbers (0-9) that we are writing here are
+ described in the header file sys/auxv.h on at least
+ some versions of SVr4 */
+ if(exec) { /* Put this here for an ELF program interpreter */
+ struct elf_phdr * eppnt;
+ eppnt = (struct elf_phdr *) exec->e_phoff;
+ put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
+ put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
+ put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
+ put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
+ put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
+ put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
+ put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
+ put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
+ };
+
+ put_fs_long((unsigned long)argc,--sp);
+ current->mm->arg_start = (unsigned long) p;
+ while (argc-->0) {
+ put_fs_long((unsigned long) p,argv++);
+ while (get_fs_byte(p++)) /* nothing */ ;
+ }
+ put_fs_long(0,argv);
+ current->mm->arg_end = current->mm->env_start = (unsigned long) p;
+ while (envc-->0) {
+ put_fs_long((unsigned long) p,envp++);
+ while (get_fs_byte(p++)) /* nothing */ ;
+ }
+ put_fs_long(0,envp);
+ current->mm->env_end = (unsigned long) p;
+ return sp;
+}
+
+
+/* This is much more generalized than the library routine read function,
+ so we keep this separate. Technically the library read function
+ is only provided so that we can read a.out libraries that have
+ an ELF header */
+
+static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
+ struct inode * interpreter_inode)
+{
+ struct file * file;
+ struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *eppnt;
+ unsigned int len;
+ unsigned int load_addr;
+ int elf_exec_fileno;
+ int elf_bss;
+ int old_fs, retval;
+ unsigned int last_bss;
+ int error;
+ int i, k;
+
+ elf_bss = 0;
+ last_bss = 0;
+ error = load_addr = 0;
+
+ /* First of all, some simple consistency checks */
+ if((interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN) ||
+ (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
+ (!interpreter_inode->i_op ||
+ !interpreter_inode->i_op->default_file_ops->mmap)){
+ return 0xffffffff;
+ };
+
+ /* Now read in all of the header information */
+
+ if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
+ return 0xffffffff;
+
+ elf_phdata = (struct elf_phdr *)
+ kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
+ if(!elf_phdata) return 0xffffffff;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
+ sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
+ set_fs(old_fs);
+
+ elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+ if (elf_exec_fileno < 0) return 0xffffffff;
+ file = current->files->fd[elf_exec_fileno];
+
+ eppnt = elf_phdata;
+ for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ if(eppnt->p_type == PT_LOAD) {
+ error = do_mmap(file,
+ eppnt->p_vaddr & 0xfffff000,
+ eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
+ eppnt->p_offset & 0xfffff000);
+
+ if(!load_addr && interp_elf_ex->e_type == ET_DYN)
+ load_addr = error;
+ k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
+ if(k > elf_bss) elf_bss = k;
+ if(error < 0 && error > -1024) break; /* Real error */
+ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
+ if(k > last_bss) last_bss = k;
+ }
+
+ /* Now use mmap to map the library into memory. */
+
+
+ sys_close(elf_exec_fileno);
+ if(error < 0 && error > -1024) {
+ kfree(elf_phdata);
+ return 0xffffffff;
+ }
+
+ padzero(elf_bss);
+ len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
+
+ /* Map the last of the bss segment */
+ if (last_bss > len)
+ do_mmap(NULL, len, last_bss-len,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ kfree(elf_phdata);
+
+ return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
+}
+
+static unsigned int load_aout_interp(struct exec * interp_ex,
+ struct inode * interpreter_inode)
+{
+ int retval;
+ unsigned int elf_entry;
+
+ current->mm->brk = interp_ex->a_bss +
+ (current->mm->end_data = interp_ex->a_data +
+ (current->mm->end_code = interp_ex->a_text));
+ elf_entry = interp_ex->a_entry;
+
+
+ if (N_MAGIC(*interp_ex) == OMAGIC) {
+ do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode, 32, (char *) 0,
+ interp_ex->a_text+interp_ex->a_data);
+ } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
+ do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode,
+ N_TXTOFF(*interp_ex) ,
+ (char *) N_TXTADDR(*interp_ex),
+ interp_ex->a_text+interp_ex->a_data);
+ } else
+ retval = -1;
+
+ if(retval >= 0)
+ do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) &
+ 0xfffff000, interp_ex->a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ if(retval < 0) return 0xffffffff;
+ return elf_entry;
+}
+
+/*
+ * These are the functions used to load ELF style executables and shared
+ * libraries. There is no binary dependent code anywhere else.
+ */
+
+#define INTERPRETER_NONE 0
+#define INTERPRETER_AOUT 1
+#define INTERPRETER_ELF 2
+
+static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
+{
+ struct elfhdr elf_ex;
+ struct elfhdr interp_elf_ex;
+ struct file * file;
+ struct exec interp_ex;
+ struct inode *interpreter_inode;
+ unsigned int load_addr;
+ unsigned int interpreter_type = INTERPRETER_NONE;
+ int i;
+ int old_fs;
+ int error;
+ struct elf_phdr * elf_ppnt, *elf_phdata;
+ int elf_exec_fileno;
+ unsigned int elf_bss, k, elf_brk;
+ int retval;
+ char * elf_interpreter;
+ unsigned int elf_entry;
+ int status;
+ unsigned int start_code, end_code, end_data;
+ unsigned int elf_stack;
+ char passed_fileno[6];
+
+ status = 0;
+ load_addr = 0;
+ elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
+
+ if (elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+ return -ENOEXEC;
+
+
+ /* First of all, some simple consistency checks */
+ if(elf_ex.e_type != ET_EXEC ||
+ (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
+ (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
+ !bprm->inode->i_op->default_file_ops->mmap)){
+ return -ENOEXEC;
+ };
+
+ /* Now read in all of the header information */
+
+ elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
+ elf_ex.e_phnum, GFP_KERNEL);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+ elf_ex.e_phentsize * elf_ex.e_phnum);
+ set_fs(old_fs);
+ if (retval < 0) {
+ kfree (elf_phdata);
+ return retval;
+ }
+
+ elf_ppnt = elf_phdata;
+
+ elf_bss = 0;
+ elf_brk = 0;
+
+ elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+
+ if (elf_exec_fileno < 0) {
+ kfree (elf_phdata);
+ return elf_exec_fileno;
+ }
+
+ file = current->files->fd[elf_exec_fileno];
+
+ elf_stack = 0xffffffff;
+ elf_interpreter = NULL;
+ start_code = 0;
+ end_code = 0;
+ end_data = 0;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
+ for(i=0;i < elf_ex.e_phnum; i++){
+ if(elf_ppnt->p_type == PT_INTERP) {
+ /* This is the program interpreter used for shared libraries -
+ for now assume that this is an a.out format binary */
+
+ elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
+ GFP_KERNEL);
+
+ retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
+ elf_ppnt->p_filesz);
+#if 0
+ printk("Using ELF interpreter %s\n", elf_interpreter);
+#endif
+ if(retval >= 0)
+ retval = namei(elf_interpreter, &interpreter_inode);
+ if(retval >= 0)
+ retval = read_exec(interpreter_inode,0,bprm->buf,128);
+
+ if(retval >= 0){
+ interp_ex = *((struct exec *) bprm->buf); /* exec-header */
+ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
+
+ };
+ if(retval < 0) {
+ kfree (elf_phdata);
+ kfree(elf_interpreter);
+ return retval;
+ };
+ };
+ elf_ppnt++;
+ };
+
+ set_fs(old_fs);
+
+ /* Some simple consistency checks for the interpreter */
+ if(elf_interpreter){
+ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+ if(retval < 0) {
+ kfree(elf_interpreter);
+ kfree(elf_phdata);
+ return -ELIBACC;
+ };
+ /* Now figure out which format our binary is */
+ if((N_MAGIC(interp_ex) != OMAGIC) &&
+ (N_MAGIC(interp_ex) != ZMAGIC) &&
+ (N_MAGIC(interp_ex) != QMAGIC))
+ interpreter_type = INTERPRETER_ELF;
+
+ if (interp_elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
+ interpreter_type &= ~INTERPRETER_ELF;
+
+ if(!interpreter_type)
+ {
+ kfree(elf_interpreter);
+ kfree(elf_phdata);
+ return -ELIBBAD;
+ };
+ }
+
+ /* OK, we are done with that, now set up the arg stuff,
+ and then start this sucker up */
+
+ if (!bprm->sh_bang) {
+ char * passed_p;
+
+ if(interpreter_type == INTERPRETER_AOUT) {
+ sprintf(passed_fileno, "%d", elf_exec_fileno);
+ passed_p = passed_fileno;
+
+ if(elf_interpreter) {
+ bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
+ bprm->argc++;
+ };
+ };
+ if (!bprm->p) {
+ if(elf_interpreter) {
+ kfree(elf_interpreter);
+ }
+ kfree (elf_phdata);
+ return -E2BIG;
+ }
+ }
+
+ /* OK, This is the point of no return */
+ flush_old_exec(bprm);
+
+ current->mm->end_data = 0;
+ current->mm->end_code = 0;
+ current->mm->start_mmap = ELF_START_MMAP;
+ current->mm->mmap = NULL;
+ elf_entry = (unsigned int) elf_ex.e_entry;
+
+ /* Do this so that we can load the interpreter, if need be. We will
+ change some of these later */
+ current->mm->rss = 0;
+ bprm->p += change_ldt(0, bprm->page);
+ current->mm->start_stack = bprm->p;
+
+ /* Now we do a little grungy work by mmaping the ELF image into
+ the correct location in memory. At this point, we assume that
+ the image should be loaded at fixed address, not at a variable
+ address. */
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
+ elf_ppnt = elf_phdata;
+ for(i=0;i < elf_ex.e_phnum; i++){
+
+ if(elf_ppnt->p_type == PT_INTERP) {
+ /* Set these up so that we are able to load the interpreter */
+ /* Now load the interpreter into user address space */
+ set_fs(old_fs);
+
+ if(interpreter_type & 1) elf_entry =
+ load_aout_interp(&interp_ex, interpreter_inode);
+
+ if(interpreter_type & 2) elf_entry =
+ load_elf_interp(&interp_elf_ex, interpreter_inode);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
+ iput(interpreter_inode);
+ kfree(elf_interpreter);
+
+ if(elf_entry == 0xffffffff) {
+ printk("Unable to load interpreter\n");
+ kfree(elf_phdata);
+ send_sig(SIGSEGV, current, 0);
+ return 0;
+ };
+ };
+
+
+ if(elf_ppnt->p_type == PT_LOAD) {
+ error = do_mmap(file,
+ elf_ppnt->p_vaddr & 0xfffff000,
+ elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE,
+ elf_ppnt->p_offset & 0xfffff000);
+
+#ifdef LOW_ELF_STACK
+ if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack)
+ elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
+#endif
+
+ if(!load_addr)
+ load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
+ k = elf_ppnt->p_vaddr;
+ if(k > start_code) start_code = k;
+ k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+ if(k > elf_bss) elf_bss = k;
+ if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k)
+ end_code = k;
+ if(end_data < k) end_data = k;
+ k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
+ if(k > elf_brk) elf_brk = k;
+ };
+ elf_ppnt++;
+ };
+ set_fs(old_fs);
+
+ kfree(elf_phdata);
+
+ if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
+
+ /* The following 3 lines need a little bit of work if we are loading
+ an iBCS2 binary. We should initially load it this way, and if
+ we get a lcall7, then we should look to see if the iBCS2 execution
+ profile is present. If it is, then switch to that, otherwise
+ bomb. */
+ current->personality = PER_LINUX;
+ current->lcall7 = no_lcall7;
+ current->signal_map = current->signal_invmap = ident_map;
+
+ current->executable = bprm->inode;
+ bprm->inode->i_count++;
+#ifdef LOW_ELF_STACK
+ current->start_stack = p = elf_stack - 4;
+#endif
+ bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
+ bprm->p = (unsigned long)
+ create_elf_tables((char *)bprm->p,
+ bprm->argc,
+ bprm->envc,
+ (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
+ load_addr,
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+ if(interpreter_type == INTERPRETER_AOUT)
+ current->mm->arg_start += strlen(passed_fileno) + 1;
+ current->mm->start_brk = current->mm->brk = elf_brk;
+ current->mm->end_code = end_code;
+ current->mm->start_code = start_code;
+ current->mm->end_data = end_data;
+ current->mm->start_stack = bprm->p;
+ current->suid = current->euid = bprm->e_uid;
+ current->sgid = current->egid = bprm->e_gid;
+
+ /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
+ sections */
+ current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
+ sys_brk((elf_brk + 0xfff) & 0xfffff000);
+
+ padzero(elf_bss);
+
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, 0);
+
+ regs->eip = elf_entry; /* eip, magic happens :-) */
+ regs->esp = bprm->p; /* stack pointer */
+ if (current->flags & PF_PTRACED)
+ send_sig(SIGTRAP, current, 0);
+ return 0;
+}
+
+/* This is really simpleminded and specialized - we are loading an
+ a.out library that is given an ELF header. */
+
+static int load_elf_library(int fd){
+ struct file * file;
+ struct elfhdr elf_ex;
+ struct elf_phdr *elf_phdata = NULL;
+ struct inode * inode;
+ unsigned int len;
+ int elf_bss;
+ int old_fs, retval;
+ unsigned int bss;
+ int error;
+ int i,j, k;
+
+ len = 0;
+ file = current->files->fd[fd];
+ inode = file->f_inode;
+ elf_bss = 0;
+
+ set_fs(KERNEL_DS);
+ if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
+ sys_close(fd);
+ return -EACCES;
+ }
+ set_fs(USER_DS);
+
+ if (elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
+ return -ENOEXEC;
+
+ /* First of all, some simple consistency checks */
+ if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+ (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
+ (!inode->i_op ||
+ !inode->i_op->default_file_ops->mmap)){
+ return -ENOEXEC;
+ };
+
+ /* Now read in all of the header information */
+
+ if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+ return -ENOEXEC;
+
+ elf_phdata = (struct elf_phdr *)
+ kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+ sizeof(struct elf_phdr) * elf_ex.e_phnum);
+ set_fs(old_fs);
+
+ j = 0;
+ for(i=0; i<elf_ex.e_phnum; i++)
+ if((elf_phdata + i)->p_type == PT_LOAD) j++;
+
+ if(j != 1) {
+ kfree(elf_phdata);
+ return -ENOEXEC;
+ };
+
+ while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+
+ /* Now use mmap to map the library into memory. */
+ error = do_mmap(file,
+ elf_phdata->p_vaddr & 0xfffff000,
+ elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE,
+ elf_phdata->p_offset & 0xfffff000);
+
+ k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+ if(k > elf_bss) elf_bss = k;
+
+ sys_close(fd);
+ if (error != elf_phdata->p_vaddr & 0xfffff000) {
+ kfree(elf_phdata);
+ return error;
+ }
+
+ padzero(elf_bss);
+
+ len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
+ bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
+ if (bss > len)
+ do_mmap(NULL, len, bss-len,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ kfree(elf_phdata);
+ return 0;
+}
+
+struct linux_binfmt elf_format = { NULL, load_elf_binary, load_elf_library };
diff --git a/ibcs/emulate.c b/ibcs/emulate.c
new file mode 100644
index 000000000..dc3b3d576
--- /dev/null
+++ b/ibcs/emulate.c
@@ -0,0 +1,10 @@
+/*
+ * linux/abi/emulate.c
+ *
+ * Copyright (C) 1993 Linus Torvalds
+ */
+
+/*
+ * Yes, sir, this file is completely empty, waiting for some real code..
+ * I still copyright it, silly me.
+ */