📄 irixelf.c
字号:
/* * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * Based upon work which is: * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). */#include <linux/module.h>#include <linux/fs.h>#include <linux/stat.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/mman.h>#include <linux/a.out.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/signal.h>#include <linux/binfmts.h>#include <linux/string.h>#include <linux/file.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/shm.h>#include <linux/personality.h>#include <linux/elfcore.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <asm/pgalloc.h>#include <asm/mipsregs.h>#include <asm/prctl.h>#define DLINFO_ITEMS 12#include <linux/elf.h>#undef DEBUG_ELFstatic int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);static int load_irix_library(struct file *);static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file);extern int dump_fpu (elf_fpregset_t *);static struct linux_binfmt irix_format = { NULL, THIS_MODULE, load_irix_binary, load_irix_library, irix_core_dump, PAGE_SIZE};#ifndef elf_addr_t#define elf_addr_t unsigned long#define elf_caddr_t char *#endif#ifdef DEBUG_ELF/* Debugging routines. */static char *get_elf_p_type(Elf32_Word p_type){ int i = (int) p_type; switch(i) { case PT_NULL: return("PT_NULL"); break; case PT_LOAD: return("PT_LOAD"); break; case PT_DYNAMIC: return("PT_DYNAMIC"); break; case PT_INTERP: return("PT_INTERP"); break; case PT_NOTE: return("PT_NOTE"); break; case PT_SHLIB: return("PT_SHLIB"); break; case PT_PHDR: return("PT_PHDR"); break; case PT_LOPROC: return("PT_LOPROC/REGINFO"); break; case PT_HIPROC: return("PT_HIPROC"); break; default: return("PT_BOGUS"); break; }}static void print_elfhdr(struct elfhdr *ehp){ int i; printk("ELFHDR: e_ident<"); for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]); printk("%x>\n", ehp->e_ident[i]); printk(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n", (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine, (unsigned long) ehp->e_version); printk(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] " "e_flags[%08lx]\n", (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff, (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags); printk(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n", (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize, (unsigned short) ehp->e_phnum); printk(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n", (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum, (unsigned short) ehp->e_shstrndx);}static void print_phdr(int i, struct elf_phdr *ep){ printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] " "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type), (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr, (unsigned long) ep->p_paddr); printk(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] " "p_align[%08lx]\n", (unsigned long) ep->p_filesz, (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags, (unsigned long) ep->p_align);}static void dump_phdrs(struct elf_phdr *ep, int pnum){ int i; for(i = 0; i < pnum; i++, ep++) { if((ep->p_type == PT_LOAD) || (ep->p_type == PT_INTERP) || (ep->p_type == PT_PHDR)) print_phdr(i, ep); }}#endif /* (DEBUG_ELF) */static void set_brk(unsigned long start, unsigned long end){ start = PAGE_ALIGN(start); end = PAGE_ALIGN(end); if (end <= start) return; do_brk(start, end - start);}/* 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(unsigned long elf_bss){ unsigned long nbyte; nbyte = elf_bss & (PAGE_SIZE-1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; clear_user((void *) elf_bss, nbyte); }}unsigned long * create_irix_tables(char * p, int argc, int envc, struct elfhdr * exec, unsigned int load_addr, unsigned int interp_load_addr, struct pt_regs *regs, struct elf_phdr *ephdr){ elf_caddr_t *argv; elf_caddr_t *envp; elf_addr_t *sp, *csp; #ifdef DEBUG_ELF printk("create_irix_tables: p[%p] argc[%d] envc[%d] " "load_addr[%08x] interp_load_addr[%08x]\n", p, argc, envc, load_addr, interp_load_addr);#endif sp = (elf_addr_t *) (~15UL & (unsigned long) p); csp = sp; csp -= exec ? DLINFO_ITEMS*2 : 2; csp -= envc+1; csp -= argc+1; csp -= 1; /* argc itself */ if ((unsigned long)csp & 15UL) { sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp); } /* * Put the ELF interpreter info on the stack */#define NEW_AUX_ENT(nr, id, val) \ __put_user ((id), sp+(nr*2)); \ __put_user ((val), sp+(nr*2+1)); \ sp -= 2; NEW_AUX_ENT(0, AT_NULL, 0); if(exec) { sp -= 11*2; NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); NEW_AUX_ENT (1, AT_PHENT, sizeof (struct elf_phdr)); NEW_AUX_ENT (2, AT_PHNUM, exec->e_phnum); NEW_AUX_ENT (3, AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT (4, AT_BASE, interp_load_addr); NEW_AUX_ENT (5, AT_FLAGS, 0); NEW_AUX_ENT (6, AT_ENTRY, (elf_addr_t) exec->e_entry); NEW_AUX_ENT (7, AT_UID, (elf_addr_t) current->uid); NEW_AUX_ENT (8, AT_EUID, (elf_addr_t) current->euid); NEW_AUX_ENT (9, AT_GID, (elf_addr_t) current->gid); NEW_AUX_ENT (10, AT_EGID, (elf_addr_t) current->egid); }#undef NEW_AUX_ENT sp -= envc+1; envp = (elf_caddr_t *) sp; sp -= argc+1; argv = (elf_caddr_t *) sp; __put_user((elf_addr_t)argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); p += strlen_user(p); } __put_user(NULL, argv); current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); p += strlen_user(p); } __put_user(NULL, 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_irix_interp(struct elfhdr * interp_elf_ex, struct file * interpreter, unsigned int *interp_load_addr){ struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; unsigned int len; unsigned int load_addr; int elf_bss; int retval; unsigned int last_bss; int error; int i; unsigned int k; elf_bss = 0; last_bss = 0; error = load_addr = 0; #ifdef DEBUG_ELF print_elfhdr(interp_elf_ex);#endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !irix_elf_check_arch(interp_elf_ex) || !interpreter->f_op->mmap) { printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; } /* Now read in all of the header information */ if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { printk("IRIX interp header bigger than a page (%d)\n", (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum)); return 0xffffffff; } elf_phdata = (struct elf_phdr *) kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); if(!elf_phdata) { printk("Cannot kmalloc phdata for IRIX interp.\n"); return 0xffffffff; } /* If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ if(interp_elf_ex->e_phentsize != 32) { printk("IRIX interp e_phentsize == %d != 32 ", interp_elf_ex->e_phentsize); kfree(elf_phdata); return 0xffffffff; } retval = kernel_read(interpreter, interp_elf_ex->e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);#ifdef DEBUG_ELF dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);#endif eppnt = elf_phdata; for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) { if(eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; unsigned long vaddr = 0; if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr;#ifdef DEBUG_ELF printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", interpreter, vaddr, (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), (unsigned long) elf_prot, (unsigned long) elf_type, (unsigned long) (eppnt->p_offset & 0xfffff000));#endif down(¤t->mm->mmap_sem); error = do_mmap(interpreter, vaddr, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), elf_prot, elf_type, eppnt->p_offset & 0xfffff000); up(¤t->mm->mmap_sem); if(error < 0 && error > -1024) { printk("Aieee IRIX interp mmap error=%d\n", error); break; /* Real error */ }#ifdef DEBUG_ELF printk("error=%08lx ", (unsigned long) error);#endif if(!load_addr && interp_elf_ex->e_type == ET_DYN) { load_addr = error;#ifdef DEBUG_ELF printk("load_addr = error ");#endif } /* Find the end of the file mapping for this phdr, and keep * track of the largest address we see for this. */ k = eppnt->p_vaddr + eppnt->p_filesz; if(k > elf_bss) elf_bss = k; /* Do the same thing for the memory mapping - between * elf_bss and last_bss is the bss section. */ k = eppnt->p_memsz + eppnt->p_vaddr; if(k > last_bss) last_bss = k;#ifdef DEBUG_ELF printk("\n");#endif } } /* Now use mmap to map the library into memory. */ if(error < 0 && error > -1024) {#ifdef DEBUG_ELF printk("got error %d\n", error);#endif kfree(elf_phdata); return 0xffffffff; } /* Now fill out the bss section. First pad the last page up * to the page boundary, and then perform a mmap to make sure * that there are zero-mapped pages up to and including the * last bss page. */#ifdef DEBUG_ELF printk("padzero(%08lx) ", (unsigned long) (elf_bss));#endif padzero(elf_bss); len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */#ifdef DEBUG_ELF printk("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss, (unsigned long) len);#endif /* Map the last of the bss segment */ if (last_bss > len) { do_brk(len, (last_bss - len)); } kfree(elf_phdata); *interp_load_addr = load_addr; return ((unsigned int) interp_elf_ex->e_entry);}/* Check sanity of IRIX elf executable header. */static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm){ if (memcmp(ehp->e_ident, ELFMAG, SELFMAG) != 0) return -ENOEXEC; /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || !irix_elf_check_arch(ehp) || !bprm->file->f_op->mmap) { return -ENOEXEC; } /* Only support MIPS ARCH2 or greater IRIX binaries for now. */ if(!(ehp->e_flags & EF_MIPS_ARCH) && !(ehp->e_flags & 0x04)) { return -ENOEXEC; } /* XXX Don't support N32 or 64bit binaries yet because they can * XXX and do execute 64 bit instructions and expect all registers * XXX to be 64 bit as well. We need to make the kernel save * XXX all registers as 64bits on cpu's capable of this at * XXX exception time plus frob the XTLB exception vector. */ if((ehp->e_flags & 0x20)) { return -ENOEXEC; } return 0; /* It's ok. */}#define IRIX_INTERP_PREFIX "/usr/gnemul/irix"/* Look for an IRIX ELF interpreter. */static inline int look_for_irix_interpreter(char **name, struct file **interpreter, struct elfhdr *interp_elf_ex, struct elf_phdr *epp, struct linux_binprm *bprm, int pnum){ int i; int retval = -EINVAL; struct file *file = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -