Fixed TLS for statically-linked programs
authorAndrew Waterman <waterman@s143.Millennium.Berkeley.EDU>
Wed, 5 May 2010 09:58:27 +0000 (02:58 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:47 +0000 (17:35 -0700)
Basically, the kernel needs to communicate the program headers
to libc.  Not all ELFs include the program header in the memory-
resident image, so we might have to forcibly map it in.

kern/src/elf.c
tests/tlstest.c
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/init-first.c
tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros/start.c

index 5e241e4..8a3f936 100644 (file)
@@ -25,6 +25,8 @@ load_one_elf(struct proc* p, struct file* f, int pgoffset, elf_info_t* ei)
        ei->dynamic = 0;
        ei->highest_addr = 0;
 
+       // assume program headers fit in a page.
+       // if this isn't true, change the code below that maps in program headers
        char* elf = (char*)kmalloc(PGSIZE,0);
        if(!elf || file_read_page(f,PADDR(elf),0) == -1)
                goto fail;
@@ -88,6 +90,16 @@ load_one_elf(struct proc* p, struct file* f, int pgoffset, elf_info_t* ei)
                }
        }
 
+       // map in program headers anyway if not present in binary.
+       // useful for TLS in static programs.
+       if(ei->phdr == -1)
+       {
+               void* phdr_addr = do_mmap(p, 0, PGSIZE, PROT_READ, 0, f, 0);
+               if(phdr_addr == MAP_FAILED)
+                       goto fail;
+               ei->phdr = (long)phdr_addr + elfhdr->e_phoff;
+       }
+
        ei->entry = elfhdr->e_entry + pgoffset*PGSIZE;
        ei->phnum = elfhdr->e_phnum;
 
@@ -109,29 +121,29 @@ int load_elf(struct proc* p, struct file* f)
                if(interp == NULL || load_one_elf(p,interp,1,&interp_ei))
                        return -1;
                file_decref(interp);
-
-               // fill in info for dynamic linker
-               elf_aux_t auxp[] = {{ELF_AUX_PHDR,ei.phdr},
-                                   {ELF_AUX_PHENT,sizeof(proghdr_t)},
-                                   {ELF_AUX_PHNUM,ei.phnum},
-                                   {ELF_AUX_ENTRY,ei.entry},
-                                   #ifdef __sparc_v8__
-                                   {ELF_AUX_HWCAP,ELF_HWCAP_SPARC_FLUSH},
-                                   #endif
-                                   {0,0}};
-
-               // put auxp after argv, envp in procinfo
-               int auxp_pos = -1;
-               for(int i = 0, zeros = 0; i < PROCINFO_MAX_ARGP; i++)
-                       if(p->procinfo->argp[i] == NULL)
-                               if(++zeros == 2)
-                                       auxp_pos = i+1;
-               if(auxp_pos == -1 ||
-                  auxp_pos+sizeof(auxp)/sizeof(char*) >= PROCINFO_MAX_ARGP)
-                       return -1;
-               memcpy(p->procinfo->argp+auxp_pos,auxp,sizeof(auxp));
        }
 
+       // fill in auxiliary info for dynamic linker/runtime
+       elf_aux_t auxp[] = {{ELF_AUX_PHDR,ei.phdr},
+                           {ELF_AUX_PHENT,sizeof(proghdr_t)},
+                           {ELF_AUX_PHNUM,ei.phnum},
+                           {ELF_AUX_ENTRY,ei.entry},
+                           #ifdef __sparc_v8__
+                           {ELF_AUX_HWCAP,ELF_HWCAP_SPARC_FLUSH},
+                           #endif
+                           {0,0}};
+
+       // put auxp after argv, envp in procinfo
+       int auxp_pos = -1;
+       for(int i = 0, zeros = 0; i < PROCINFO_MAX_ARGP; i++)
+               if(p->procinfo->argp[i] == NULL)
+                       if(++zeros == 2)
+                               auxp_pos = i+1;
+       if(auxp_pos == -1 ||
+          auxp_pos+sizeof(auxp)/sizeof(char*) >= PROCINFO_MAX_ARGP)
+               return -1;
+       memcpy(p->procinfo->argp+auxp_pos,auxp,sizeof(auxp));
+
        uintptr_t core0_entry = ei.dynamic ? interp_ei.entry : ei.entry;
        proc_init_trapframe(&p->env_tf,0,core0_entry,USTACKTOP);
        p->env_entry = ei.entry;
index f47a5ba..72510a4 100644 (file)
@@ -1,11 +1,14 @@
+#include <assert.h>
 #include <rstdio.h>
 
+#define BAR0 0xdeadbeef
 volatile __thread int foo;
-volatile __thread int bar;
+volatile __thread int bar = BAR0;
 
 int main()
 {
        printf("&foo = %p, &bar = %p\n",&foo,&bar);
+       assert(bar == BAR0);
        bar = 0xcafebabe;
        printf("bar = %p\n",bar);
        return 0;
index f051282..6d9c5cd 100644 (file)
@@ -31,6 +31,7 @@
 #include <ldsodefs.h>
 #include <locale/localeinfo.h>
 #include <sys/time.h>
+#include <elf.h>
 
 /* Set nonzero if we have to be prepared for more then one libc being
    used in the process.  Safe assumption if initializer never runs.  */
@@ -79,6 +80,39 @@ _init (int argc, char **argv, char **envp)
   __environ = envp;
 
 #ifndef SHARED
+  extern ElfW(Phdr) *_dl_phdr;
+  extern size_t _dl_phnum;
+
+  void** auxp = envp;
+  while(*auxp)
+    auxp++;
+  ElfW(auxv_t) *av = (ElfW(auxv_t)*)(auxp+1);
+
+  for ( ; av->a_type != AT_NULL; av++)
+  {
+    switch (av->a_type)
+    {
+      case AT_PHDR:
+        _dl_phdr = (void *) av->a_un.a_val;
+        break;
+      case AT_PHNUM:
+        _dl_phnum = av->a_un.a_val;
+        break;
+      case AT_PAGESZ:
+        _dl_pagesize = av->a_un.a_val;
+        break;
+      case AT_ENTRY:
+        /* user_entry = av->a_un.a_val; */
+        break;
+      case AT_PLATFORM:
+        _dl_platform = (void *) av->a_un.a_val;
+        break;
+      case AT_HWCAP:
+        _dl_hwcap = (unsigned long int) av->a_un.a_val;
+        break;
+    }
+  }
+  
   __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
 
   __libc_init_secure ();
index 5db1f47..27f8b9c 100644 (file)
@@ -64,9 +64,14 @@ _start(void)
        char* argbuf = (char*)alloca(sizeof(__procinfo.argbuf));
        memcpy(argbuf,__procinfo.argbuf,sizeof(__procinfo.argbuf));
 
-       for(int i = 0; i < PROCINFO_MAX_ARGP; i++)
+       // touch up pointers, but don't mess up auxp!
+       for(int i = 0, zeros = 0; i < PROCINFO_MAX_ARGP; i++)
+       {
                if(argv[i])
                        argv[i] += argbuf - __procinfo.argbuf;
+               else if(++zeros == 2)
+                       break;
+       }
 
        int argc = 0;
        while(argv[argc])