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$
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/sysarch.h>
3738816Sdfr
3838816Sdfr#include <dlfcn.h>
3938816Sdfr#include <err.h>
4038816Sdfr#include <errno.h>
4138816Sdfr#include <fcntl.h>
4238816Sdfr#include <stdarg.h>
4338816Sdfr#include <stdio.h>
4438816Sdfr#include <stdlib.h>
4538816Sdfr#include <string.h>
4638816Sdfr#include <unistd.h>
4738816Sdfr
4838816Sdfr#include "debug.h"
4938816Sdfr#include "rtld.h"
5038816Sdfr
5138816Sdfr/*
52115280Speter * Process the special R_X86_64_COPY relocations in the main program.  These
5338816Sdfr * copy data from a shared object into a region in the main program's BSS
5438816Sdfr * segment.
5538816Sdfr *
5638816Sdfr * Returns 0 on success, -1 on failure.
5738816Sdfr */
5838816Sdfrint
5938816Sdfrdo_copy_relocations(Obj_Entry *dstobj)
6038816Sdfr{
61115280Speter    const Elf_Rela *relalim;
62115280Speter    const Elf_Rela *rela;
6338816Sdfr
6438816Sdfr    assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
6538816Sdfr
66115280Speter    relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + dstobj->relasize);
67115280Speter    for (rela = dstobj->rela;  rela < relalim;  rela++) {
68115280Speter	if (ELF_R_TYPE(rela->r_info) == R_X86_64_COPY) {
6938816Sdfr	    void *dstaddr;
7038816Sdfr	    const Elf_Sym *dstsym;
7138816Sdfr	    const char *name;
7238816Sdfr	    size_t size;
7338816Sdfr	    const void *srcaddr;
7438816Sdfr	    const Elf_Sym *srcsym;
75216695Skib	    const Obj_Entry *srcobj, *defobj;
76216695Skib	    SymLook req;
77216695Skib	    int res;
7838816Sdfr
79115280Speter	    dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
80115280Speter	    dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
8138816Sdfr	    name = dstobj->strtab + dstsym->st_name;
8238816Sdfr	    size = dstsym->st_size;
83216695Skib	    symlook_init(&req, name);
84216695Skib	    req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
85233231Skib	    req.flags = SYMLOOK_EARLY;
8638816Sdfr
87216695Skib	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
88216695Skib		res = symlook_obj(&req, srcobj);
89216695Skib		if (res == 0) {
90216695Skib		    srcsym = req.sym_out;
91216695Skib		    defobj = req.defobj_out;
9238816Sdfr		    break;
93216695Skib		}
94216695Skib	    }
9538816Sdfr
9638816Sdfr	    if (srcobj == NULL) {
9738816Sdfr		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
9838816Sdfr		  " relocation in %s", name, dstobj->path);
9938816Sdfr		return -1;
10038816Sdfr	    }
10138816Sdfr
102216695Skib	    srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
10338816Sdfr	    memcpy(dstaddr, srcaddr, size);
10438816Sdfr	}
10538816Sdfr    }
10638816Sdfr
10738816Sdfr    return 0;
10838816Sdfr}
10938816Sdfr
11045501Sjdp/* Initialize the special GOT entries. */
11145501Sjdpvoid
11245501Sjdpinit_pltgot(Obj_Entry *obj)
11345501Sjdp{
11445501Sjdp    if (obj->pltgot != NULL) {
11545501Sjdp	obj->pltgot[1] = (Elf_Addr) obj;
11645501Sjdp	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
11745501Sjdp    }
11845501Sjdp}
11945501Sjdp
12038816Sdfr/* Process the non-PLT relocations. */
12138816Sdfrint
122233231Skibreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
123233231Skib    RtldLockState *lockstate)
12438816Sdfr{
125115280Speter	const Elf_Rela *relalim;
126115280Speter	const Elf_Rela *rela;
12776296Sjdp	SymCache *cache;
12898100Sdillon	int r = -1;
12938816Sdfr
13098100Sdillon	/*
13198100Sdillon	 * The dynamic loader may be called from a thread, we have
13298100Sdillon	 * limited amounts of stack available so we cannot use alloca().
13398100Sdillon	 */
134208256Srdivacky	if (obj != obj_rtld) {
135234841Skib	    cache = calloc(obj->dynsymcount, sizeof(SymCache));
136208256Srdivacky	    /* No need to check for NULL here */
137208256Srdivacky	} else
13898100Sdillon	    cache = NULL;
13976296Sjdp
140115280Speter	relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
141115280Speter	for (rela = obj->rela;  rela < relalim;  rela++) {
142115280Speter	    Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
143123481Speter	    Elf32_Addr *where32 = (Elf32_Addr *)where;
14438816Sdfr
145115280Speter	    switch (ELF_R_TYPE(rela->r_info)) {
14638816Sdfr
147115280Speter	    case R_X86_64_NONE:
14838816Sdfr		break;
14938816Sdfr
150115280Speter	    case R_X86_64_64:
15138816Sdfr		{
15238816Sdfr		    const Elf_Sym *def;
15338816Sdfr		    const Obj_Entry *defobj;
15438816Sdfr
155115280Speter		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
156233231Skib		      flags, cache, lockstate);
15738816Sdfr		    if (def == NULL)
15898100Sdillon			goto done;
15938816Sdfr
160115280Speter		    *where = (Elf_Addr) (defobj->relocbase + def->st_value + rela->r_addend);
16138816Sdfr		}
16238816Sdfr		break;
16338816Sdfr
164115280Speter	    case R_X86_64_PC32:
16538816Sdfr		/*
16638816Sdfr		 * I don't think the dynamic linker should ever see this
16738816Sdfr		 * type of relocation.  But the binutils-2.6 tools sometimes
16838816Sdfr		 * generate it.
16938816Sdfr		 */
17038816Sdfr		{
17138816Sdfr		    const Elf_Sym *def;
17238816Sdfr		    const Obj_Entry *defobj;
17338816Sdfr
174115280Speter		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175233231Skib		      flags, cache, lockstate);
17638816Sdfr		    if (def == NULL)
17798100Sdillon			goto done;
17838816Sdfr
179123481Speter		    *where32 = (Elf32_Addr) (unsigned long) (defobj->relocbase +
180123481Speter		        def->st_value + rela->r_addend - (Elf_Addr) where);
18138816Sdfr		}
18238816Sdfr		break;
183115280Speter	/* missing: R_X86_64_GOT32 R_X86_64_PLT32 */
18438816Sdfr
185115280Speter	    case R_X86_64_COPY:
18638816Sdfr		/*
18738816Sdfr		 * These are deferred until all other relocations have
18838816Sdfr		 * been done.  All we do here is make sure that the COPY
18938816Sdfr		 * relocation is not in a shared library.  They are allowed
19038816Sdfr		 * only in executable files.
19138816Sdfr		 */
19238816Sdfr		if (!obj->mainprog) {
193115280Speter		    _rtld_error("%s: Unexpected R_X86_64_COPY relocation"
19438816Sdfr		      " in shared library", obj->path);
19598100Sdillon		    goto done;
19638816Sdfr		}
19738816Sdfr		break;
19838816Sdfr
199115280Speter	    case R_X86_64_GLOB_DAT:
20038816Sdfr		{
20138816Sdfr		    const Elf_Sym *def;
20238816Sdfr		    const Obj_Entry *defobj;
20338816Sdfr
204115280Speter		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
205233231Skib		      flags, cache, lockstate);
20638816Sdfr		    if (def == NULL)
20798100Sdillon			goto done;
20838816Sdfr
20938816Sdfr		    *where = (Elf_Addr) (defobj->relocbase + def->st_value);
21038816Sdfr		}
21138816Sdfr		break;
21238816Sdfr
213133063Sdfr	    case R_X86_64_TPOFF64:
214133063Sdfr		{
215133063Sdfr		    const Elf_Sym *def;
216133063Sdfr		    const Obj_Entry *defobj;
217133063Sdfr
218133063Sdfr		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
219233231Skib		      flags, cache, lockstate);
220133063Sdfr		    if (def == NULL)
221133063Sdfr			goto done;
222133063Sdfr
223133063Sdfr		    /*
224133063Sdfr		     * We lazily allocate offsets for static TLS as we
225133063Sdfr		     * see the first relocation that references the
226133063Sdfr		     * TLS block. This allows us to support (small
227133063Sdfr		     * amounts of) static TLS in dynamically loaded
228133063Sdfr		     * modules. If we run out of space, we generate an
229133063Sdfr		     * error.
230133063Sdfr		     */
231133063Sdfr		    if (!defobj->tls_done) {
232133063Sdfr			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
233133063Sdfr			    _rtld_error("%s: No space available for static "
234133063Sdfr					"Thread Local Storage", obj->path);
235133063Sdfr			    goto done;
236133063Sdfr			}
237133063Sdfr		    }
238133063Sdfr
239133063Sdfr		    *where = (Elf_Addr) (def->st_value - defobj->tlsoffset +
240133063Sdfr					 rela->r_addend);
241133063Sdfr		}
242133063Sdfr		break;
243133063Sdfr
244133063Sdfr	    case R_X86_64_TPOFF32:
245133063Sdfr		{
246133063Sdfr		    const Elf_Sym *def;
247133063Sdfr		    const Obj_Entry *defobj;
248133063Sdfr
249133063Sdfr		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
250233231Skib		      flags, cache, lockstate);
251133063Sdfr		    if (def == NULL)
252133063Sdfr			goto done;
253133063Sdfr
254133063Sdfr		    /*
255133063Sdfr		     * We lazily allocate offsets for static TLS as we
256133063Sdfr		     * see the first relocation that references the
257133063Sdfr		     * TLS block. This allows us to support (small
258133063Sdfr		     * amounts of) static TLS in dynamically loaded
259133063Sdfr		     * modules. If we run out of space, we generate an
260133063Sdfr		     * error.
261133063Sdfr		     */
262133063Sdfr		    if (!defobj->tls_done) {
263133063Sdfr			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
264133063Sdfr			    _rtld_error("%s: No space available for static "
265133063Sdfr					"Thread Local Storage", obj->path);
266133063Sdfr			    goto done;
267133063Sdfr			}
268133063Sdfr		    }
269133063Sdfr
270133063Sdfr		    *where32 = (Elf32_Addr) (def->st_value -
271133063Sdfr					     defobj->tlsoffset +
272133063Sdfr					     rela->r_addend);
273133063Sdfr		}
274133063Sdfr		break;
275133063Sdfr
276133063Sdfr	    case R_X86_64_DTPMOD64:
277133063Sdfr		{
278133063Sdfr		    const Elf_Sym *def;
279133063Sdfr		    const Obj_Entry *defobj;
280133063Sdfr
281133063Sdfr		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
282233231Skib		      flags, cache, lockstate);
283133063Sdfr		    if (def == NULL)
284133063Sdfr			goto done;
285133063Sdfr
286133063Sdfr		    *where += (Elf_Addr) defobj->tlsindex;
287133063Sdfr		}
288133063Sdfr		break;
289133063Sdfr
290133063Sdfr	    case R_X86_64_DTPOFF64:
291133063Sdfr		{
292133063Sdfr		    const Elf_Sym *def;
293133063Sdfr		    const Obj_Entry *defobj;
294133063Sdfr
295133063Sdfr		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
296233231Skib		      flags, cache, lockstate);
297133063Sdfr		    if (def == NULL)
298133063Sdfr			goto done;
299133063Sdfr
300133063Sdfr		    *where += (Elf_Addr) (def->st_value + rela->r_addend);
301133063Sdfr		}
302133063Sdfr		break;
303133063Sdfr
304133063Sdfr	    case R_X86_64_DTPOFF32:
305133063Sdfr		{
306133063Sdfr		    const Elf_Sym *def;
307133063Sdfr		    const Obj_Entry *defobj;
308133063Sdfr
309133063Sdfr		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
310233231Skib		      flags, cache, lockstate);
311133063Sdfr		    if (def == NULL)
312133063Sdfr			goto done;
313133063Sdfr
314133063Sdfr		    *where32 += (Elf32_Addr) (def->st_value + rela->r_addend);
315133063Sdfr		}
316133063Sdfr		break;
317133063Sdfr
318115280Speter	    case R_X86_64_RELATIVE:
319115280Speter		*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
32038816Sdfr		break;
32138816Sdfr
322115280Speter	/* missing: R_X86_64_GOTPCREL, R_X86_64_32, R_X86_64_32S, R_X86_64_16, R_X86_64_PC16, R_X86_64_8, R_X86_64_PC8 */
323115280Speter
32438816Sdfr	    default:
325153503Smarcel		_rtld_error("%s: Unsupported relocation type %u"
32638816Sdfr		  " in non-PLT relocations\n", obj->path,
327153503Smarcel		  (unsigned int)ELF_R_TYPE(rela->r_info));
32898100Sdillon		goto done;
32938816Sdfr	    }
33038816Sdfr	}
33198103Sdillon	r = 0;
33298103Sdillondone:
333208256Srdivacky	if (cache != NULL)
334208256Srdivacky	    free(cache);
335233231Skib	return (r);
33638816Sdfr}
33738816Sdfr
33838816Sdfr/* Process the PLT relocations. */
33938816Sdfrint
34056780Sjdpreloc_plt(Obj_Entry *obj)
34138816Sdfr{
342115280Speter    const Elf_Rela *relalim;
343115280Speter    const Elf_Rela *rela;
34438816Sdfr
345115280Speter    relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
346115280Speter    for (rela = obj->pltrela;  rela < relalim;  rela++) {
34748205Sjdp	Elf_Addr *where;
34838816Sdfr
349228435Skib	switch(ELF_R_TYPE(rela->r_info)) {
350228435Skib	case R_X86_64_JMP_SLOT:
351228435Skib	  /* Relocate the GOT slot pointing into the PLT. */
352228435Skib	  where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
353228435Skib	  *where += (Elf_Addr)obj->relocbase;
354228435Skib	  break;
35538816Sdfr
356228435Skib	case R_X86_64_IRELATIVE:
357228435Skib	  obj->irelative = true;
358228435Skib	  break;
359228435Skib
360228435Skib	default:
361228435Skib	  _rtld_error("Unknown relocation type %x in PLT",
362228435Skib	    (unsigned int)ELF_R_TYPE(rela->r_info));
363228435Skib	  return (-1);
364228435Skib	}
36556780Sjdp    }
36656780Sjdp    return 0;
36756780Sjdp}
36838816Sdfr
36956780Sjdp/* Relocate the jump slots in an object. */
37056780Sjdpint
371233231Skibreloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
37256780Sjdp{
373115280Speter    const Elf_Rela *relalim;
374115280Speter    const Elf_Rela *rela;
37548205Sjdp
37656780Sjdp    if (obj->jmpslots_done)
37756780Sjdp	return 0;
378115280Speter    relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
379115280Speter    for (rela = obj->pltrela;  rela < relalim;  rela++) {
38085004Sdfr	Elf_Addr *where, target;
38156780Sjdp	const Elf_Sym *def;
38256780Sjdp	const Obj_Entry *defobj;
38356780Sjdp
384228435Skib	switch (ELF_R_TYPE(rela->r_info)) {
385228435Skib	case R_X86_64_JMP_SLOT:
386228435Skib	  where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
387233231Skib	  def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
388233231Skib		SYMLOOK_IN_PLT | flags, NULL, lockstate);
389228435Skib	  if (def == NULL)
390228435Skib	      return (-1);
391228435Skib	  if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
392228435Skib	      obj->gnu_ifunc = true;
393228435Skib	      continue;
394228435Skib	  }
395228435Skib	  target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
396228435Skib	  reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
397228435Skib	  break;
398228435Skib
399228435Skib	case R_X86_64_IRELATIVE:
400228435Skib	  break;
401228435Skib
402228435Skib	default:
403228435Skib	  _rtld_error("Unknown relocation type %x in PLT",
404228435Skib	    (unsigned int)ELF_R_TYPE(rela->r_info));
405228435Skib	  return (-1);
406228435Skib	}
40748205Sjdp    }
40856780Sjdp    obj->jmpslots_done = true;
40938816Sdfr    return 0;
41038816Sdfr}
411133063Sdfr
412228435Skibint
413228435Skibreloc_iresolve(Obj_Entry *obj, RtldLockState *lockstate)
414228435Skib{
415228435Skib    const Elf_Rela *relalim;
416228435Skib    const Elf_Rela *rela;
417228435Skib
418228503Skib    if (!obj->irelative)
419228503Skib	return (0);
420228435Skib    relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
421228435Skib    for (rela = obj->pltrela;  rela < relalim;  rela++) {
422228435Skib	Elf_Addr *where, target, *ptr;
423228435Skib
424228435Skib	switch (ELF_R_TYPE(rela->r_info)) {
425228435Skib	case R_X86_64_JMP_SLOT:
426228435Skib	  break;
427228435Skib
428228435Skib	case R_X86_64_IRELATIVE:
429228435Skib	  ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
430228435Skib	  where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
431228503Skib	  lock_release(rtld_bind_lock, lockstate);
432228435Skib	  target = ((Elf_Addr (*)(void))ptr)();
433228503Skib	  wlock_acquire(rtld_bind_lock, lockstate);
434228435Skib	  *where = target;
435228435Skib	  break;
436228435Skib	}
437228435Skib    }
438228503Skib    obj->irelative = false;
439228435Skib    return (0);
440228435Skib}
441228435Skib
442228435Skibint
443233231Skibreloc_gnu_ifunc(Obj_Entry *obj, int flags, RtldLockState *lockstate)
444228435Skib{
445228435Skib    const Elf_Rela *relalim;
446228435Skib    const Elf_Rela *rela;
447228435Skib
448228435Skib    if (!obj->gnu_ifunc)
449228435Skib	return (0);
450228435Skib    relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
451228435Skib    for (rela = obj->pltrela;  rela < relalim;  rela++) {
452228435Skib	Elf_Addr *where, target;
453228435Skib	const Elf_Sym *def;
454228435Skib	const Obj_Entry *defobj;
455228435Skib
456228435Skib	switch (ELF_R_TYPE(rela->r_info)) {
457228435Skib	case R_X86_64_JMP_SLOT:
458228435Skib	  where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
459233231Skib	  def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
460233231Skib		SYMLOOK_IN_PLT | flags, NULL, lockstate);
461228435Skib	  if (def == NULL)
462228435Skib	      return (-1);
463228435Skib	  if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
464228435Skib	      continue;
465228503Skib	  lock_release(rtld_bind_lock, lockstate);
466228435Skib	  target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
467228503Skib	  wlock_acquire(rtld_bind_lock, lockstate);
468228435Skib	  reloc_jmpslot(where, target, defobj, obj, (const Elf_Rel *)rela);
469228435Skib	  break;
470228435Skib	}
471228435Skib    }
472228435Skib    obj->gnu_ifunc = false;
473228503Skib    return (0);
474228435Skib}
475228435Skib
476133063Sdfrvoid
477133063Sdfrallocate_initial_tls(Obj_Entry *objs)
478133063Sdfr{
479133063Sdfr    /*
480133063Sdfr     * Fix the size of the static TLS block by using the maximum
481133063Sdfr     * offset allocated so far and adding a bit for dynamic modules to
482133063Sdfr     * use.
483133063Sdfr     */
484133063Sdfr    tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA;
485133063Sdfr    amd64_set_fsbase(allocate_tls(objs, 0,
486157198Sdavidxu				  3*sizeof(Elf_Addr), sizeof(Elf_Addr)));
487133063Sdfr}
488133063Sdfr
489133063Sdfrvoid *__tls_get_addr(tls_index *ti)
490133063Sdfr{
491133063Sdfr    Elf_Addr** segbase;
492133063Sdfr
493133063Sdfr    __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
494133063Sdfr
495133063Sdfr    return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset);
496133063Sdfr}
497