138816Sdfr/*-
248205Sjdp * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
338816Sdfr * All rights reserved.
438816Sdfr *
538816Sdfr * Redistribution and use in source and binary forms, with or without
638816Sdfr * modification, are permitted provided that the following conditions
738816Sdfr * are met:
838816Sdfr * 1. Redistributions of source code must retain the above copyright
938816Sdfr *    notice, this list of conditions and the following disclaimer.
1038816Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1138816Sdfr *    notice, this list of conditions and the following disclaimer in the
1238816Sdfr *    documentation and/or other materials provided with the distribution.
1338816Sdfr *
1438816Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1538816Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1638816Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1738816Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1838816Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1938816Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2038816Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2138816Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2238816Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2338816Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2438816Sdfr *
2550476Speter * $FreeBSD: stable/10/libexec/rtld-elf/i386/reloc.c 331206 2018-03-19 14:28:58Z marius $
2638816Sdfr */
2738816Sdfr
2838816Sdfr/*
2938816Sdfr * Dynamic linker for ELF.
3038816Sdfr *
3138816Sdfr * John Polstra <jdp@polstra.com>.
3238816Sdfr */
3338816Sdfr
3438816Sdfr#include <sys/param.h>
3538816Sdfr#include <sys/mman.h>
36133063Sdfr#include <machine/segments.h>
37133063Sdfr#include <machine/sysarch.h>
3838816Sdfr
3938816Sdfr#include <dlfcn.h>
4038816Sdfr#include <err.h>
4138816Sdfr#include <errno.h>
4238816Sdfr#include <fcntl.h>
4338816Sdfr#include <stdarg.h>
4438816Sdfr#include <stdio.h>
4538816Sdfr#include <stdlib.h>
4638816Sdfr#include <string.h>
4738816Sdfr#include <unistd.h>
4838816Sdfr
4938816Sdfr#include "debug.h"
5038816Sdfr#include "rtld.h"
51281453Skib#include "rtld_tls.h"
5238816Sdfr
5338816Sdfr/*
5438816Sdfr * Process the special R_386_COPY relocations in the main program.  These
5538816Sdfr * copy data from a shared object into a region in the main program's BSS
5638816Sdfr * segment.
5738816Sdfr *
5838816Sdfr * Returns 0 on success, -1 on failure.
5938816Sdfr */
6038816Sdfrint
6138816Sdfrdo_copy_relocations(Obj_Entry *dstobj)
6238816Sdfr{
6338816Sdfr    const Elf_Rel *rellim;
6438816Sdfr    const Elf_Rel *rel;
6538816Sdfr
6638816Sdfr    assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
6738816Sdfr
6838816Sdfr    rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
6938816Sdfr    for (rel = dstobj->rel;  rel < rellim;  rel++) {
7038816Sdfr	if (ELF_R_TYPE(rel->r_info) == R_386_COPY) {
7138816Sdfr	    void *dstaddr;
7238816Sdfr	    const Elf_Sym *dstsym;
7338816Sdfr	    const char *name;
7438816Sdfr	    size_t size;
7538816Sdfr	    const void *srcaddr;
7638816Sdfr	    const Elf_Sym *srcsym;
77216695Skib	    const Obj_Entry *srcobj, *defobj;
78216695Skib	    SymLook req;
79216695Skib	    int res;
8038816Sdfr
8138816Sdfr	    dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
8238816Sdfr	    dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
8338816Sdfr	    name = dstobj->strtab + dstsym->st_name;
8438816Sdfr	    size = dstsym->st_size;
85216695Skib	    symlook_init(&req, name);
86216695Skib	    req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
87233231Skib	    req.flags = SYMLOOK_EARLY;
8838816Sdfr
89296727Skib	    for (srcobj = globallist_next(dstobj);  srcobj != NULL;
90296727Skib	      srcobj = globallist_next(srcobj)) {
91216695Skib		res = symlook_obj(&req, srcobj);
92216695Skib		if (res == 0) {
93216695Skib		    srcsym = req.sym_out;
94216695Skib		    defobj = req.defobj_out;
9538816Sdfr		    break;
96216695Skib		}
97216695Skib	    }
9838816Sdfr
9938816Sdfr	    if (srcobj == NULL) {
10038816Sdfr		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
10138816Sdfr		  " relocation in %s", name, dstobj->path);
10238816Sdfr		return -1;
10338816Sdfr	    }
10438816Sdfr
105216695Skib	    srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
10638816Sdfr	    memcpy(dstaddr, srcaddr, size);
10738816Sdfr	}
10838816Sdfr    }
10938816Sdfr
11038816Sdfr    return 0;
11138816Sdfr}
11238816Sdfr
11345501Sjdp/* Initialize the special GOT entries. */
11445501Sjdpvoid
11545501Sjdpinit_pltgot(Obj_Entry *obj)
11645501Sjdp{
11745501Sjdp    if (obj->pltgot != NULL) {
11845501Sjdp	obj->pltgot[1] = (Elf_Addr) obj;
11945501Sjdp	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
12045501Sjdp    }
12145501Sjdp}
12245501Sjdp
12338816Sdfr/* Process the non-PLT relocations. */
12438816Sdfrint
125233231Skibreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
126233231Skib    RtldLockState *lockstate)
12738816Sdfr{
12838816Sdfr	const Elf_Rel *rellim;
12938816Sdfr	const Elf_Rel *rel;
13076296Sjdp	SymCache *cache;
131271469Skib	const Elf_Sym *def;
132271469Skib	const Obj_Entry *defobj;
133271469Skib	Elf_Addr *where, symval, add;
134271469Skib	int r;
13538816Sdfr
136271469Skib	r = -1;
13798100Sdillon	/*
13898100Sdillon	 * The dynamic loader may be called from a thread, we have
13998100Sdillon	 * limited amounts of stack available so we cannot use alloca().
14098100Sdillon	 */
141208256Srdivacky	if (obj != obj_rtld) {
142271469Skib		cache = calloc(obj->dynsymcount, sizeof(SymCache));
143271469Skib		/* No need to check for NULL here */
144208256Srdivacky	} else
145271469Skib		cache = NULL;
14676296Sjdp
147271469Skib	rellim = (const Elf_Rel *)((caddr_t) obj->rel + obj->relsize);
14838816Sdfr	for (rel = obj->rel;  rel < rellim;  rel++) {
149271469Skib		switch (ELF_R_TYPE(rel->r_info)) {
150271469Skib		case R_386_32:
151271469Skib		case R_386_PC32:
152271469Skib		case R_386_GLOB_DAT:
153271469Skib		case R_386_TLS_TPOFF:
154271469Skib		case R_386_TLS_TPOFF32:
155271469Skib		case R_386_TLS_DTPMOD32:
156271469Skib		case R_386_TLS_DTPOFF32:
157271469Skib			def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
158271469Skib			    flags, cache, lockstate);
159271469Skib			if (def == NULL)
160271469Skib				goto done;
161271469Skib			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
162271469Skib				switch (ELF_R_TYPE(rel->r_info)) {
163271469Skib				case R_386_32:
164271469Skib				case R_386_PC32:
165271469Skib				case R_386_GLOB_DAT:
166271469Skib					if ((flags & SYMLOOK_IFUNC) == 0) {
167271469Skib						obj->non_plt_gnu_ifunc = true;
168271469Skib						continue;
169271469Skib					}
170271469Skib					symval = (Elf_Addr)rtld_resolve_ifunc(
171271469Skib					    defobj, def);
172271469Skib					break;
173271469Skib				case R_386_TLS_TPOFF:
174271469Skib				case R_386_TLS_TPOFF32:
175271469Skib				case R_386_TLS_DTPMOD32:
176271469Skib				case R_386_TLS_DTPOFF32:
177271469Skib					_rtld_error("%s: IFUNC for TLS reloc",
178271469Skib					    obj->path);
179271469Skib					goto done;
180271469Skib				}
181271469Skib			} else {
182271469Skib				if ((flags & SYMLOOK_IFUNC) != 0)
183271469Skib					continue;
184271469Skib				symval = (Elf_Addr)defobj->relocbase +
185271469Skib				    def->st_value;
186271469Skib			}
187271469Skib			break;
188271469Skib		default:
189271469Skib			if ((flags & SYMLOOK_IFUNC) != 0)
190271469Skib				continue;
191271469Skib			break;
19238816Sdfr		}
193271469Skib		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
19438816Sdfr
195271469Skib		switch (ELF_R_TYPE(rel->r_info)) {
196271469Skib		case R_386_NONE:
197271469Skib			break;
198271469Skib		case R_386_32:
199271469Skib			*where += symval;
200271469Skib			break;
201271469Skib		case R_386_PC32:
202133063Sdfr		    /*
203271469Skib		     * I don't think the dynamic linker should ever
204271469Skib		     * see this type of relocation.  But the
205271469Skib		     * binutils-2.6 tools sometimes generate it.
206133063Sdfr		     */
207271469Skib		    *where += symval - (Elf_Addr)where;
208271469Skib		    break;
209271469Skib		case R_386_COPY:
210271469Skib			/*
211271469Skib			 * These are deferred until all other
212271469Skib			 * relocations have been done.  All we do here
213271469Skib			 * is make sure that the COPY relocation is
214271469Skib			 * not in a shared library.  They are allowed
215271469Skib			 * only in executable files.
216271469Skib			 */
217271469Skib			if (!obj->mainprog) {
218271469Skib				_rtld_error("%s: Unexpected R_386_COPY "
219271469Skib				    "relocation in shared library", obj->path);
220271469Skib				goto done;
221133063Sdfr			}
222271469Skib			break;
223271469Skib		case R_386_GLOB_DAT:
224271469Skib			*where = symval;
225271469Skib			break;
226271469Skib		case R_386_RELATIVE:
227271469Skib			*where += (Elf_Addr)obj->relocbase;
228271469Skib			break;
229271469Skib		case R_386_TLS_TPOFF:
230271469Skib		case R_386_TLS_TPOFF32:
231271469Skib			/*
232271469Skib			 * We lazily allocate offsets for static TLS
233271469Skib			 * as we see the first relocation that
234271469Skib			 * references the TLS block. This allows us to
235271469Skib			 * support (small amounts of) static TLS in
236271469Skib			 * dynamically loaded modules. If we run out
237271469Skib			 * of space, we generate an error.
238271469Skib			 */
239271469Skib			if (!defobj->tls_done) {
240271469Skib				if (!allocate_tls_offset((Obj_Entry*) defobj)) {
241271469Skib					_rtld_error("%s: No space available "
242271469Skib					    "for static Thread Local Storage",
243271469Skib					    obj->path);
244271469Skib					goto done;
245271469Skib				}
246271469Skib			}
247271469Skib			add = (Elf_Addr)(def->st_value - defobj->tlsoffset);
248271469Skib			if (ELF_R_TYPE(rel->r_info) == R_386_TLS_TPOFF)
249271469Skib				*where += add;
250271469Skib			else
251271469Skib				*where -= add;
252271469Skib			break;
253271469Skib		case R_386_TLS_DTPMOD32:
254271469Skib			*where += (Elf_Addr)defobj->tlsindex;
255271469Skib			break;
256271469Skib		case R_386_TLS_DTPOFF32:
257271469Skib			*where += (Elf_Addr) def->st_value;
258271469Skib			break;
259271469Skib		default:
260271469Skib			_rtld_error("%s: Unsupported relocation type %d"
261271469Skib			    " in non-PLT relocations\n", obj->path,
262271469Skib			    ELF_R_TYPE(rel->r_info));
263133063Sdfr			goto done;
264133063Sdfr		}
26538816Sdfr	}
26698103Sdillon	r = 0;
26798103Sdillondone:
268271469Skib	free(cache);
269233231Skib	return (r);
27038816Sdfr}
27138816Sdfr
27238816Sdfr/* Process the PLT relocations. */
27338816Sdfrint
27456780Sjdpreloc_plt(Obj_Entry *obj)
27538816Sdfr{
27648205Sjdp    const Elf_Rel *rellim;
27748205Sjdp    const Elf_Rel *rel;
27838816Sdfr
27948205Sjdp    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
28048205Sjdp    for (rel = obj->pltrel;  rel < rellim;  rel++) {
281228435Skib	Elf_Addr *where/*, val*/;
28238816Sdfr
283228435Skib	switch (ELF_R_TYPE(rel->r_info)) {
284228435Skib	case R_386_JMP_SLOT:
285228435Skib	  /* Relocate the GOT slot pointing into the PLT. */
286228435Skib	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
287228435Skib	  *where += (Elf_Addr)obj->relocbase;
288228435Skib	  break;
28938816Sdfr
290228435Skib	case R_386_IRELATIVE:
291228435Skib	  obj->irelative = true;
292228435Skib	  break;
293228435Skib
294228435Skib	default:
295228435Skib	  _rtld_error("Unknown relocation type %x in PLT",
296228435Skib	    ELF_R_TYPE(rel->r_info));
297228435Skib	  return (-1);
298228435Skib	}
29956780Sjdp    }
30056780Sjdp    return 0;
30156780Sjdp}
30238816Sdfr
30356780Sjdp/* Relocate the jump slots in an object. */
30456780Sjdpint
305233231Skibreloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
30656780Sjdp{
30756780Sjdp    const Elf_Rel *rellim;
30856780Sjdp    const Elf_Rel *rel;
30948205Sjdp
31056780Sjdp    if (obj->jmpslots_done)
31156780Sjdp	return 0;
31256780Sjdp    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
31356780Sjdp    for (rel = obj->pltrel;  rel < rellim;  rel++) {
31485004Sdfr	Elf_Addr *where, target;
31556780Sjdp	const Elf_Sym *def;
31656780Sjdp	const Obj_Entry *defobj;
31756780Sjdp
318228435Skib	switch (ELF_R_TYPE(rel->r_info)) {
319228435Skib	case R_386_JMP_SLOT:
320228435Skib	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
321233231Skib	  def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
322233231Skib		SYMLOOK_IN_PLT | flags, NULL, lockstate);
323228435Skib	  if (def == NULL)
324228435Skib	      return (-1);
325228435Skib	  if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
326228435Skib	      obj->gnu_ifunc = true;
327228435Skib	      continue;
328228435Skib	  }
329228435Skib	  target = (Elf_Addr)(defobj->relocbase + def->st_value);
330228435Skib	  reloc_jmpslot(where, target, defobj, obj, rel);
331228435Skib	  break;
332228435Skib
333228435Skib	case R_386_IRELATIVE:
334228435Skib	  break;
335228435Skib
336228435Skib	default:
337228435Skib	  _rtld_error("Unknown relocation type %x in PLT",
338228435Skib	    ELF_R_TYPE(rel->r_info));
339228435Skib	  return (-1);
340228435Skib	}
34148205Sjdp    }
342228435Skib
34356780Sjdp    obj->jmpslots_done = true;
34438816Sdfr    return 0;
34538816Sdfr}
346133063Sdfr
347228435Skibint
348228435Skibreloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
349228435Skib{
350228435Skib    const Elf_Rel *rellim;
351228435Skib    const Elf_Rel *rel;
352228435Skib    Elf_Addr *where, target;
353228435Skib
354228503Skib    if (!obj->irelative)
355228503Skib	return (0);
356228435Skib    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
357228435Skib    for (rel = obj->pltrel;  rel < rellim;  rel++) {
358228435Skib	switch (ELF_R_TYPE(rel->r_info)) {
359228435Skib	case R_386_IRELATIVE:
360228435Skib	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
361228503Skib	  lock_release(rtld_bind_lock, lockstate);
362309061Skib	  target = call_ifunc_resolver(obj->relocbase + *where);
363228503Skib	  wlock_acquire(rtld_bind_lock, lockstate);
364228435Skib	  *where = target;
365228435Skib	  break;
366228435Skib	}
367228435Skib    }
368228503Skib    obj->irelative = false;
369228435Skib    return (0);
370228435Skib}
371228435Skib
372228435Skibint
373233231Skibreloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
374228435Skib{
375228435Skib    const Elf_Rel *rellim;
376228435Skib    const Elf_Rel *rel;
377228435Skib
378228435Skib    if (!obj->gnu_ifunc)
379228435Skib	return (0);
380228435Skib    rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
381228435Skib    for (rel = obj->pltrel;  rel < rellim;  rel++) {
382228435Skib	Elf_Addr *where, target;
383228435Skib	const Elf_Sym *def;
384228435Skib	const Obj_Entry *defobj;
385228435Skib
386228435Skib	switch (ELF_R_TYPE(rel->r_info)) {
387228435Skib	case R_386_JMP_SLOT:
388228435Skib	  where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
389233231Skib	  def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
390233231Skib		SYMLOOK_IN_PLT | flags, NULL, lockstate);
391228435Skib	  if (def == NULL)
392228435Skib	      return (-1);
393228435Skib	  if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
394228435Skib	      continue;
395228503Skib	  lock_release(rtld_bind_lock, lockstate);
396228435Skib	  target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
397228503Skib	  wlock_acquire(rtld_bind_lock, lockstate);
398228435Skib	  reloc_jmpslot(where, target, defobj, obj, rel);
399228435Skib	  break;
400228435Skib	}
401228435Skib    }
402228435Skib
403228435Skib    obj->gnu_ifunc = false;
404228435Skib    return (0);
405228435Skib}
406228435Skib
407309061Skibuint32_t cpu_feature, cpu_feature2, cpu_stdext_feature, cpu_stdext_feature2;
408309061Skib
409309061Skibstatic void
410309061Skibrtld_cpuid_count(int idx, int cnt, u_int *p)
411309061Skib{
412309061Skib
413309061Skib	__asm __volatile(
414309061Skib	    "	pushl	%%ebx\n"
415309061Skib	    "	cpuid\n"
416309061Skib	    "	movl	%%ebx,%1\n"
417309061Skib	    "	popl	%%ebx\n"
418309061Skib	    : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3])
419309061Skib	    :  "0" (idx), "2" (cnt));
420309061Skib}
421309061Skib
422133063Sdfrvoid
423309061Skibifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
424309061Skib{
425309061Skib	u_int p[4], cpu_high;
426309061Skib	int cpuid_supported;
427309061Skib
428309061Skib	__asm __volatile(
429309061Skib	    "	pushfl\n"
430309061Skib	    "	popl	%%eax\n"
431309061Skib	    "	movl    %%eax,%%ecx\n"
432309061Skib	    "	xorl    $0x200000,%%eax\n"
433309061Skib	    "	pushl	%%eax\n"
434309061Skib	    "	popfl\n"
435309061Skib	    "	pushfl\n"
436309061Skib	    "	popl    %%eax\n"
437309061Skib	    "	xorl    %%eax,%%ecx\n"
438309061Skib	    "	je	1f\n"
439309061Skib	    "	movl	$1,%0\n"
440309061Skib	    "	jmp	2f\n"
441309061Skib	    "1:	movl	$0,%0\n"
442309061Skib	    "2:\n"
443309061Skib	    : "=r" (cpuid_supported) : : "eax", "ecx");
444309061Skib	if (!cpuid_supported)
445309061Skib		return;
446309061Skib
447309061Skib	rtld_cpuid_count(1, 0, p);
448309061Skib	cpu_feature = p[3];
449309061Skib	cpu_feature2 = p[2];
450309061Skib	rtld_cpuid_count(0, 0, p);
451309061Skib	cpu_high = p[0];
452309061Skib	if (cpu_high >= 7) {
453309061Skib		rtld_cpuid_count(7, 0, p);
454309061Skib		cpu_stdext_feature = p[1];
455309061Skib		cpu_stdext_feature2 = p[2];
456309061Skib	}
457309061Skib}
458309061Skib
459309061Skibvoid
460331206Smariuspre_init(void)
461331206Smarius{
462331206Smarius
463331206Smarius}
464331206Smarius
465331206Smariusvoid
466133063Sdfrallocate_initial_tls(Obj_Entry *objs)
467133063Sdfr{
468133063Sdfr    void* tls;
469133063Sdfr
470133063Sdfr    /*
471133063Sdfr     * Fix the size of the static TLS block by using the maximum
472133063Sdfr     * offset allocated so far and adding a bit for dynamic modules to
473133063Sdfr     * use.
474133063Sdfr     */
475133063Sdfr    tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA;
476157198Sdavidxu    tls = allocate_tls(objs, NULL, 3*sizeof(Elf_Addr), sizeof(Elf_Addr));
477147673Speter    i386_set_gsbase(tls);
478133063Sdfr}
479133063Sdfr
480133063Sdfr/* GNU ABI */
481133063Sdfr__attribute__((__regparm__(1)))
482133063Sdfrvoid *___tls_get_addr(tls_index *ti)
483133063Sdfr{
484133063Sdfr    Elf_Addr** segbase;
485133063Sdfr
486133063Sdfr    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
487133063Sdfr
488133063Sdfr    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
489133063Sdfr}
490133063Sdfr
491133063Sdfr/* Sun ABI */
492133063Sdfrvoid *__tls_get_addr(tls_index *ti)
493133063Sdfr{
494133063Sdfr    Elf_Addr** segbase;
495133063Sdfr
496133063Sdfr    __asm __volatile("movl %%gs:0, %0" : "=r" (segbase));
497133063Sdfr
498133063Sdfr    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
499133063Sdfr}
500