Some powerpc machines can support 64k pages, enabled by the
CONFIG_64K_PAGES option in linux.

However, the uClibc dynamic loader won't currently work on these
machines, as it uses hard-coded values (PAGE_ALIGN, ADDR_ALIGN and
OFFS_ALIGN) in the ldso architecture-specific headers.  When running on
a kernel with 64k pages, ld.so tries to mmap with 4k-aligned addresses,
rather than 64k, so mmap fails with -EINVAL.

When booting a 64k machine with a uClibc dynamic linker, init fails
with:

/init:500: can't map '/lib/libc.so.0'
/init:500: can't map '/lib/libc.so.0'
/init:500: can't map '/lib/libc.so.0'
/init: can't load library 'libc.so.0'
Kernel panic - not syncing: Attempted to kill init!

This change allows ld.so determine these alignment masks at runtime,
rather than compile-time. Since we have the _dl_pagesize variable
available, we can use that to generate the appropriate masks.

This allows me to start a uClibc-based root fs on a 64k machine.

Signed-off-by: Jeremy Kerr <[EMAIL PROTECTED]>

---

 ldso/ldso/dl-elf.c |   39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)

Index: uClibc/ldso/ldso/dl-elf.c
===================================================================
--- uClibc.orig/ldso/ldso/dl-elf.c      2008-11-25 20:19:19.000000000 +1100
+++ uClibc/ldso/ldso/dl-elf.c   2008-11-25 20:22:26.000000000 +1100
@@ -336,6 +336,7 @@ struct elf_resolve *_dl_load_elf_shared_
        unsigned long dynamic_info[DYNAMIC_SIZE];
        unsigned long *lpnt;
        unsigned long libaddr;
+       unsigned long page_align, addr_align, offs_align;
        unsigned long minvma = 0xffffffff, maxvma = 0;
        int i, flags, piclib, infile;
        ElfW(Addr) relro_addr = 0;
@@ -442,7 +443,11 @@ struct elf_resolve *_dl_load_elf_shared_
 
        DL_CHECK_LIB_TYPE (epnt, piclib, _dl_progname, libname);
 
-       maxvma = (maxvma + ADDR_ALIGN) & ~ADDR_ALIGN;
+       addr_align = _dl_pagesize - 1;
+       page_align = ~addr_align;
+       offs_align = page_align & ~(1 << 31);
+
+       maxvma = (maxvma + addr_align) & ~addr_align;
        minvma = minvma & ~0xffffU;
 
        flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ;
@@ -517,15 +522,15 @@ struct elf_resolve *_dl_load_elf_shared_
                                       aligned pages:
 
                                    ((ppnt->p_vaddr + ppnt->p_filesz
-                                     + ADDR_ALIGN)
-                                    & PAGE_ALIGN)
+                                     + addr_align)
+                                    & page_align)
                                    < ppnt->p_vaddr + ppnt->p_memsz)
 
                                       Instead, we have to do this:  */
                                    ppnt->p_filesz < ppnt->p_memsz)
                                  {
                                    piclib2map = (char *)
-                                     _dl_mmap(0, (ppnt->p_vaddr & ADDR_ALIGN)
+                                     _dl_mmap(0, (ppnt->p_vaddr & addr_align)
                                               + ppnt->p_memsz,
                                               LXFLAGS(ppnt->p_flags),
                                               flags | MAP_ANONYMOUS, -1, 0);
@@ -533,14 +538,14 @@ struct elf_resolve *_dl_load_elf_shared_
                                      goto cant_map;
                                    DL_INIT_LOADADDR_HDR
                                      (lib_loadaddr, piclib2map
-                                      + (ppnt->p_vaddr & ADDR_ALIGN), ppnt);
+                                      + (ppnt->p_vaddr & addr_align), ppnt);
                                  }
 
                                tryaddr = piclib == 2 ? piclib2map
                                  : ((char*) (piclib ? libaddr : 0) +
-                                    (ppnt->p_vaddr & PAGE_ALIGN));
+                                    (ppnt->p_vaddr & page_align));
 
-                               size = (ppnt->p_vaddr & ADDR_ALIGN)
+                               size = (ppnt->p_vaddr & addr_align)
                                  + ppnt->p_filesz;
 
                                /* For !MMU, mmap to fixed address will fail.
@@ -553,7 +558,7 @@ struct elf_resolve *_dl_load_elf_shared_
                                  status = (char *) _dl_mmap
                                    (tryaddr, size, LXFLAGS(ppnt->p_flags),
                                     flags | (piclib2map ? MAP_FIXED : 0),
-                                    infile, ppnt->p_offset & OFFS_ALIGN);
+                                    infile, ppnt->p_offset & offs_align);
 #ifndef __ARCH_USE_MMU__
                                else
                                  status = MAP_FAILED;
@@ -561,7 +566,7 @@ struct elf_resolve *_dl_load_elf_shared_
 #ifdef _DL_PREAD
                                if (_dl_mmap_check_error(status) && piclib2map
                                    && (_DL_PREAD (infile, tryaddr, size,
-                                                  ppnt->p_offset & OFFS_ALIGN)
+                                                  ppnt->p_offset & offs_align)
                                        == size))
                                  status = tryaddr;
 #endif
@@ -580,7 +585,7 @@ struct elf_resolve *_dl_load_elf_shared_
                                if (! piclib2map) {
                                  DL_INIT_LOADADDR_HDR
                                    (lib_loadaddr, status
-                                    + (ppnt->p_vaddr & ADDR_ALIGN), ppnt);
+                                    + (ppnt->p_vaddr & addr_align), ppnt);
                                }
                                /* Now we want to allocate and
                                   zero-out any data from the end of
@@ -608,7 +613,7 @@ struct elf_resolve *_dl_load_elf_shared_
                                /* MAP_SIZE is the address of the
                                   beginning of the next page.  */
                                map_size = (ppnt->p_vaddr + ppnt->p_filesz
-                                           + ADDR_ALIGN) & PAGE_ALIGN;
+                                           + addr_align) & page_align;
 
 #ifndef MIN
 # define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -632,20 +637,20 @@ struct elf_resolve *_dl_load_elf_shared_
                                }
                        } else {
                                tryaddr = (piclib == 2 ? 0
-                                          : (char *) (ppnt->p_vaddr & 
PAGE_ALIGN)
+                                          : (char *) (ppnt->p_vaddr & 
page_align)
                                           + (piclib ? libaddr : 0));
-                               size = (ppnt->p_vaddr & ADDR_ALIGN) + 
ppnt->p_filesz;
+                               size = (ppnt->p_vaddr & addr_align) + 
ppnt->p_filesz;
                                status = (char *) _dl_mmap
                                           (tryaddr, size, 
LXFLAGS(ppnt->p_flags),
                                            flags | (piclib == 2 ? 
MAP_EXECUTABLE
                                                     | MAP_DENYWRITE : 0),
-                                           infile, ppnt->p_offset & 
OFFS_ALIGN);
+                                           infile, ppnt->p_offset & 
offs_align);
                                if (_dl_mmap_check_error(status)
                                    || (tryaddr && tryaddr != status))
                                  goto cant_map;
                                DL_INIT_LOADADDR_HDR
                                  (lib_loadaddr, status
-                                  + (ppnt->p_vaddr & ADDR_ALIGN), ppnt);
+                                  + (ppnt->p_vaddr & addr_align), ppnt);
                        }
 
                        /* if (libaddr == 0 && piclib) {
@@ -690,8 +695,8 @@ struct elf_resolve *_dl_load_elf_shared_
                for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
                        if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
                                _dl_mprotect((void *) ((piclib ? libaddr : 0) +
-                                                       (ppnt->p_vaddr & 
PAGE_ALIGN)),
-                                               (ppnt->p_vaddr & ADDR_ALIGN) + 
(unsigned long) ppnt->p_filesz,
+                                                       (ppnt->p_vaddr & 
page_align)),
+                                               (ppnt->p_vaddr & addr_align) + 
(unsigned long) ppnt->p_filesz,
                                                PROT_READ | PROT_WRITE | 
PROT_EXEC);
                }
 #else
_______________________________________________
uClibc mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/uclibc

Reply via email to