127bd4146SNathan Whitehorn /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */
227bd4146SNathan Whitehorn
327bd4146SNathan Whitehorn /*-
4b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
5e6209940SPedro F. Giffuni *
627bd4146SNathan Whitehorn * Copyright (C) 1998 Tsubai Masanari
727bd4146SNathan Whitehorn * All rights reserved.
827bd4146SNathan Whitehorn *
927bd4146SNathan Whitehorn * Redistribution and use in source and binary forms, with or without
1027bd4146SNathan Whitehorn * modification, are permitted provided that the following conditions
1127bd4146SNathan Whitehorn * are met:
1227bd4146SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright
1327bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer.
1427bd4146SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright
1527bd4146SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the
1627bd4146SNathan Whitehorn * documentation and/or other materials provided with the distribution.
1727bd4146SNathan Whitehorn * 3. The name of the author may not be used to endorse or promote products
1827bd4146SNathan Whitehorn * derived from this software without specific prior written permission.
1927bd4146SNathan Whitehorn *
2027bd4146SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2127bd4146SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2227bd4146SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2327bd4146SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2427bd4146SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2527bd4146SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2627bd4146SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2727bd4146SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2827bd4146SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2927bd4146SNathan Whitehorn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3027bd4146SNathan Whitehorn */
3127bd4146SNathan Whitehorn
3227bd4146SNathan Whitehorn #include <sys/param.h>
3327bd4146SNathan Whitehorn #include <sys/mman.h>
3441b4ec8aSBrandon Bergren #include <sys/sysctl.h>
3527bd4146SNathan Whitehorn
3627bd4146SNathan Whitehorn #include <errno.h>
3727bd4146SNathan Whitehorn #include <stdio.h>
3827bd4146SNathan Whitehorn #include <stdlib.h>
3927bd4146SNathan Whitehorn #include <string.h>
4027bd4146SNathan Whitehorn #include <unistd.h>
41a29cc9a3SAndriy Gapon #include <machine/cpu.h>
4227bd4146SNathan Whitehorn #include <machine/md_var.h>
4327bd4146SNathan Whitehorn
4427bd4146SNathan Whitehorn #include "debug.h"
4527bd4146SNathan Whitehorn #include "rtld.h"
4627bd4146SNathan Whitehorn
4729ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
4827bd4146SNathan Whitehorn struct funcdesc {
4927bd4146SNathan Whitehorn Elf_Addr addr;
5027bd4146SNathan Whitehorn Elf_Addr toc;
5127bd4146SNathan Whitehorn Elf_Addr env;
5227bd4146SNathan Whitehorn };
5329ba9b61SNathan Whitehorn #endif
5427bd4146SNathan Whitehorn
551cd90a2cSAndrew Turner bool
arch_digest_dynamic(struct Struct_Obj_Entry * obj,const Elf_Dyn * dynp)561cd90a2cSAndrew Turner arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp)
571cd90a2cSAndrew Turner {
581cd90a2cSAndrew Turner if (dynp->d_tag == DT_PPC64_GLINK) {
591cd90a2cSAndrew Turner obj->glink = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr);
601cd90a2cSAndrew Turner return (true);
611cd90a2cSAndrew Turner }
621cd90a2cSAndrew Turner
631cd90a2cSAndrew Turner return (false);
641cd90a2cSAndrew Turner }
651cd90a2cSAndrew Turner
6627bd4146SNathan Whitehorn /*
6727bd4146SNathan Whitehorn * Process the R_PPC_COPY relocations
6827bd4146SNathan Whitehorn */
6927bd4146SNathan Whitehorn int
do_copy_relocations(Obj_Entry * dstobj)7027bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj)
7127bd4146SNathan Whitehorn {
7227bd4146SNathan Whitehorn const Elf_Rela *relalim;
7327bd4146SNathan Whitehorn const Elf_Rela *rela;
7427bd4146SNathan Whitehorn
7527bd4146SNathan Whitehorn /*
7627bd4146SNathan Whitehorn * COPY relocs are invalid outside of the main program
7727bd4146SNathan Whitehorn */
7827bd4146SNathan Whitehorn assert(dstobj->mainprog);
7927bd4146SNathan Whitehorn
80903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *) dstobj->rela +
8127bd4146SNathan Whitehorn dstobj->relasize);
8227bd4146SNathan Whitehorn for (rela = dstobj->rela; rela < relalim; rela++) {
8327bd4146SNathan Whitehorn void *dstaddr;
8427bd4146SNathan Whitehorn const Elf_Sym *dstsym;
8527bd4146SNathan Whitehorn const char *name;
8627bd4146SNathan Whitehorn size_t size;
8727bd4146SNathan Whitehorn const void *srcaddr;
8827bd4146SNathan Whitehorn const Elf_Sym *srcsym = NULL;
898569deafSKonstantin Belousov const Obj_Entry *srcobj, *defobj;
908569deafSKonstantin Belousov SymLook req;
918569deafSKonstantin Belousov int res;
9227bd4146SNathan Whitehorn
9327bd4146SNathan Whitehorn if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
9427bd4146SNathan Whitehorn continue;
9527bd4146SNathan Whitehorn }
9627bd4146SNathan Whitehorn
9727bd4146SNathan Whitehorn dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
9827bd4146SNathan Whitehorn dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
9927bd4146SNathan Whitehorn name = dstobj->strtab + dstsym->st_name;
10027bd4146SNathan Whitehorn size = dstsym->st_size;
1018569deafSKonstantin Belousov symlook_init(&req, name);
1028569deafSKonstantin Belousov req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
103082f959aSKonstantin Belousov req.flags = SYMLOOK_EARLY;
10427bd4146SNathan Whitehorn
1059fee0541SKonstantin Belousov for (srcobj = globallist_next(dstobj); srcobj != NULL;
1069fee0541SKonstantin Belousov srcobj = globallist_next(srcobj)) {
1078569deafSKonstantin Belousov res = symlook_obj(&req, srcobj);
1088569deafSKonstantin Belousov if (res == 0) {
1098569deafSKonstantin Belousov srcsym = req.sym_out;
1108569deafSKonstantin Belousov defobj = req.defobj_out;
11127bd4146SNathan Whitehorn break;
11227bd4146SNathan Whitehorn }
11327bd4146SNathan Whitehorn }
11427bd4146SNathan Whitehorn
11527bd4146SNathan Whitehorn if (srcobj == NULL) {
11627bd4146SNathan Whitehorn _rtld_error("Undefined symbol \"%s\" "
11727bd4146SNathan Whitehorn " referenced from COPY"
11827bd4146SNathan Whitehorn " relocation in %s", name, dstobj->path);
11927bd4146SNathan Whitehorn return (-1);
12027bd4146SNathan Whitehorn }
12127bd4146SNathan Whitehorn
1228569deafSKonstantin Belousov srcaddr = (const void *)(defobj->relocbase+srcsym->st_value);
12327bd4146SNathan Whitehorn memcpy(dstaddr, srcaddr, size);
12427bd4146SNathan Whitehorn dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
12527bd4146SNathan Whitehorn }
12627bd4146SNathan Whitehorn
12727bd4146SNathan Whitehorn return (0);
12827bd4146SNathan Whitehorn }
12927bd4146SNathan Whitehorn
13027bd4146SNathan Whitehorn
13127bd4146SNathan Whitehorn /*
13227bd4146SNathan Whitehorn * Perform early relocation of the run-time linker image
13327bd4146SNathan Whitehorn */
13427bd4146SNathan Whitehorn void
reloc_non_plt_self(Elf_Dyn * dynp,Elf_Addr relocbase)13527bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
13627bd4146SNathan Whitehorn {
137a5d5e8ddSPedro F. Giffuni const Elf_Rela *rela = NULL, *relalim;
13827bd4146SNathan Whitehorn Elf_Addr relasz = 0;
13927bd4146SNathan Whitehorn Elf_Addr *where;
14027bd4146SNathan Whitehorn
14127bd4146SNathan Whitehorn /*
14227bd4146SNathan Whitehorn * Extract the rela/relasz values from the dynamic section
14327bd4146SNathan Whitehorn */
14427bd4146SNathan Whitehorn for (; dynp->d_tag != DT_NULL; dynp++) {
14527bd4146SNathan Whitehorn switch (dynp->d_tag) {
14627bd4146SNathan Whitehorn case DT_RELA:
14727bd4146SNathan Whitehorn rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
14827bd4146SNathan Whitehorn break;
14927bd4146SNathan Whitehorn case DT_RELASZ:
15027bd4146SNathan Whitehorn relasz = dynp->d_un.d_val;
15127bd4146SNathan Whitehorn break;
15227bd4146SNathan Whitehorn }
15327bd4146SNathan Whitehorn }
15427bd4146SNathan Whitehorn
15527bd4146SNathan Whitehorn /*
15627bd4146SNathan Whitehorn * Relocate these values
15727bd4146SNathan Whitehorn */
158903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)rela + relasz);
15927bd4146SNathan Whitehorn for (; rela < relalim; rela++) {
16027bd4146SNathan Whitehorn where = (Elf_Addr *)(relocbase + rela->r_offset);
16127bd4146SNathan Whitehorn *where = (Elf_Addr)(relocbase + rela->r_addend);
16227bd4146SNathan Whitehorn }
16327bd4146SNathan Whitehorn }
16427bd4146SNathan Whitehorn
16527bd4146SNathan Whitehorn
16627bd4146SNathan Whitehorn /*
16727bd4146SNathan Whitehorn * Relocate a non-PLT object with addend.
16827bd4146SNathan Whitehorn */
16927bd4146SNathan Whitehorn static int
reloc_nonplt_object(Obj_Entry * obj_rtld __unused,Obj_Entry * obj,const Elf_Rela * rela,SymCache * cache,int flags,RtldLockState * lockstate)170903e0ffdSAlex Richardson reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj,
171903e0ffdSAlex Richardson const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate)
17227bd4146SNathan Whitehorn {
17341b4ec8aSBrandon Bergren const Elf_Sym *def = NULL;
17427bd4146SNathan Whitehorn const Obj_Entry *defobj;
17541b4ec8aSBrandon Bergren Elf_Addr *where, symval = 0;
17627bd4146SNathan Whitehorn
17741b4ec8aSBrandon Bergren /*
17841b4ec8aSBrandon Bergren * First, resolve symbol for relocations which
17941b4ec8aSBrandon Bergren * reference symbols.
18041b4ec8aSBrandon Bergren */
18127bd4146SNathan Whitehorn switch (ELF_R_TYPE(rela->r_info)) {
18227bd4146SNathan Whitehorn
1839cc92083SNathan Whitehorn case R_PPC64_UADDR64: /* doubleword64 S + A */
1849cc92083SNathan Whitehorn case R_PPC64_ADDR64:
18527bd4146SNathan Whitehorn case R_PPC_GLOB_DAT:
18641b4ec8aSBrandon Bergren case R_PPC64_DTPMOD64:
18741b4ec8aSBrandon Bergren case R_PPC64_TPREL64:
18841b4ec8aSBrandon Bergren case R_PPC64_DTPREL64:
18927bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
190082f959aSKonstantin Belousov flags, cache, lockstate);
19127bd4146SNathan Whitehorn if (def == NULL) {
19227bd4146SNathan Whitehorn return (-1);
19327bd4146SNathan Whitehorn }
19427bd4146SNathan Whitehorn /*
19541b4ec8aSBrandon Bergren * If symbol is IFUNC, only perform relocation
19641b4ec8aSBrandon Bergren * when caller allowed it by passing
19741b4ec8aSBrandon Bergren * SYMLOOK_IFUNC flag. Skip the relocations
19841b4ec8aSBrandon Bergren * otherwise.
19941b4ec8aSBrandon Bergren *
20041b4ec8aSBrandon Bergren * Also error out in case IFUNC relocations
20141b4ec8aSBrandon Bergren * are specified for TLS, which cannot be
20241b4ec8aSBrandon Bergren * usefully interpreted.
20327bd4146SNathan Whitehorn */
20441b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
20541b4ec8aSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) {
20641b4ec8aSBrandon Bergren case R_PPC64_UADDR64:
20741b4ec8aSBrandon Bergren case R_PPC64_ADDR64:
20841b4ec8aSBrandon Bergren case R_PPC_GLOB_DAT:
20941b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) == 0) {
21041b4ec8aSBrandon Bergren dbg("Non-PLT reference to IFUNC found!");
21141b4ec8aSBrandon Bergren obj->non_plt_gnu_ifunc = true;
21241b4ec8aSBrandon Bergren return (0);
21341b4ec8aSBrandon Bergren }
21441b4ec8aSBrandon Bergren symval = (Elf_Addr)rtld_resolve_ifunc(
21541b4ec8aSBrandon Bergren defobj, def);
21641b4ec8aSBrandon Bergren break;
21741b4ec8aSBrandon Bergren default:
21841b4ec8aSBrandon Bergren _rtld_error("%s: IFUNC for TLS reloc",
21927bd4146SNathan Whitehorn obj->path);
22027bd4146SNathan Whitehorn return (-1);
22127bd4146SNathan Whitehorn }
22241b4ec8aSBrandon Bergren } else {
22341b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0)
22441b4ec8aSBrandon Bergren return (0);
22541b4ec8aSBrandon Bergren symval = (Elf_Addr)defobj->relocbase +
22641b4ec8aSBrandon Bergren def->st_value;
22741b4ec8aSBrandon Bergren }
22827bd4146SNathan Whitehorn break;
22941b4ec8aSBrandon Bergren default:
23041b4ec8aSBrandon Bergren if ((flags & SYMLOOK_IFUNC) != 0)
23141b4ec8aSBrandon Bergren return (0);
23241b4ec8aSBrandon Bergren }
23327bd4146SNathan Whitehorn
23441b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
23541b4ec8aSBrandon Bergren
23641b4ec8aSBrandon Bergren switch (ELF_R_TYPE(rela->r_info)) {
23741b4ec8aSBrandon Bergren case R_PPC_NONE:
23827bd4146SNathan Whitehorn break;
23941b4ec8aSBrandon Bergren case R_PPC64_UADDR64:
24041b4ec8aSBrandon Bergren case R_PPC64_ADDR64:
24141b4ec8aSBrandon Bergren case R_PPC_GLOB_DAT:
24241b4ec8aSBrandon Bergren /* Don't issue write if unnecessary; avoid COW page fault */
24341b4ec8aSBrandon Bergren if (*where != symval + rela->r_addend) {
24441b4ec8aSBrandon Bergren *where = symval + rela->r_addend;
24541b4ec8aSBrandon Bergren }
24641b4ec8aSBrandon Bergren break;
24727bd4146SNathan Whitehorn case R_PPC64_DTPMOD64:
24827bd4146SNathan Whitehorn *where = (Elf_Addr) defobj->tlsindex;
24927bd4146SNathan Whitehorn break;
25027bd4146SNathan Whitehorn case R_PPC64_TPREL64:
25127bd4146SNathan Whitehorn /*
25227bd4146SNathan Whitehorn * We lazily allocate offsets for static TLS as we
25327bd4146SNathan Whitehorn * see the first relocation that references the
25427bd4146SNathan Whitehorn * TLS block. This allows us to support (small
25527bd4146SNathan Whitehorn * amounts of) static TLS in dynamically loaded
25627bd4146SNathan Whitehorn * modules. If we run out of space, we generate an
25727bd4146SNathan Whitehorn * error.
25827bd4146SNathan Whitehorn */
259283a4f40SKonstantin Belousov if (!defobj->tls_static) {
260903e0ffdSAlex Richardson if (!allocate_tls_offset(
261903e0ffdSAlex Richardson __DECONST(Obj_Entry *, defobj))) {
26227bd4146SNathan Whitehorn _rtld_error("%s: No space available for static "
26327bd4146SNathan Whitehorn "Thread Local Storage", obj->path);
26427bd4146SNathan Whitehorn return (-1);
26527bd4146SNathan Whitehorn }
26627bd4146SNathan Whitehorn }
26727bd4146SNathan Whitehorn
26827bd4146SNathan Whitehorn *(Elf_Addr **)where = *where * sizeof(Elf_Addr)
26927bd4146SNathan Whitehorn + (Elf_Addr *)(def->st_value + rela->r_addend
27045a18a1fSJustin Hibbits + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
27127bd4146SNathan Whitehorn break;
27227bd4146SNathan Whitehorn case R_PPC64_DTPREL64:
27327bd4146SNathan Whitehorn *where += (Elf_Addr)(def->st_value + rela->r_addend
27427bd4146SNathan Whitehorn - TLS_DTV_OFFSET);
27541b4ec8aSBrandon Bergren break;
27641b4ec8aSBrandon Bergren case R_PPC_RELATIVE: /* doubleword64 B + A */
27741b4ec8aSBrandon Bergren symval = (Elf_Addr)(obj->relocbase + rela->r_addend);
27827bd4146SNathan Whitehorn
27941b4ec8aSBrandon Bergren /* As above, don't issue write unnecessarily */
28041b4ec8aSBrandon Bergren if (*where != symval) {
28141b4ec8aSBrandon Bergren *where = symval;
28241b4ec8aSBrandon Bergren }
28341b4ec8aSBrandon Bergren break;
28441b4ec8aSBrandon Bergren case R_PPC_COPY:
28541b4ec8aSBrandon Bergren /*
28641b4ec8aSBrandon Bergren * These are deferred until all other relocations
28741b4ec8aSBrandon Bergren * have been done. All we do here is make sure
28841b4ec8aSBrandon Bergren * that the COPY relocation is not in a shared
28941b4ec8aSBrandon Bergren * library. They are allowed only in executable
29041b4ec8aSBrandon Bergren * files.
29141b4ec8aSBrandon Bergren */
29241b4ec8aSBrandon Bergren if (!obj->mainprog) {
29341b4ec8aSBrandon Bergren _rtld_error("%s: Unexpected R_COPY "
29441b4ec8aSBrandon Bergren " relocation in shared library",
29541b4ec8aSBrandon Bergren obj->path);
29641b4ec8aSBrandon Bergren return (-1);
29741b4ec8aSBrandon Bergren }
29841b4ec8aSBrandon Bergren break;
29941b4ec8aSBrandon Bergren case R_PPC_IRELATIVE:
30041b4ec8aSBrandon Bergren /*
30141b4ec8aSBrandon Bergren * These will be handled by reloc_iresolve().
30241b4ec8aSBrandon Bergren */
30341b4ec8aSBrandon Bergren obj->irelative = true;
30441b4ec8aSBrandon Bergren break;
30541b4ec8aSBrandon Bergren case R_PPC_JMP_SLOT:
30641b4ec8aSBrandon Bergren /*
30741b4ec8aSBrandon Bergren * These will be handled by the plt/jmpslot routines
30841b4ec8aSBrandon Bergren */
30927bd4146SNathan Whitehorn break;
31027bd4146SNathan Whitehorn
31127bd4146SNathan Whitehorn default:
31227bd4146SNathan Whitehorn _rtld_error("%s: Unsupported relocation type %ld"
31327bd4146SNathan Whitehorn " in non-PLT relocations\n", obj->path,
31427bd4146SNathan Whitehorn ELF_R_TYPE(rela->r_info));
31527bd4146SNathan Whitehorn return (-1);
31627bd4146SNathan Whitehorn }
31727bd4146SNathan Whitehorn return (0);
31827bd4146SNathan Whitehorn }
31927bd4146SNathan Whitehorn
32027bd4146SNathan Whitehorn
32127bd4146SNathan Whitehorn /*
32227bd4146SNathan Whitehorn * Process non-PLT relocations
32327bd4146SNathan Whitehorn */
32427bd4146SNathan Whitehorn int
reloc_non_plt(Obj_Entry * obj,Obj_Entry * obj_rtld,int flags,RtldLockState * lockstate)325082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
326082f959aSKonstantin Belousov RtldLockState *lockstate)
32727bd4146SNathan Whitehorn {
32827bd4146SNathan Whitehorn const Elf_Rela *relalim;
32927bd4146SNathan Whitehorn const Elf_Rela *rela;
330f846c80aSKonstantin Belousov const Elf_Phdr *phdr;
33127bd4146SNathan Whitehorn SymCache *cache;
332f6265192SKonstantin Belousov int bytes = obj->dynsymcount * sizeof(SymCache);
33327bd4146SNathan Whitehorn int r = -1;
33427bd4146SNathan Whitehorn
33527bd4146SNathan Whitehorn /*
33627bd4146SNathan Whitehorn * The dynamic loader may be called from a thread, we have
33727bd4146SNathan Whitehorn * limited amounts of stack available so we cannot use alloca().
33827bd4146SNathan Whitehorn */
33927bd4146SNathan Whitehorn if (obj != obj_rtld) {
34027bd4146SNathan Whitehorn cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
34127bd4146SNathan Whitehorn -1, 0);
34227bd4146SNathan Whitehorn if (cache == MAP_FAILED)
34327bd4146SNathan Whitehorn cache = NULL;
34427bd4146SNathan Whitehorn } else
34527bd4146SNathan Whitehorn cache = NULL;
34627bd4146SNathan Whitehorn
34727bd4146SNathan Whitehorn /*
34827bd4146SNathan Whitehorn * From the SVR4 PPC ABI:
34927bd4146SNathan Whitehorn * "The PowerPC family uses only the Elf32_Rela relocation
35027bd4146SNathan Whitehorn * entries with explicit addends."
35127bd4146SNathan Whitehorn */
352903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
35327bd4146SNathan Whitehorn for (rela = obj->rela; rela < relalim; rela++) {
354082f959aSKonstantin Belousov if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
355082f959aSKonstantin Belousov lockstate) < 0)
35627bd4146SNathan Whitehorn goto done;
35727bd4146SNathan Whitehorn }
35827bd4146SNathan Whitehorn r = 0;
35927bd4146SNathan Whitehorn done:
3604b51c699SNathan Whitehorn if (cache)
36127bd4146SNathan Whitehorn munmap(cache, bytes);
3624b51c699SNathan Whitehorn
363f846c80aSKonstantin Belousov /*
364f846c80aSKonstantin Belousov * Synchronize icache for executable segments in case we made
365f846c80aSKonstantin Belousov * any changes.
366f846c80aSKonstantin Belousov */
367f846c80aSKonstantin Belousov for (phdr = obj->phdr;
368f846c80aSKonstantin Belousov (const char *)phdr < (const char *)obj->phdr + obj->phsize;
369f846c80aSKonstantin Belousov phdr++) {
370f846c80aSKonstantin Belousov if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
371f846c80aSKonstantin Belousov __syncicache(obj->relocbase + phdr->p_vaddr,
372f846c80aSKonstantin Belousov phdr->p_memsz);
373f846c80aSKonstantin Belousov }
374f846c80aSKonstantin Belousov }
3754b51c699SNathan Whitehorn
37627bd4146SNathan Whitehorn return (r);
37727bd4146SNathan Whitehorn }
37827bd4146SNathan Whitehorn
37927bd4146SNathan Whitehorn
38027bd4146SNathan Whitehorn /*
38127bd4146SNathan Whitehorn * Initialise a PLT slot to the resolving trampoline
38227bd4146SNathan Whitehorn */
38327bd4146SNathan Whitehorn static int
reloc_plt_object(Obj_Entry * obj,const Elf_Rela * rela)38427bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
38527bd4146SNathan Whitehorn {
38627bd4146SNathan Whitehorn Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
38727bd4146SNathan Whitehorn long reloff;
38827bd4146SNathan Whitehorn
38927bd4146SNathan Whitehorn reloff = rela - obj->pltrela;
39027bd4146SNathan Whitehorn
391a4c5dfc0SNathan Whitehorn dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where,
392a4c5dfc0SNathan Whitehorn reloff, obj->glink);
393a4c5dfc0SNathan Whitehorn
39429ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
395a4c5dfc0SNathan Whitehorn /* Glink code is 3 instructions after the first 32k, 2 before */
396a4c5dfc0SNathan Whitehorn *where = (Elf_Addr)obj->glink + 32 +
397a4c5dfc0SNathan Whitehorn 8*((reloff < 0x8000) ? reloff : 0x8000) +
398a4c5dfc0SNathan Whitehorn 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000));
39929ba9b61SNathan Whitehorn #else
40041b4ec8aSBrandon Bergren /* 64-Bit ELF V2 ABI Specification, sec. 4.2.5.3. */
40129ba9b61SNathan Whitehorn *where = (Elf_Addr)obj->glink + 4*reloff + 32;
40229ba9b61SNathan Whitehorn #endif
40327bd4146SNathan Whitehorn
40427bd4146SNathan Whitehorn return (0);
40527bd4146SNathan Whitehorn }
40627bd4146SNathan Whitehorn
40727bd4146SNathan Whitehorn /*
40827bd4146SNathan Whitehorn * Process the PLT relocations.
40927bd4146SNathan Whitehorn */
41027bd4146SNathan Whitehorn int
reloc_plt(Obj_Entry * obj,int flags __unused,RtldLockState * lockstate __unused)4114849c3a5SMichal Meloun reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
41227bd4146SNathan Whitehorn {
41327bd4146SNathan Whitehorn const Elf_Rela *relalim;
41427bd4146SNathan Whitehorn const Elf_Rela *rela;
41527bd4146SNathan Whitehorn
41627bd4146SNathan Whitehorn if (obj->pltrelasize != 0) {
417903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela +
41827bd4146SNathan Whitehorn obj->pltrelasize);
41927bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) {
42041b4ec8aSBrandon Bergren
42141b4ec8aSBrandon Bergren #if defined(_CALL_ELF) && _CALL_ELF == 2
42241b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
42341b4ec8aSBrandon Bergren dbg("ABI violation - found IRELATIVE in the PLT.");
42441b4ec8aSBrandon Bergren obj->irelative = true;
42541b4ec8aSBrandon Bergren continue;
42641b4ec8aSBrandon Bergren }
42741b4ec8aSBrandon Bergren #endif
42841b4ec8aSBrandon Bergren /*
42941b4ec8aSBrandon Bergren * PowerPC(64) .rela.plt is composed of an array of
43041b4ec8aSBrandon Bergren * R_PPC_JMP_SLOT relocations. Unlike other platforms,
43141b4ec8aSBrandon Bergren * this is the ONLY relocation type that is valid here.
43241b4ec8aSBrandon Bergren */
43327bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
43427bd4146SNathan Whitehorn
43527bd4146SNathan Whitehorn if (reloc_plt_object(obj, rela) < 0) {
43627bd4146SNathan Whitehorn return (-1);
43727bd4146SNathan Whitehorn }
43827bd4146SNathan Whitehorn }
43927bd4146SNathan Whitehorn }
44027bd4146SNathan Whitehorn
44127bd4146SNathan Whitehorn return (0);
44227bd4146SNathan Whitehorn }
44327bd4146SNathan Whitehorn
44427bd4146SNathan Whitehorn /*
44527bd4146SNathan Whitehorn * LD_BIND_NOW was set - force relocation for all jump slots
44627bd4146SNathan Whitehorn */
44727bd4146SNathan Whitehorn int
reloc_jmpslots(Obj_Entry * obj,int flags,RtldLockState * lockstate)448082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
44927bd4146SNathan Whitehorn {
45027bd4146SNathan Whitehorn const Obj_Entry *defobj;
45127bd4146SNathan Whitehorn const Elf_Rela *relalim;
45227bd4146SNathan Whitehorn const Elf_Rela *rela;
45327bd4146SNathan Whitehorn const Elf_Sym *def;
45427bd4146SNathan Whitehorn Elf_Addr *where;
45527bd4146SNathan Whitehorn Elf_Addr target;
45627bd4146SNathan Whitehorn
457903e0ffdSAlex Richardson relalim = (const Elf_Rela *)((const char *)obj->pltrela +
458903e0ffdSAlex Richardson obj->pltrelasize);
45927bd4146SNathan Whitehorn for (rela = obj->pltrela; rela < relalim; rela++) {
46041b4ec8aSBrandon Bergren /* This isn't actually a jump slot, ignore it. */
46141b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE)
46241b4ec8aSBrandon Bergren continue;
46327bd4146SNathan Whitehorn assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
46427bd4146SNathan Whitehorn where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
46527bd4146SNathan Whitehorn def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
466082f959aSKonstantin Belousov SYMLOOK_IN_PLT | flags, NULL, lockstate);
46727bd4146SNathan Whitehorn if (def == NULL) {
46827bd4146SNathan Whitehorn dbg("reloc_jmpslots: sym not found");
46927bd4146SNathan Whitehorn return (-1);
47027bd4146SNathan Whitehorn }
47127bd4146SNathan Whitehorn
47227bd4146SNathan Whitehorn target = (Elf_Addr)(defobj->relocbase + def->st_value);
47327bd4146SNathan Whitehorn
474d48dde6fSNathan Whitehorn if (def == &sym_zero) {
475d48dde6fSNathan Whitehorn /* Zero undefined weak symbols */
47629ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
477d48dde6fSNathan Whitehorn bzero(where, sizeof(struct funcdesc));
47829ba9b61SNathan Whitehorn #else
47929ba9b61SNathan Whitehorn *where = 0;
48029ba9b61SNathan Whitehorn #endif
481d48dde6fSNathan Whitehorn } else {
48241b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
48341b4ec8aSBrandon Bergren /* LD_BIND_NOW, ifunc in shared lib.*/
48441b4ec8aSBrandon Bergren obj->gnu_ifunc = true;
48541b4ec8aSBrandon Bergren continue;
48641b4ec8aSBrandon Bergren }
48727bd4146SNathan Whitehorn reloc_jmpslot(where, target, defobj, obj,
48827bd4146SNathan Whitehorn (const Elf_Rel *) rela);
48927bd4146SNathan Whitehorn }
490d48dde6fSNathan Whitehorn }
49127bd4146SNathan Whitehorn
49227bd4146SNathan Whitehorn obj->jmpslots_done = true;
49327bd4146SNathan Whitehorn
49427bd4146SNathan Whitehorn return (0);
49527bd4146SNathan Whitehorn }
49627bd4146SNathan Whitehorn
49727bd4146SNathan Whitehorn
49827bd4146SNathan Whitehorn /*
49927bd4146SNathan Whitehorn * Update the value of a PLT jump slot.
50027bd4146SNathan Whitehorn */
50127bd4146SNathan Whitehorn Elf_Addr
reloc_jmpslot(Elf_Addr * wherep,Elf_Addr target,const Obj_Entry * defobj __unused,const Obj_Entry * obj __unused,const Elf_Rel * rel __unused)502b6abe132SJustin Hibbits reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj __unused,
503903e0ffdSAlex Richardson const Obj_Entry *obj __unused, const Elf_Rel *rel __unused)
50427bd4146SNathan Whitehorn {
50527bd4146SNathan Whitehorn
50627bd4146SNathan Whitehorn /*
50727bd4146SNathan Whitehorn * At the PLT entry pointed at by `wherep', construct
50827bd4146SNathan Whitehorn * a direct transfer to the now fully resolved function
50927bd4146SNathan Whitehorn * address.
51027bd4146SNathan Whitehorn */
51127bd4146SNathan Whitehorn
51229ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
51329ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
51429ba9b61SNathan Whitehorn (void *)wherep, (void *)target, *(Elf_Addr *)target,
51529ba9b61SNathan Whitehorn (Elf_Addr)defobj->relocbase);
51629ba9b61SNathan Whitehorn
517e35ddbe4SKonstantin Belousov if (ld_bind_not)
518e35ddbe4SKonstantin Belousov goto out;
519e35ddbe4SKonstantin Belousov
520a4c5dfc0SNathan Whitehorn /*
521a4c5dfc0SNathan Whitehorn * For the trampoline, the second two elements of the function
522a4c5dfc0SNathan Whitehorn * descriptor are unused, so we are fine replacing those at any time
523a4c5dfc0SNathan Whitehorn * with the real ones with no thread safety implications. However, we
524a4c5dfc0SNathan Whitehorn * need to make sure the main entry point pointer ([0]) is seen to be
525a4c5dfc0SNathan Whitehorn * modified *after* the second two elements. This can't be done in
526a4c5dfc0SNathan Whitehorn * general, since there are no barriers in the reading code, but put in
527a4c5dfc0SNathan Whitehorn * some isyncs to at least make it a little better.
528a4c5dfc0SNathan Whitehorn */
52927bd4146SNathan Whitehorn memcpy(wherep, (void *)target, sizeof(struct funcdesc));
530a4c5dfc0SNathan Whitehorn wherep[2] = ((Elf_Addr *)target)[2];
531a4c5dfc0SNathan Whitehorn wherep[1] = ((Elf_Addr *)target)[1];
532a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory");
533a4c5dfc0SNathan Whitehorn wherep[0] = ((Elf_Addr *)target)[0];
534a4c5dfc0SNathan Whitehorn __asm __volatile ("isync" : : : "memory");
535a4c5dfc0SNathan Whitehorn
53627bd4146SNathan Whitehorn if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
53727bd4146SNathan Whitehorn /*
538a4c5dfc0SNathan Whitehorn * It is possible (LD_BIND_NOW) that the function
53927bd4146SNathan Whitehorn * descriptor we are copying has not yet been relocated.
540a4c5dfc0SNathan Whitehorn * If this happens, fix it. Don't worry about threading in
541a4c5dfc0SNathan Whitehorn * this case since LD_BIND_NOW makes it irrelevant.
54227bd4146SNathan Whitehorn */
54327bd4146SNathan Whitehorn
54427bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->addr +=
54527bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase;
54627bd4146SNathan Whitehorn ((struct funcdesc *)(wherep))->toc +=
54727bd4146SNathan Whitehorn (Elf_Addr)defobj->relocbase;
54827bd4146SNathan Whitehorn }
54929ba9b61SNathan Whitehorn #else
55029ba9b61SNathan Whitehorn dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
55129ba9b61SNathan Whitehorn (void *)target);
55227bd4146SNathan Whitehorn
55341b4ec8aSBrandon Bergren assert(target >= (Elf_Addr)defobj->relocbase);
55441b4ec8aSBrandon Bergren
55541b4ec8aSBrandon Bergren if (ld_bind_not)
55641b4ec8aSBrandon Bergren goto out;
55741b4ec8aSBrandon Bergren
55841b4ec8aSBrandon Bergren if (*wherep != target)
55929ba9b61SNathan Whitehorn *wherep = target;
56041b4ec8aSBrandon Bergren
56129ba9b61SNathan Whitehorn #endif
56241b4ec8aSBrandon Bergren out:
56329ba9b61SNathan Whitehorn
56427bd4146SNathan Whitehorn return (target);
56527bd4146SNathan Whitehorn }
56627bd4146SNathan Whitehorn
5676be4b697SKonstantin Belousov int
reloc_iresolve(Obj_Entry * obj,struct Struct_RtldLockState * lockstate)56841b4ec8aSBrandon Bergren reloc_iresolve(Obj_Entry *obj,
56941b4ec8aSBrandon Bergren struct Struct_RtldLockState *lockstate)
5706be4b697SKonstantin Belousov {
57141b4ec8aSBrandon Bergren /*
57241b4ec8aSBrandon Bergren * Since PLT slots on PowerPC64 are always R_PPC_JMP_SLOT,
57341b4ec8aSBrandon Bergren * R_PPC_IRELATIVE is in RELA.
57441b4ec8aSBrandon Bergren */
57541b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1
57641b4ec8aSBrandon Bergren (void)(obj);
57741b4ec8aSBrandon Bergren (void)(lockstate);
5786be4b697SKonstantin Belousov /* XXX not implemented */
5796be4b697SKonstantin Belousov return (0);
58041b4ec8aSBrandon Bergren #else
58141b4ec8aSBrandon Bergren const Elf_Rela *relalim;
58241b4ec8aSBrandon Bergren const Elf_Rela *rela;
58341b4ec8aSBrandon Bergren Elf_Addr *where, target, *ptr;
58441b4ec8aSBrandon Bergren
58541b4ec8aSBrandon Bergren if (!obj->irelative)
58641b4ec8aSBrandon Bergren return (0);
58741b4ec8aSBrandon Bergren
58841b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
58941b4ec8aSBrandon Bergren for (rela = obj->rela; rela < relalim; rela++) {
59041b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
59141b4ec8aSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
59241b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
59341b4ec8aSBrandon Bergren
59441b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate);
59541b4ec8aSBrandon Bergren target = call_ifunc_resolver(ptr);
59641b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate);
59741b4ec8aSBrandon Bergren
59841b4ec8aSBrandon Bergren *where = target;
59941b4ec8aSBrandon Bergren }
60041b4ec8aSBrandon Bergren }
60141b4ec8aSBrandon Bergren /*
60241b4ec8aSBrandon Bergren * XXX Remove me when lld is fixed!
60341b4ec8aSBrandon Bergren * LLD currently makes illegal relocations in the PLT.
60441b4ec8aSBrandon Bergren */
60541b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
60641b4ec8aSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) {
60741b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
60841b4ec8aSBrandon Bergren ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
60941b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
61041b4ec8aSBrandon Bergren
61141b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate);
61241b4ec8aSBrandon Bergren target = call_ifunc_resolver(ptr);
61341b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate);
61441b4ec8aSBrandon Bergren
61541b4ec8aSBrandon Bergren *where = target;
61641b4ec8aSBrandon Bergren }
61741b4ec8aSBrandon Bergren }
61841b4ec8aSBrandon Bergren
61941b4ec8aSBrandon Bergren obj->irelative = false;
62041b4ec8aSBrandon Bergren return (0);
62141b4ec8aSBrandon Bergren #endif
6226be4b697SKonstantin Belousov }
6236be4b697SKonstantin Belousov
6246be4b697SKonstantin Belousov int
reloc_gnu_ifunc(Obj_Entry * obj __unused,int flags __unused,struct Struct_RtldLockState * lockstate __unused)625903e0ffdSAlex Richardson reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
626903e0ffdSAlex Richardson struct Struct_RtldLockState *lockstate __unused)
6276be4b697SKonstantin Belousov {
62841b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1
62941b4ec8aSBrandon Bergren _rtld_error("reloc_gnu_ifunc(): Not implemented!");
6306be4b697SKonstantin Belousov /* XXX not implemented */
63141b4ec8aSBrandon Bergren return (-1);
63241b4ec8aSBrandon Bergren #else
63341b4ec8aSBrandon Bergren
63441b4ec8aSBrandon Bergren const Elf_Rela *relalim;
63541b4ec8aSBrandon Bergren const Elf_Rela *rela;
63641b4ec8aSBrandon Bergren Elf_Addr *where, target;
63741b4ec8aSBrandon Bergren const Elf_Sym *def;
63841b4ec8aSBrandon Bergren const Obj_Entry *defobj;
63941b4ec8aSBrandon Bergren
64041b4ec8aSBrandon Bergren if (!obj->gnu_ifunc)
6416be4b697SKonstantin Belousov return (0);
64241b4ec8aSBrandon Bergren relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
64341b4ec8aSBrandon Bergren for (rela = obj->pltrela; rela < relalim; rela++) {
64441b4ec8aSBrandon Bergren if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) {
64541b4ec8aSBrandon Bergren where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
64641b4ec8aSBrandon Bergren def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
64741b4ec8aSBrandon Bergren SYMLOOK_IN_PLT | flags, NULL, lockstate);
64841b4ec8aSBrandon Bergren if (def == NULL)
64941b4ec8aSBrandon Bergren return (-1);
65041b4ec8aSBrandon Bergren if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
65141b4ec8aSBrandon Bergren continue;
65241b4ec8aSBrandon Bergren lock_release(rtld_bind_lock, lockstate);
65341b4ec8aSBrandon Bergren target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
65441b4ec8aSBrandon Bergren wlock_acquire(rtld_bind_lock, lockstate);
65541b4ec8aSBrandon Bergren reloc_jmpslot(where, target, defobj, obj,
65641b4ec8aSBrandon Bergren (const Elf_Rel *)rela);
65741b4ec8aSBrandon Bergren }
65841b4ec8aSBrandon Bergren }
65941b4ec8aSBrandon Bergren obj->gnu_ifunc = false;
66041b4ec8aSBrandon Bergren return (0);
66141b4ec8aSBrandon Bergren #endif
6626be4b697SKonstantin Belousov }
6636be4b697SKonstantin Belousov
664c5ca0d11SKonstantin Belousov int
reloc_iresolve_nonplt(Obj_Entry * obj __unused,struct Struct_RtldLockState * lockstate __unused)665c5ca0d11SKonstantin Belousov reloc_iresolve_nonplt(Obj_Entry *obj __unused,
666c5ca0d11SKonstantin Belousov struct Struct_RtldLockState *lockstate __unused)
667c5ca0d11SKonstantin Belousov {
668c5ca0d11SKonstantin Belousov return (0);
669c5ca0d11SKonstantin Belousov }
670c5ca0d11SKonstantin Belousov
67127bd4146SNathan Whitehorn void
init_pltgot(Obj_Entry * obj)67227bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj)
67327bd4146SNathan Whitehorn {
67429ba9b61SNathan Whitehorn Elf_Addr *pltcall;
67529ba9b61SNathan Whitehorn
67629ba9b61SNathan Whitehorn pltcall = obj->pltgot;
67729ba9b61SNathan Whitehorn
67829ba9b61SNathan Whitehorn if (pltcall == NULL) {
67929ba9b61SNathan Whitehorn return;
68029ba9b61SNathan Whitehorn }
68129ba9b61SNathan Whitehorn
682a4c5dfc0SNathan Whitehorn #if defined(_CALL_ELF) && _CALL_ELF == 2
68329ba9b61SNathan Whitehorn pltcall[0] = (Elf_Addr)&_rtld_bind_start;
68429ba9b61SNathan Whitehorn pltcall[1] = (Elf_Addr)obj;
685a4c5dfc0SNathan Whitehorn #else
686a4c5dfc0SNathan Whitehorn memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc));
687a4c5dfc0SNathan Whitehorn pltcall[2] = (Elf_Addr)obj;
68829ba9b61SNathan Whitehorn #endif
68927bd4146SNathan Whitehorn }
69027bd4146SNathan Whitehorn
69141b4ec8aSBrandon Bergren /*
69241b4ec8aSBrandon Bergren * Actual values are 32 bit.
69341b4ec8aSBrandon Bergren */
69441b4ec8aSBrandon Bergren u_long cpu_features;
69541b4ec8aSBrandon Bergren u_long cpu_features2;
69641b4ec8aSBrandon Bergren
69741b4ec8aSBrandon Bergren void
powerpc64_abi_variant_hook(Elf_Auxinfo ** aux_info)69841b4ec8aSBrandon Bergren powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info)
69941b4ec8aSBrandon Bergren {
70041b4ec8aSBrandon Bergren /*
70141b4ec8aSBrandon Bergren * Since aux_info[] is easier to work with than aux, go ahead and
70241b4ec8aSBrandon Bergren * initialize cpu_features / cpu_features2.
70341b4ec8aSBrandon Bergren */
70441b4ec8aSBrandon Bergren cpu_features = -1UL;
70541b4ec8aSBrandon Bergren cpu_features2 = -1UL;
70641b4ec8aSBrandon Bergren if (aux_info[AT_HWCAP] != NULL)
70741b4ec8aSBrandon Bergren cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val;
70841b4ec8aSBrandon Bergren if (aux_info[AT_HWCAP2] != NULL)
70941b4ec8aSBrandon Bergren cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val;
71041b4ec8aSBrandon Bergren }
71141b4ec8aSBrandon Bergren
71227bd4146SNathan Whitehorn void
ifunc_init(Elf_Auxinfo * aux_info[__min_size (AT_COUNT)]__unused)713*33658afdSJessica Clarke ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)] __unused)
7144352999eSKonstantin Belousov {
71541fc6f68SMarius Strobl
71641fc6f68SMarius Strobl }
71741fc6f68SMarius Strobl
71841fc6f68SMarius Strobl void
allocate_initial_tls(Obj_Entry * list)71927bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list)
72027bd4146SNathan Whitehorn {
72127bd4146SNathan Whitehorn
72227bd4146SNathan Whitehorn /*
72327bd4146SNathan Whitehorn * Fix the size of the static TLS block by using the maximum
72427bd4146SNathan Whitehorn * offset allocated so far and adding a bit for dynamic modules to
72527bd4146SNathan Whitehorn * use.
72627bd4146SNathan Whitehorn */
72727bd4146SNathan Whitehorn
72895335dd3SStephen J. Kiernan tls_static_space = tls_last_offset + tls_last_size +
72995335dd3SStephen J. Kiernan ld_static_tls_extra;
73027bd4146SNathan Whitehorn
7318bcdb144SJohn Baldwin _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
73227bd4146SNathan Whitehorn }
73327bd4146SNathan Whitehorn
73427bd4146SNathan Whitehorn void*
__tls_get_addr(tls_index * ti)73527bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti)
73627bd4146SNathan Whitehorn {
7378bcdb144SJohn Baldwin uintptr_t **dtvp;
73827bd4146SNathan Whitehorn char *p;
73927bd4146SNathan Whitehorn
7408bcdb144SJohn Baldwin dtvp = &_tcb_get()->tcb_dtv;
7418bcdb144SJohn Baldwin p = tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset);
74227bd4146SNathan Whitehorn
74327bd4146SNathan Whitehorn return (p + TLS_DTV_OFFSET);
74427bd4146SNathan Whitehorn }
745