add thread-pointer support for pre-2.6 kernels on i386
authorRich Felker <dalias@aerifal.cx>
Tue, 10 Jun 2014 07:36:56 +0000 (03:36 -0400)
committerRich Felker <dalias@aerifal.cx>
Tue, 10 Jun 2014 07:36:56 +0000 (03:36 -0400)
such kernels cannot support threads, but the thread pointer is also
important for other purposes, most notably stack protector. without a
valid thread pointer, all code compiled with stack protector will
crash. the same applies to any use of thread-local storage by
applications or libraries.

the concept of this patch is to fall back to using the modify_ldt
syscall, which has been around since linux 1.0, to setup the gs
segment register. since the kernel does not have a way to
automatically assign ldt entries, use of slot zero is hard-coded. if
this fallback path is used, __set_thread_area returns a positive value
(rather than the usual zero for success, or negative for error)
indicating to the caller that the thread pointer was successfully set,
but only for the main thread, and that thread creation will not work
properly. the code in __init_tp has been changed accordingly to record
this result for later use by pthread_create.

src/env/__init_tls.c
src/thread/i386/__set_thread_area.s

index 89d081ef50af32bcf7092012d033fe8664730ace..e1a2b614f57d2741d7b0f7160b6499596c197405 100644 (file)
@@ -11,17 +11,12 @@ int __init_tp(void *p)
 {
        pthread_t td = p;
        td->self = td;
-       if (__set_thread_area(TP_ADJ(p)) < 0)
-               return -1;
+       int r = __set_thread_area(TP_ADJ(p));
+       if (r < 0) return -1;
+       if (!r) libc.can_do_threads = 1;
+       libc.has_thread_pointer = 1;
        td->tid = td->pid = __syscall(SYS_set_tid_address, &td->tid);
        td->errno_ptr = &td->errno_val;
-       /* Currently, both of these predicates depend in the same thing:
-        * successful initialization of the thread pointer. However, in
-        * the future, we may support setups where setting the thread
-        * pointer is possible but threads other than the main thread
-        * cannot work, so it's best to keep the predicates separate. */
-       libc.has_thread_pointer = 1;
-       libc.can_do_threads = 1;
        return 0;
 }
 
index cccf1cd3dd751f2a1446d4f927a29aca4b992bbb..ad5381513804787fcd6969e8552c6904041425cb 100644 (file)
@@ -12,11 +12,25 @@ __set_thread_area:
        mov $243,%al
        int $128
        testl %eax,%eax
-       jnz 1f
-       movl (%esp),%ecx
-       leal 3(,%ecx,8),%ecx
-       movw %cx,%gs
+       jnz 2f
+       movl (%esp),%edx
+       leal 3(,%edx,8),%edx
+3:     movw %dx,%gs
 1:
        addl $16,%esp
        popl %ebx
        ret
+2:
+       mov %ebx,%ecx
+       xor %ebx,%ebx
+       xor %edx,%edx
+       mov %ebx,(%esp)
+       mov $1,%bl
+       mov $16,%dl
+       mov $123,%al
+       int $128
+       testl %eax,%eax
+       jnz 1b
+       mov $7,%dl
+       inc %al
+       jmp 3b