⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irixelf.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * irixelf.c: Code to load IRIX ELF executables conforming to the MIPS ABI. *            Based off of work by Eric Youngdale. * * Copyright (C) 1993 - 1994 Eric Youngdale <ericy@cais.com> * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com> * Copyright (C) 2004 - 2005 Steven J. Hill <sjhill@realitydiluted.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/slab.h>#include <linux/shm.h>#include <linux/personality.h>#include <linux/elfcore.h>#include <linux/smp_lock.h>#include <asm/mipsregs.h>#include <asm/namei.h>#include <asm/prctl.h>#include <asm/uaccess.h>#define DLINFO_ITEMS 12#include <linux/elf.h>#undef DEBUGstatic 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);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#endif#ifdef DEBUG/* 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 */static void set_brk(unsigned long start, unsigned long end){	start = PAGE_ALIGN(start);	end = PAGE_ALIGN(end);	if (end <= start)		return;	down_write(&current->mm->mmap_sem);	do_brk(start, end - start);	up_write(&current->mm->mmap_sem);}/* 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 __user *) elf_bss, nbyte);	}}static 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_addr_t *argv;	elf_addr_t *envp;	elf_addr_t *sp, *csp;#ifdef DEBUG	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 = sp;	sp -= argc+1;	argv = sp;	__put_user((elf_addr_t)argc,--sp);	current->mm->arg_start = (unsigned long) p;	while (argc-->0) {		__put_user((unsigned long)p,argv++);		p += strlen_user(p);	}	__put_user((unsigned long) NULL, argv);	current->mm->arg_end = current->mm->env_start = (unsigned long) p;	while (envc-->0) {		__put_user((unsigned long)p,envp++);		p += strlen_user(p);	}	__put_user((unsigned long) 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	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) ||	     !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 = 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	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;	    pr_debug("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));	    down_write(&current->mm->mmap_sem);	    error = do_mmap(interpreter, vaddr,			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),			    elf_prot, elf_type,			    eppnt->p_offset & 0xfffff000);	    up_write(&current->mm->mmap_sem);	    if(error < 0 && error > -1024) {		    printk("Aieee IRIX interp mmap error=%d\n", error);		    break;  /* Real error */	    }	    pr_debug("error=%08lx ", (unsigned long) error);	    if(!load_addr && interp_elf_ex->e_type == ET_DYN) {	      load_addr = error;              pr_debug("load_addr = error ");	    }	    /* 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;	    pr_debug("\n");	  }	}	/* Now use mmap to map the library into memory. */	if(error < 0 && error > -1024) {		pr_debug("got error %d\n", error);		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.	 */	pr_debug("padzero(%08lx) ", (unsigned long) (elf_bss));	padzero(elf_bss);	len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */	pr_debug("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss,	         (unsigned long) len);	/* Map the last of the bss segment */	if (last_bss > len) {		down_write(&current->mm->mmap_sem);		do_brk(len, (last_bss - len));		up_write(&current->mm->mmap_sem);	}	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) ||	    !bprm->file->f_op->mmap) {		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 & EF_MIPS_ABI2))		return -ENOEXEC;	return 0;}/* * This is where the detailed check is performed. Irix binaries * use interpreters with 'libc.so' in the name, so this function * can differentiate between Linux and Irix binaries. */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;	*name = NULL;	for(i = 0; i < pnum; i++, epp++) {		if (epp->p_type != PT_INTERP)			continue;		/* It is illegal to have two interpreters for one executable. */		if (*name != NULL)			goto out;		*name = kmalloc(epp->p_filesz + strlen(IRIX_EMUL), GFP_KERNEL);		if (!*name)			return -ENOMEM;		strcpy(*name, IRIX_EMUL);		retval = kernel_read(bprm->file, epp->p_offset, (*name + 16),		                     epp->p_filesz);		if (retval < 0)			goto out;		file = open_exec(*name);		if (IS_ERR(file)) {			retval = PTR_ERR(file);			goto out;		}		retval = kernel_read(file, 0, bprm->buf, 128);		if (retval < 0)			goto dput_and_out;		*interp_elf_ex = *(struct elfhdr *) bprm->buf;	}	*interpreter = file;	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -