summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2014-06-10 03:36:56 -0400
committerRich Felker <dalias@aerifal.cx>2014-06-10 03:36:56 -0400
commit64e32287f9d8a84217834bcc3387e9431cad9e4c (patch)
treeae9201f73be9e4257acf1e161782305d40578fac
parent246e752d9e7c472735444815163f0a22e5bc4161 (diff)
downloadmusl-64e32287f9d8a84217834bcc3387e9431cad9e4c.tar.gz
add thread-pointer support for pre-2.6 kernels on i386
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.
-rw-r--r--src/env/__init_tls.c13
-rw-r--r--src/thread/i386/__set_thread_area.s22
2 files changed, 22 insertions, 13 deletions
diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c
index 89d081ef..e1a2b614 100644
--- a/src/env/__init_tls.c
+++ b/src/env/__init_tls.c
@@ -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;
}
diff --git a/src/thread/i386/__set_thread_area.s b/src/thread/i386/__set_thread_area.s
index cccf1cd3..ad538151 100644
--- a/src/thread/i386/__set_thread_area.s
+++ b/src/thread/i386/__set_thread_area.s
@@ -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