mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-22 10:50:07 +00:00
Update.
* elf/rtld.c (_dl_start_final): Allocate TLS and initialize thread-pointer as soon as possible. * sysdeps/generic/ldsodefs.h: Include <tls.h>. Define first TLS elements in rtld_global. * sysdeps/generic/tls.h: New file. * elf/Makefile (distribute): Add tls.h. * sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS relocations. Not complete yet. * resolv/resolv.h: Allow user to define __need_res_state and only define __res_start structure then. * include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
This commit is contained in:
parent
67ddea9254
commit
535b764df5
13
ChangeLog
13
ChangeLog
@ -1,5 +1,18 @@
|
||||
2002-02-04 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* elf/rtld.c (_dl_start_final): Allocate TLS and initialize
|
||||
thread-pointer as soon as possible.
|
||||
* sysdeps/generic/ldsodefs.h: Include <tls.h>. Define first TLS
|
||||
elements in rtld_global.
|
||||
* sysdeps/generic/tls.h: New file.
|
||||
* elf/Makefile (distribute): Add tls.h.
|
||||
* sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS
|
||||
relocations. Not complete yet.
|
||||
|
||||
* resolv/resolv.h: Allow user to define __need_res_state and only
|
||||
define __res_start structure then.
|
||||
* include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
|
||||
|
||||
* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Move
|
||||
dl_cpuclock_offset initialization to _dl_start_final.
|
||||
(_dl_show_auxv): Avoid unnecessary sign extension.
|
||||
|
@ -67,7 +67,7 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
|
||||
reldep6mod4.c reldep6mod3.c reldep6mod2.c reldep6mod1.c \
|
||||
reldep6mod0.c \
|
||||
unwind-dw2.c unwind-dw2-fde.c unwind.h unwind-pe.h \
|
||||
unwind-dw2-fde.h dwarf2.h dl-procinfo.c
|
||||
unwind-dw2-fde.h dwarf2.h dl-procinfo.c tls.h
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
|
75
elf/rtld.c
75
elf/rtld.c
@ -218,6 +218,16 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
|
||||
which use `alloca'. */
|
||||
ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
|
||||
extern char _begin[], _end[];
|
||||
#ifdef USE_TLS
|
||||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Phdr) *phdr;
|
||||
size_t cnt;
|
||||
size_t tlssize = 0;
|
||||
size_t tlsimagesize = 0;
|
||||
const void *tlsimage = NULL;
|
||||
void *tlsblock = NULL;
|
||||
dtv_t initdtv[2];
|
||||
#endif
|
||||
|
||||
if (HP_TIMING_AVAIL)
|
||||
{
|
||||
@ -244,11 +254,76 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
|
||||
HP_TIMING_NOW (GL(dl_cpuclock_offset));
|
||||
#endif
|
||||
|
||||
#if USE_TLS
|
||||
/* Get the dynamic linkers program header. */
|
||||
ehdr = (ElfW(Ehdr) *) bootstrap_map_p->l_addr;
|
||||
phdr = (ElfW(Phdr) *) (bootstrap_map_p->l_addr + ehdr->e_phoff);
|
||||
for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
|
||||
if (phdr[cnt].p_type == PT_TLS)
|
||||
{
|
||||
size_t align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
|
||||
|
||||
tlssize = phdr[cnt].p_memsz;
|
||||
tlsimagesize = phdr[cnt].p_filesz;
|
||||
tlsimage = (void *) (bootstrap_map_p->l_addr + phdr[cnt].p_offset);
|
||||
|
||||
/* We can now allocate the initial TLS block. This can happen
|
||||
on the stack. We'll get the final memory later when we
|
||||
know all about the various objects loaded at startup
|
||||
time. */
|
||||
# if TLS_TCB_AT_TP
|
||||
tlsblock = alloca (roundup (tlssize, TLS_INIT_TCB_ALIGN)
|
||||
+ TLS_INIT_TCB_SIZE
|
||||
+ align);
|
||||
# elif TLS_DTV_AT_TP
|
||||
tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align)
|
||||
+ tlssize
|
||||
+ align);
|
||||
# else
|
||||
/* In case a model with a different layout for the TCB and DTV
|
||||
is defined add another #elif here and in the following #ifs. */
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
/* Align the TLS block. */
|
||||
tlsblock = (void *) (((uintptr_t) tlsblock + align - 1)
|
||||
& ~(align - 1));
|
||||
|
||||
/* Initialize the dtv. */
|
||||
initdtv[0].counter = 1;
|
||||
|
||||
/* Initialize the TLS block. */
|
||||
# if TLS_TCB_AT_TP
|
||||
initdtv[1].pointer = tlsblock;
|
||||
# elif TLS_DTV_AT_TP
|
||||
GL(rtld_tlsoffset) = roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align);
|
||||
initdtv[1].pointer = (char *) tlsblock + GL(rtld_tlsoffset);
|
||||
# else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
memset (__mempcpy (initdtv[1].pointer, tlsimage, tlsimagesize),
|
||||
'\0', tlssize - tlsimagesize);
|
||||
|
||||
/* Initialize the thread pointer. */
|
||||
# if TLS_TCB_AT_TP
|
||||
GL(rtld_tlsoffset) = roundup (tlssize, TLS_INIT_TCB_ALIGN);
|
||||
TLS_INIT_TP ((char *) tlsblock + GL(rtld_tlsoffset), initdtv);
|
||||
# elif TLS_DTV_AT_TP
|
||||
TLS_INIT_TP (tlsblock, intidtv);
|
||||
# else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
|
||||
/* There can only be one PT_TLS entry. */
|
||||
break;
|
||||
}
|
||||
#endif /* use TLS */
|
||||
|
||||
/* Call the OS-dependent function to set up life so we can do things like
|
||||
file access. It will call `dl_main' (below) to do all the real work
|
||||
of the dynamic linker, and then unwind our frame and run the user
|
||||
entry point on the same stack we entered on. */
|
||||
*start_addr = _dl_sysdep_start (arg, &dl_main);
|
||||
|
||||
#ifndef HP_TIMING_NONAVAIL
|
||||
if (HP_TIMING_AVAIL)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <resolv/resolv.h>
|
||||
|
||||
#ifdef _RESOLV_H_
|
||||
/* Now define the internal interfaces. */
|
||||
extern int __res_vinit (res_state, int);
|
||||
extern void _sethtent (int);
|
||||
@ -26,5 +27,6 @@ extern void res_send_setqhook (res_send_qhook __hook);
|
||||
extern void res_send_setrhook (res_send_rhook __hook);
|
||||
extern int res_ourserver_p (const res_state __statp,
|
||||
const struct sockaddr_in6 *__inp);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,9 @@
|
||||
2002-02-04 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* internals.h: Move thread descriptor definition...
|
||||
* descr.h.: ...here. New file.
|
||||
* sysdeps/i386/tls.h: New file.
|
||||
|
||||
2002-02-01 H.J. Lu <hjl@gnu.org>
|
||||
|
||||
* sysdeps/mips/pspinlock.c (__pthread_spin_lock): Use a
|
||||
|
168
linuxthreads/descr.h
Normal file
168
linuxthreads/descr.h
Normal file
@ -0,0 +1,168 @@
|
||||
/* Linuxthreads - a simple clone()-based implementation of Posix */
|
||||
/* threads for Linux. */
|
||||
/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or */
|
||||
/* modify it under the terms of the GNU Library General Public License */
|
||||
/* as published by the Free Software Foundation; either version 2 */
|
||||
/* of the License, or (at your option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, */
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* GNU Library General Public License for more details. */
|
||||
|
||||
#ifndef _DESCR_H
|
||||
#define _DESCR_H 1
|
||||
|
||||
#define __need_res_state
|
||||
#include <resolv.h>
|
||||
#include <sched.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <hp-timing.h>
|
||||
#include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
|
||||
|
||||
|
||||
/* The type of thread descriptors */
|
||||
typedef struct _pthread_descr_struct *pthread_descr;
|
||||
|
||||
|
||||
/* Some more includes. */
|
||||
#include <pt-machine.h>
|
||||
#include <linuxthreads_db/thread_dbP.h>
|
||||
|
||||
|
||||
/* Arguments passed to thread creation routine */
|
||||
struct pthread_start_args {
|
||||
void *(*start_routine)(void *); /* function to run */
|
||||
void *arg; /* its argument */
|
||||
sigset_t mask; /* initial signal mask for thread */
|
||||
int schedpolicy; /* initial scheduling policy (if any) */
|
||||
struct sched_param schedparam; /* initial scheduling parameters (if any) */
|
||||
};
|
||||
|
||||
|
||||
/* Callback interface for removing the thread from waiting on an
|
||||
object if it is cancelled while waiting or about to wait.
|
||||
This hold a pointer to the object, and a pointer to a function
|
||||
which ``extricates'' the thread from its enqueued state.
|
||||
The function takes two arguments: pointer to the wait object,
|
||||
and a pointer to the thread. It returns 1 if an extrication
|
||||
actually occured, and hence the thread must also be signalled.
|
||||
It returns 0 if the thread had already been extricated. */
|
||||
typedef struct _pthread_extricate_struct {
|
||||
void *pu_object;
|
||||
int (*pu_extricate_func)(void *, pthread_descr);
|
||||
} pthread_extricate_if;
|
||||
|
||||
|
||||
/* Atomic counter made possible by compare_and_swap */
|
||||
struct pthread_atomic {
|
||||
long p_count;
|
||||
int p_spinlock;
|
||||
};
|
||||
|
||||
|
||||
/* Context info for read write locks. The pthread_rwlock_info structure
|
||||
is information about a lock that has been read-locked by the thread
|
||||
in whose list this structure appears. The pthread_rwlock_context
|
||||
is embedded in the thread context and contains a pointer to the
|
||||
head of the list of lock info structures, as well as a count of
|
||||
read locks that are untracked, because no info structure could be
|
||||
allocated for them. */
|
||||
struct _pthread_rwlock_t;
|
||||
typedef struct _pthread_rwlock_info {
|
||||
struct _pthread_rwlock_info *pr_next;
|
||||
struct _pthread_rwlock_t *pr_lock;
|
||||
int pr_lock_count;
|
||||
} pthread_readlock_info;
|
||||
|
||||
|
||||
/* We keep thread specific data in a special data structure, a two-level
|
||||
array. The top-level array contains pointers to dynamically allocated
|
||||
arrays of a certain number of data pointers. So we can implement a
|
||||
sparse array. Each dynamic second-level array has
|
||||
PTHREAD_KEY_2NDLEVEL_SIZE
|
||||
entries. This value shouldn't be too large. */
|
||||
#define PTHREAD_KEY_2NDLEVEL_SIZE 32
|
||||
|
||||
/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
|
||||
keys in each subarray. */
|
||||
#define PTHREAD_KEY_1STLEVEL_SIZE \
|
||||
((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
|
||||
/ PTHREAD_KEY_2NDLEVEL_SIZE)
|
||||
|
||||
|
||||
union dtv;
|
||||
|
||||
|
||||
struct _pthread_descr_struct {
|
||||
/* XXX Remove this union for IA-64 style TLS module */
|
||||
union {
|
||||
struct {
|
||||
pthread_descr self; /* Pointer to this structure */
|
||||
union dtv *dtvp;
|
||||
} data;
|
||||
void *__padding[16];
|
||||
} p_header;
|
||||
pthread_descr p_nextlive, p_prevlive;
|
||||
/* Double chaining of active threads */
|
||||
pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */
|
||||
pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */
|
||||
pthread_t p_tid; /* Thread identifier */
|
||||
int p_pid; /* PID of Unix process */
|
||||
int p_priority; /* Thread priority (== 0 if not realtime) */
|
||||
struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
|
||||
int p_signal; /* last signal received */
|
||||
sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
|
||||
sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
|
||||
char p_terminated; /* true if terminated e.g. by pthread_exit */
|
||||
char p_detached; /* true if detached */
|
||||
char p_exited; /* true if the assoc. process terminated */
|
||||
void * p_retval; /* placeholder for return value */
|
||||
int p_retcode; /* placeholder for return code */
|
||||
pthread_descr p_joining; /* thread joining on that thread or NULL */
|
||||
struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
|
||||
char p_cancelstate; /* cancellation state */
|
||||
char p_canceltype; /* cancellation type (deferred/async) */
|
||||
char p_canceled; /* cancellation request pending */
|
||||
int * p_errnop; /* pointer to used errno variable */
|
||||
int p_errno; /* error returned by last system call */
|
||||
int * p_h_errnop; /* pointer to used h_errno variable */
|
||||
int p_h_errno; /* error returned by last netdb function */
|
||||
char * p_in_sighandler; /* stack address of sighandler, or NULL */
|
||||
char p_sigwaiting; /* true if a sigwait() is in progress */
|
||||
struct pthread_start_args p_start_args; /* arguments for thread creation */
|
||||
void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
|
||||
void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
|
||||
int p_userstack; /* nonzero if the user provided the stack */
|
||||
void *p_guardaddr; /* address of guard area or NULL */
|
||||
size_t p_guardsize; /* size of guard area */
|
||||
int p_nr; /* Index of descriptor in __pthread_handles */
|
||||
int p_report_events; /* Nonzero if events must be reported. */
|
||||
td_eventbuf_t p_eventbuf; /* Data for event. */
|
||||
struct pthread_atomic p_resume_count; /* number of times restart() was
|
||||
called on thread */
|
||||
char p_woken_by_cancel; /* cancellation performed wakeup */
|
||||
char p_condvar_avail; /* flag if conditional variable became avail */
|
||||
char p_sem_avail; /* flag if semaphore became available */
|
||||
pthread_extricate_if *p_extricate; /* See above */
|
||||
pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
|
||||
pthread_readlock_info *p_readlock_free; /* Free list of structs */
|
||||
int p_untracked_readlock_count; /* Readlocks not tracked by list */
|
||||
struct __res_state *p_resp; /* Pointer to resolver state */
|
||||
struct __res_state p_res; /* per-thread resolver state */
|
||||
int p_inheritsched; /* copied from the thread attribute */
|
||||
#if HP_TIMING_AVAIL
|
||||
hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */
|
||||
#endif
|
||||
/* New elements must be added at the end. */
|
||||
} __attribute__ ((aligned(32))); /* We need to align the structure so that
|
||||
doubles are aligned properly. This is 8
|
||||
bytes on MIPS and 16 bytes on MIPS64.
|
||||
32 bytes might give better cache
|
||||
utilization. */
|
||||
|
||||
#endif /* descr.h */
|
@ -20,21 +20,15 @@
|
||||
/* Includes */
|
||||
|
||||
#include <limits.h>
|
||||
#include <resolv.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stackinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
|
||||
|
||||
#include "descr.h"
|
||||
|
||||
extern long int testandset (int *spinlock);
|
||||
extern int __compare_and_swap (long int *p, long int oldval, long int newval);
|
||||
|
||||
#include "pt-machine.h"
|
||||
#include "semaphore.h"
|
||||
#include "../linuxthreads_db/thread_dbP.h"
|
||||
#include <hp-timing.h>
|
||||
|
||||
#ifndef THREAD_GETMEM
|
||||
# define THREAD_GETMEM(descr, member) descr->member
|
||||
@ -49,31 +43,6 @@ extern int __compare_and_swap (long int *p, long int oldval, long int newval);
|
||||
# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
|
||||
#endif
|
||||
|
||||
/* Arguments passed to thread creation routine */
|
||||
|
||||
struct pthread_start_args {
|
||||
void * (*start_routine)(void *); /* function to run */
|
||||
void * arg; /* its argument */
|
||||
sigset_t mask; /* initial signal mask for thread */
|
||||
int schedpolicy; /* initial scheduling policy (if any) */
|
||||
struct sched_param schedparam; /* initial scheduling parameters (if any) */
|
||||
};
|
||||
|
||||
|
||||
/* We keep thread specific data in a special data structure, a two-level
|
||||
array. The top-level array contains pointers to dynamically allocated
|
||||
arrays of a certain number of data pointers. So we can implement a
|
||||
sparse array. Each dynamic second-level array has
|
||||
PTHREAD_KEY_2NDLEVEL_SIZE
|
||||
entries. This value shouldn't be too large. */
|
||||
#define PTHREAD_KEY_2NDLEVEL_SIZE 32
|
||||
|
||||
/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
|
||||
keys in each subarray. */
|
||||
#define PTHREAD_KEY_1STLEVEL_SIZE \
|
||||
((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
|
||||
/ PTHREAD_KEY_2NDLEVEL_SIZE)
|
||||
|
||||
typedef void (*destr_function)(void *);
|
||||
|
||||
struct pthread_key_struct {
|
||||
@ -85,112 +54,6 @@ struct pthread_key_struct {
|
||||
#define PTHREAD_START_ARGS_INITIALIZER(fct) \
|
||||
{ (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } }
|
||||
|
||||
/* The type of thread descriptors */
|
||||
|
||||
typedef struct _pthread_descr_struct * pthread_descr;
|
||||
|
||||
/* Callback interface for removing the thread from waiting on an
|
||||
object if it is cancelled while waiting or about to wait.
|
||||
This hold a pointer to the object, and a pointer to a function
|
||||
which ``extricates'' the thread from its enqueued state.
|
||||
The function takes two arguments: pointer to the wait object,
|
||||
and a pointer to the thread. It returns 1 if an extrication
|
||||
actually occured, and hence the thread must also be signalled.
|
||||
It returns 0 if the thread had already been extricated. */
|
||||
|
||||
typedef struct _pthread_extricate_struct {
|
||||
void *pu_object;
|
||||
int (*pu_extricate_func)(void *, pthread_descr);
|
||||
} pthread_extricate_if;
|
||||
|
||||
/* Atomic counter made possible by compare_and_swap */
|
||||
|
||||
struct pthread_atomic {
|
||||
long p_count;
|
||||
int p_spinlock;
|
||||
};
|
||||
|
||||
/* Context info for read write locks. The pthread_rwlock_info structure
|
||||
is information about a lock that has been read-locked by the thread
|
||||
in whose list this structure appears. The pthread_rwlock_context
|
||||
is embedded in the thread context and contains a pointer to the
|
||||
head of the list of lock info structures, as well as a count of
|
||||
read locks that are untracked, because no info structure could be
|
||||
allocated for them. */
|
||||
|
||||
struct _pthread_rwlock_t;
|
||||
|
||||
typedef struct _pthread_rwlock_info {
|
||||
struct _pthread_rwlock_info *pr_next;
|
||||
struct _pthread_rwlock_t *pr_lock;
|
||||
int pr_lock_count;
|
||||
} pthread_readlock_info;
|
||||
|
||||
struct _pthread_descr_struct {
|
||||
union {
|
||||
struct {
|
||||
pthread_descr self; /* Pointer to this structure */
|
||||
} data;
|
||||
void *__padding[16];
|
||||
} p_header;
|
||||
pthread_descr p_nextlive, p_prevlive;
|
||||
/* Double chaining of active threads */
|
||||
pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */
|
||||
pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */
|
||||
pthread_t p_tid; /* Thread identifier */
|
||||
int p_pid; /* PID of Unix process */
|
||||
int p_priority; /* Thread priority (== 0 if not realtime) */
|
||||
struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
|
||||
int p_signal; /* last signal received */
|
||||
sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
|
||||
sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
|
||||
char p_terminated; /* true if terminated e.g. by pthread_exit */
|
||||
char p_detached; /* true if detached */
|
||||
char p_exited; /* true if the assoc. process terminated */
|
||||
void * p_retval; /* placeholder for return value */
|
||||
int p_retcode; /* placeholder for return code */
|
||||
pthread_descr p_joining; /* thread joining on that thread or NULL */
|
||||
struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
|
||||
char p_cancelstate; /* cancellation state */
|
||||
char p_canceltype; /* cancellation type (deferred/async) */
|
||||
char p_canceled; /* cancellation request pending */
|
||||
int * p_errnop; /* pointer to used errno variable */
|
||||
int p_errno; /* error returned by last system call */
|
||||
int * p_h_errnop; /* pointer to used h_errno variable */
|
||||
int p_h_errno; /* error returned by last netdb function */
|
||||
char * p_in_sighandler; /* stack address of sighandler, or NULL */
|
||||
char p_sigwaiting; /* true if a sigwait() is in progress */
|
||||
struct pthread_start_args p_start_args; /* arguments for thread creation */
|
||||
void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
|
||||
void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
|
||||
int p_userstack; /* nonzero if the user provided the stack */
|
||||
void *p_guardaddr; /* address of guard area or NULL */
|
||||
size_t p_guardsize; /* size of guard area */
|
||||
int p_nr; /* Index of descriptor in __pthread_handles */
|
||||
int p_report_events; /* Nonzero if events must be reported. */
|
||||
td_eventbuf_t p_eventbuf; /* Data for event. */
|
||||
struct pthread_atomic p_resume_count; /* number of times restart() was
|
||||
called on thread */
|
||||
char p_woken_by_cancel; /* cancellation performed wakeup */
|
||||
char p_condvar_avail; /* flag if conditional variable became avail */
|
||||
char p_sem_avail; /* flag if semaphore became available */
|
||||
pthread_extricate_if *p_extricate; /* See above */
|
||||
pthread_readlock_info *p_readlock_list; /* List of readlock info structs */
|
||||
pthread_readlock_info *p_readlock_free; /* Free list of structs */
|
||||
int p_untracked_readlock_count; /* Readlocks not tracked by list */
|
||||
struct __res_state *p_resp; /* Pointer to resolver state */
|
||||
struct __res_state p_res; /* per-thread resolver state */
|
||||
int p_inheritsched; /* copied from the thread attribute */
|
||||
#if HP_TIMING_AVAIL
|
||||
hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread. */
|
||||
#endif
|
||||
/* New elements must be added at the end. */
|
||||
} __attribute__ ((aligned(32))); /* We need to align the structure so that
|
||||
doubles are aligned properly. This is 8
|
||||
bytes on MIPS and 16 bytes on MIPS64.
|
||||
32 bytes might give better cache
|
||||
utilization. */
|
||||
|
||||
|
||||
/* The type of thread handles. */
|
||||
|
||||
|
95
linuxthreads/sysdeps/i386/tls.h
Normal file
95
linuxthreads/sysdeps/i386/tls.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* Definition for thread-local data handling. linuxthreads/i386 version.
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
#ifndef _TLS_H
|
||||
#define _TLS_H
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
void *pointer;
|
||||
} dtv_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *tcb;
|
||||
dtv_t *dtv;
|
||||
} tcbhead_t;
|
||||
|
||||
|
||||
/* Get the thread descriptor definition. */
|
||||
#include <linuxthreads/descr.h>
|
||||
|
||||
|
||||
/* We can support TLS only if the floating-stack support is available. */
|
||||
#if FLOATING_STACKS && defined HAVE_TLS_SUPPORT
|
||||
|
||||
/* Get system call information. */
|
||||
# include <sysdep.h>
|
||||
|
||||
/* Signal that TLS support is available. */
|
||||
# define USE_TLS 1
|
||||
|
||||
/* This is the size of the initial TCB. */
|
||||
# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
|
||||
|
||||
/* Alignment requirements for the initial TCB. */
|
||||
# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
|
||||
|
||||
/* This is the size of the TCB. */
|
||||
# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
|
||||
|
||||
/* Alignment requirements for the TCB. */
|
||||
# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
|
||||
|
||||
/* The TCB can have any size and the memory following the address the
|
||||
thread pointer points to is unspecified. Allocate the TCB there. */
|
||||
# define TLS_TCB_AT_TP 1
|
||||
|
||||
/* Code to initially initialize the thread pointer. This might need
|
||||
special attention since 'errno' is not yet available and if the
|
||||
operation can cause a failure 'errno' must not be touched. */
|
||||
# define TLS_INIT_TP(descr, dtvp) \
|
||||
do { \
|
||||
void *_descr = (descr); \
|
||||
struct modify_ldt_ldt_s ldt_entry = \
|
||||
{ 0, (unsigned long int) _descr, 1048576, 1, 0, 0, 1, 0, 1, 0 }; \
|
||||
int result; \
|
||||
tcbhead_t *head = _descr; \
|
||||
\
|
||||
head->tcb = _descr; \
|
||||
head->dtv = dtvp; \
|
||||
\
|
||||
asm ("pushl %%ebx\n\t" \
|
||||
"movl $1, %%ebx\n\t" \
|
||||
"int $0x80\n\t" \
|
||||
"popl %%ebx" \
|
||||
: "=a" (result) \
|
||||
: "0" (__NR_modify_ldt), "d" (sizeof (ldt_entry)), "c" (&ldt_entry));\
|
||||
\
|
||||
if (__builtin_expect (result, 0) != 0) \
|
||||
/* Nothing else we can do. */ \
|
||||
asm ("hlt"); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* tls.h */
|
@ -1,3 +1,14 @@
|
||||
2002-02-04 Ulrich Drepper <drepper@redhat.com>
|
||||
|
||||
* thread_dbP.h: Include descr.h instead of internals.h.
|
||||
* td_ta_event_getmsg.c: Also include <linuxthreads/internals.h>.
|
||||
* td_ta_map_id2thr.c: Likewise.
|
||||
* td_ta_map_lwp2thr.c: Likewise.
|
||||
* td_ta_thr_iter.c: Likewise.
|
||||
* td_ta_tsd_iter.c: Likewise.
|
||||
* td_thr_tsd.c: Likewise.
|
||||
* td_thr_validate.c: Likewise.
|
||||
|
||||
2001-12-28 Andreas Jaeger <aj@suse.de>
|
||||
|
||||
* td_init.c (td_init): Don't use __FUNCTION__ as literal.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Retrieve event.
|
||||
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Map thread ID to thread handle.
|
||||
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Which thread is running on an lwp?
|
||||
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Iterate over a process's threads.
|
||||
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
#include <alloca.h>
|
||||
|
||||
static int
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Iterate over a process's thread-specific data.
|
||||
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
#include <alloca.h>
|
||||
|
||||
td_err_e
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Get a thread-specific data pointer for a thread.
|
||||
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Validate a thread handle.
|
||||
Copyright (C) 1999, 2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
02111-1307 USA. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <linuxthreads/internals.h>
|
||||
|
||||
|
||||
td_err_e
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <string.h>
|
||||
#include "proc_service.h"
|
||||
#include "thread_db.h"
|
||||
#include "../linuxthreads/internals.h"
|
||||
#include "../linuxthreads/descr.h"
|
||||
|
||||
|
||||
/* Indeces for the symbol names. */
|
||||
|
@ -50,39 +50,24 @@
|
||||
*/
|
||||
|
||||
#ifndef _RESOLV_H_
|
||||
#define _RESOLV_H_
|
||||
#ifndef __need_res_state
|
||||
# define _RESOLV_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#if (!defined(BSD)) || (BSD < 199306)
|
||||
# include <sys/param.h>
|
||||
# if (!defined(BSD)) || (BSD < 199306)
|
||||
# include <sys/bitypes.h>
|
||||
#else
|
||||
# else
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <sys/cdefs.h>
|
||||
# include <stdio.h>
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
/*
|
||||
* Revision information. This is the release date in YYYYMMDD format.
|
||||
* It can change every day so the right thing to do with it is use it
|
||||
* in preprocessor commands such as "#if (__RES > 19931104)". Do not
|
||||
* compare for equality; rather, use it to determine whether your resolver
|
||||
* is new enough to contain a certain feature.
|
||||
*/
|
||||
|
||||
#define __RES 19991006
|
||||
|
||||
/*
|
||||
* Resolver configuration file.
|
||||
* Normally not present, but may contain the address of the
|
||||
* inital name server(s) to query and the domain search list.
|
||||
*/
|
||||
|
||||
#ifndef _PATH_RESCONF
|
||||
#define _PATH_RESCONF "/etc/resolv.conf"
|
||||
#endif
|
||||
#ifndef __res_state_defined
|
||||
# define __res_state_defined
|
||||
|
||||
typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
|
||||
res_sendhookact;
|
||||
@ -101,27 +86,21 @@ typedef res_sendhookact (*res_send_rhook) (const struct sockaddr_in *ns,
|
||||
int anssiz,
|
||||
int *resplen);
|
||||
|
||||
struct res_sym {
|
||||
int number; /* Identifying number, like T_MX */
|
||||
char * name; /* Its symbolic name, like "MX" */
|
||||
char * humanname; /* Its fun name, like "mail exchanger" */
|
||||
};
|
||||
|
||||
/*
|
||||
* Global defines and variables for resolver stub.
|
||||
*/
|
||||
#define MAXNS 3 /* max # name servers we'll track */
|
||||
#define MAXDFLSRCH 3 /* # default domain levels to try */
|
||||
#define MAXDNSRCH 6 /* max # domains in search path */
|
||||
#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
|
||||
# define MAXNS 3 /* max # name servers we'll track */
|
||||
# define MAXDFLSRCH 3 /* # default domain levels to try */
|
||||
# define MAXDNSRCH 6 /* max # domains in search path */
|
||||
# define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */
|
||||
|
||||
#define RES_TIMEOUT 5 /* min. seconds between retries */
|
||||
#define MAXRESOLVSORT 10 /* number of net to sort on */
|
||||
#define RES_MAXNDOTS 15 /* should reflect bit field size */
|
||||
#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */
|
||||
#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */
|
||||
#define RES_DFLRETRY 2 /* Default #/tries. */
|
||||
#define RES_MAXTIME 65535 /* Infinity, in milliseconds. */
|
||||
# define RES_TIMEOUT 5 /* min. seconds between retries */
|
||||
# define MAXRESOLVSORT 10 /* number of net to sort on */
|
||||
# define RES_MAXNDOTS 15 /* should reflect bit field size */
|
||||
# define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */
|
||||
# define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */
|
||||
# define RES_DFLRETRY 2 /* Default #/tries. */
|
||||
# define RES_MAXTIME 65535 /* Infinity, in milliseconds. */
|
||||
|
||||
struct __res_state {
|
||||
int retrans; /* retransmition time interval */
|
||||
@ -130,7 +109,7 @@ struct __res_state {
|
||||
int nscount; /* number of name servers */
|
||||
struct sockaddr_in
|
||||
nsaddr_list[MAXNS]; /* address of name server */
|
||||
#define nsaddr nsaddr_list[0] /* for backward compatibility */
|
||||
# define nsaddr nsaddr_list[0] /* for backward compatibility */
|
||||
u_short id; /* current message id */
|
||||
char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
|
||||
char defdname[256]; /* default domain (deprecated) */
|
||||
@ -161,6 +140,35 @@ struct __res_state {
|
||||
};
|
||||
|
||||
typedef struct __res_state *res_state;
|
||||
# undef __need_res_state
|
||||
#endif
|
||||
|
||||
#ifdef _RESOLV_H_
|
||||
/*
|
||||
* Revision information. This is the release date in YYYYMMDD format.
|
||||
* It can change every day so the right thing to do with it is use it
|
||||
* in preprocessor commands such as "#if (__RES > 19931104)". Do not
|
||||
* compare for equality; rather, use it to determine whether your resolver
|
||||
* is new enough to contain a certain feature.
|
||||
*/
|
||||
|
||||
#define __RES 19991006
|
||||
|
||||
/*
|
||||
* Resolver configuration file.
|
||||
* Normally not present, but may contain the address of the
|
||||
* inital name server(s) to query and the domain search list.
|
||||
*/
|
||||
|
||||
#ifndef _PATH_RESCONF
|
||||
#define _PATH_RESCONF "/etc/resolv.conf"
|
||||
#endif
|
||||
|
||||
struct res_sym {
|
||||
int number; /* Identifying number, like T_MX */
|
||||
char * name; /* Its symbolic name, like "MX" */
|
||||
char * humanname; /* Its fun name, like "mail exchanger" */
|
||||
};
|
||||
|
||||
/*
|
||||
* Resolver flags (used to be discrete per-module statics ints).
|
||||
@ -374,5 +382,6 @@ int res_nmkquery __P((res_state,
|
||||
int res_nsend __P((res_state, const u_char *, int, u_char *, int));
|
||||
void res_nclose __P((res_state));
|
||||
__END_DECLS
|
||||
#endif
|
||||
|
||||
#endif /* !_RESOLV_H_ */
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <dl-lookupcfg.h>
|
||||
#include <bits/libc-lock.h>
|
||||
#include <hp-timing.h>
|
||||
#include <tls.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@ -286,6 +287,11 @@ struct rtld_global
|
||||
EXTERN hp_timing_t _dl_hp_timing_overhead;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TLS
|
||||
/* Offset of the TLS block for ld.so from the thread-pointer. */
|
||||
EXTERN size_t _rtld_tlsoffset;
|
||||
#endif
|
||||
|
||||
/* Name of the shared object to be profiled (if any). */
|
||||
EXTERN const char *_dl_profile;
|
||||
/* Map of shared object to be profiled. */
|
||||
|
22
sysdeps/generic/tls.h
Normal file
22
sysdeps/generic/tls.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* Definition for thread-local data handling. Generic version.
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA. */
|
||||
|
||||
/* By default no TLS support is available. This is signaled by the
|
||||
absence of the symbol USE_TLS. */
|
||||
#undef USE_TLS
|
@ -342,7 +342,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifdef RTLD_BOOTSTRAP
|
||||
#if defined RTLD_BOOTSTRAP && !defined USE_TLS
|
||||
Elf32_Addr value;
|
||||
|
||||
assert (r_type == R_386_GLOB_DAT || r_type == R_386_JMP_SLOT);
|
||||
@ -352,7 +352,9 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
#else
|
||||
const Elf32_Sym *const refsym = sym;
|
||||
Elf32_Addr value = RESOLVE (&sym, version, r_type);
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
if (sym)
|
||||
# endif
|
||||
value += sym->st_value;
|
||||
|
||||
switch (r_type)
|
||||
@ -361,6 +363,40 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
case R_386_JMP_SLOT:
|
||||
*reloc_addr = value;
|
||||
break;
|
||||
|
||||
/* XXX Remove TLS relocations which are not needed. */
|
||||
|
||||
case R_386_TLS_DTPMOD32:
|
||||
# ifdef RTLD_BOOTSTRAP
|
||||
/* During startup the dynamic linker is always the module
|
||||
with index 1.
|
||||
XXX If this relocation is necessary move before RESOLVE
|
||||
call. */
|
||||
*reloc_addr = 1;
|
||||
# else
|
||||
/* XXX Implement. RESOLVE must return the map from which we
|
||||
get the module ID. */
|
||||
_exit (99);
|
||||
# endif
|
||||
break;
|
||||
case R_386_TLS_DTPOFF32:
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
/* During relocation all TLS symbols are defined and used.
|
||||
Therefore the offset is already correct. */
|
||||
*reloc_addr = sym->st_value;
|
||||
# endif
|
||||
break;
|
||||
case R_386_TLS_TPOFF32:
|
||||
/* The offset is positive, backward from the thread pointer. */
|
||||
# ifdef RTLD_BOOTSTRAP
|
||||
*reloc_addr = GL(rtld_tlsoffset) - sym->st_value;
|
||||
# else
|
||||
/* XXX Implement. */
|
||||
_exit (98);
|
||||
# endif
|
||||
break;
|
||||
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
case R_386_32:
|
||||
*reloc_addr += value;
|
||||
break;
|
||||
@ -390,6 +426,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
|
||||
default:
|
||||
_dl_reloc_bad_type (map, r_type, 0);
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
6
sysdeps/i386/elf/configure
vendored
6
sysdeps/i386/elf/configure
vendored
@ -9,16 +9,18 @@ if eval "test \"`echo '$''{'libc_cv_386_tls'+set}'`\" = set"; then
|
||||
else
|
||||
cat > conftest.s <<\EOF
|
||||
.section ".tdata", "awT", @progbits
|
||||
.globl foo
|
||||
foo: .long 1
|
||||
.section ".tbss", "awT", @nobits
|
||||
.comm bar,4,4
|
||||
.globl bar
|
||||
bar: .skip 4
|
||||
.text
|
||||
baz: leal bar@TLSLDM(%ebx), %eax
|
||||
leal bar@DTPOFF(%eax), %edx
|
||||
subl foo@GOTTPOFF(%edx), %eax
|
||||
subl $bar@TPOFF, %eax
|
||||
EOF
|
||||
if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:22: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
|
||||
if { ac_try='${CC-cc} -c $CFLAGS conftest.s 1>&5'; { (eval echo configure:24: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then
|
||||
libc_cv_386_tls=yes
|
||||
else
|
||||
libc_cv_386_tls=no
|
||||
|
Loading…
Reference in New Issue
Block a user