[PATCH] update for binfmt_elf.c

From: David Mosberger (davidm@hpl.hp.com)
Date: Fri Jul 14 2000 - 17:22:44 EST


Here is a patch that is makes fs/binfmt_elf.c more careful in
distinguishing betweeen the ELF executable "page size" and the Linux
kernel's page size. So far, binfmt_elf.c always aligned everything
according to ELF_EXEC_PAGESIZE, but this doesn't work right if the ELF
executable's page size is smaller than the host's page size. This
happens, for example, when loading an IA-32 binary on an IA-64 host
with a page size >4KB. Of course, it's not possible to use the normal
mmap() in this case either. Thus, the patch also provides the means
to use an alternate mapping function via macro "elf_map".

I believe this patch is safe for all platforms, but I'm not 100% sure,
so I thought it would be good to put it up for testing/discussion.

        --david

diff -urN linux-2.4.0-test4/fs/binfmt_elf.c linux-2.4.0-test4-lia/fs/binfmt_elf.c
--- linux-2.4.0-test4/fs/binfmt_elf.c Tue Jul 11 15:43:45 2000
+++ linux-2.4.0-test4-lia/fs/binfmt_elf.c Thu Jul 13 15:54:09 2000
@@ -41,6 +41,7 @@
 
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_elf_library(struct file*);
+static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
 extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
 extern void dump_thread(struct pt_regs *, struct user *);
 
@@ -59,9 +60,15 @@
 #define elf_core_dump NULL
 #endif
 
-#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-#define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
+#if ELF_EXEC_PAGESIZE > PAGE_SIZE
+# define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE
+#else
+# define ELF_MIN_ALIGN PAGE_SIZE
+#endif
+
+#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1))
+#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1))
+#define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
 
 static struct linux_binfmt elf_format = {
         NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
@@ -89,7 +96,7 @@
 
         nbyte = ELF_PAGEOFFSET(elf_bss);
         if (nbyte) {
- nbyte = ELF_EXEC_PAGESIZE - nbyte;
+ nbyte = ELF_MIN_ALIGN - nbyte;
                 clear_user((void *) elf_bss, nbyte);
         }
 }
@@ -198,6 +205,22 @@
         return sp;
 }
 
+#ifndef elf_map
+
+static inline unsigned long
+elf_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
+{
+ unsigned long map_addr;
+
+ down(&current->mm->mmap_sem);
+ map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+ eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
+ eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+ up(&current->mm->mmap_sem);
+ return(map_addr);
+}
+
+#endif /* !elf_map */
 
 /* This is much more generalized than the library routine read function,
    so we keep this separate. Technically the library read function
@@ -235,7 +258,7 @@
         /* Now read in all of the header information */
 
         size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
- if (size > ELF_EXEC_PAGESIZE)
+ if (size > ELF_MIN_ALIGN)
                 goto out;
         elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
         if (!elf_phdata)
@@ -261,16 +284,7 @@
             if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
                     elf_type |= MAP_FIXED;
 
- down(&current->mm->mmap_sem);
- map_addr = do_mmap(interpreter,
- load_addr + ELF_PAGESTART(vaddr),
- eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
- up(&current->mm->mmap_sem);
- if (map_addr > -1024UL) /* Real error */
- goto out_close;
+ map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
 
             if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
                 load_addr = map_addr - ELF_PAGESTART(vaddr);
@@ -304,7 +318,7 @@
          * last bss page.
          */
         padzero(elf_bss);
- elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */
+ elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */
 
         /* Map the last of the bss segment */
         if (last_bss > elf_bss)
@@ -356,7 +370,7 @@
         flush_icache_range((unsigned long)addr,
                            (unsigned long)addr + text_data);
 
- do_brk(ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1),
+ do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
                 interp_ex->a_bss);
         elf_entry = interp_ex->a_entry;
 
@@ -607,13 +635,7 @@
                         elf_flags |= MAP_FIXED;
                 }
 
- down(&current->mm->mmap_sem);
- error = do_mmap(bprm->file, ELF_PAGESTART(load_bias + vaddr),
- (elf_ppnt->p_filesz +
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot, elf_flags, (elf_ppnt->p_offset -
- ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
- up(&current->mm->mmap_sem);
+ error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
 
                 if (!load_addr_set) {
                         load_addr_set = 1;
@@ -785,7 +807,7 @@
         /* Now read in all of the header information */
 
         j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
- if (j > ELF_EXEC_PAGESIZE)
+ if (j > ELF_MIN_ALIGN)
                 goto out;
 
         error = -ENOMEM;
@@ -824,8 +846,7 @@
                 elf_bss = k;
         padzero(elf_bss);
 
- len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr +
- ELF_EXEC_PAGESIZE - 1);
+ len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
         bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
         if (bss > len)
                 do_brk(len, bss - len);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jul 15 2000 - 21:00:21 EST