patch-1.3.5 linux/arch/i386/ibcs/binfmt_coff.c
Next file: linux/arch/i386/ibcs/binfmt_elf.c
Previous file: linux/arch/i386/ibcs/Makefile
Back to the patch index
Back to the overall index
- Lines: 785
- Date:
Thu Jan 1 02:00:00 1970
- Orig file:
v1.3.4/linux/arch/i386/ibcs/binfmt_coff.c
- Orig date:
Tue Nov 22 15:40:12 1994
diff -u --recursive --new-file v1.3.4/linux/arch/i386/ibcs/binfmt_coff.c linux/arch/i386/ibcs/binfmt_coff.c
@@ -1,784 +0,0 @@
-/*
- * 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, ®s, 0);
-/*
- * Release the work buffer and return the result.
- */
- kfree (bprm); /* Release the buffer area */
- }
-/*
- * Return the result of the load operation
- */
- return (status);
-}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this