xref: /freebsd/libexec/rtld-elf/powerpc64/reloc.c (revision 41b4ec8ab025578020483864c1cf23ffed8fd55d)
127bd4146SNathan Whitehorn /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
227bd4146SNathan Whitehorn 
327bd4146SNathan Whitehorn /*-
4e6209940SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
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  * $FreeBSD$
3227bd4146SNathan Whitehorn  */
3327bd4146SNathan Whitehorn 
3427bd4146SNathan Whitehorn #include <sys/param.h>
3527bd4146SNathan Whitehorn #include <sys/mman.h>
36*41b4ec8aSBrandon Bergren #include <sys/sysctl.h>
3727bd4146SNathan Whitehorn 
3827bd4146SNathan Whitehorn #include <errno.h>
3927bd4146SNathan Whitehorn #include <stdio.h>
4027bd4146SNathan Whitehorn #include <stdlib.h>
4127bd4146SNathan Whitehorn #include <string.h>
4227bd4146SNathan Whitehorn #include <unistd.h>
43a29cc9a3SAndriy Gapon #include <machine/cpu.h>
4427bd4146SNathan Whitehorn #include <machine/md_var.h>
4527bd4146SNathan Whitehorn 
4627bd4146SNathan Whitehorn #include "debug.h"
4727bd4146SNathan Whitehorn #include "rtld.h"
4827bd4146SNathan Whitehorn 
4929ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
5027bd4146SNathan Whitehorn struct funcdesc {
5127bd4146SNathan Whitehorn 	Elf_Addr addr;
5227bd4146SNathan Whitehorn 	Elf_Addr toc;
5327bd4146SNathan Whitehorn 	Elf_Addr env;
5427bd4146SNathan Whitehorn };
5529ba9b61SNathan Whitehorn #endif
5627bd4146SNathan Whitehorn 
5727bd4146SNathan Whitehorn /*
5827bd4146SNathan Whitehorn  * Process the R_PPC_COPY relocations
5927bd4146SNathan Whitehorn  */
6027bd4146SNathan Whitehorn int
6127bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj)
6227bd4146SNathan Whitehorn {
6327bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
6427bd4146SNathan Whitehorn 	const Elf_Rela *rela;
6527bd4146SNathan Whitehorn 
6627bd4146SNathan Whitehorn 	/*
6727bd4146SNathan Whitehorn 	 * COPY relocs are invalid outside of the main program
6827bd4146SNathan Whitehorn 	 */
6927bd4146SNathan Whitehorn 	assert(dstobj->mainprog);
7027bd4146SNathan Whitehorn 
71903e0ffdSAlex Richardson 	relalim = (const Elf_Rela *)((const char *) dstobj->rela +
7227bd4146SNathan Whitehorn 	    dstobj->relasize);
7327bd4146SNathan Whitehorn 	for (rela = dstobj->rela;  rela < relalim;  rela++) {
7427bd4146SNathan Whitehorn 		void *dstaddr;
7527bd4146SNathan Whitehorn 		const Elf_Sym *dstsym;
7627bd4146SNathan Whitehorn 		const char *name;
7727bd4146SNathan Whitehorn 		size_t size;
7827bd4146SNathan Whitehorn 		const void *srcaddr;
7927bd4146SNathan Whitehorn 		const Elf_Sym *srcsym = NULL;
808569deafSKonstantin Belousov 		const Obj_Entry *srcobj, *defobj;
818569deafSKonstantin Belousov 		SymLook req;
828569deafSKonstantin Belousov 		int res;
8327bd4146SNathan Whitehorn 
8427bd4146SNathan Whitehorn 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
8527bd4146SNathan Whitehorn 			continue;
8627bd4146SNathan Whitehorn 		}
8727bd4146SNathan Whitehorn 
8827bd4146SNathan Whitehorn 		dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
8927bd4146SNathan Whitehorn 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
9027bd4146SNathan Whitehorn 		name = dstobj->strtab + dstsym->st_name;
9127bd4146SNathan Whitehorn 		size = dstsym->st_size;
928569deafSKonstantin Belousov 		symlook_init(&req, name);
938569deafSKonstantin Belousov 		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
94082f959aSKonstantin Belousov 		req.flags = SYMLOOK_EARLY;
9527bd4146SNathan Whitehorn 
969fee0541SKonstantin Belousov 		for (srcobj = globallist_next(dstobj); srcobj != NULL;
979fee0541SKonstantin Belousov 		     srcobj = globallist_next(srcobj)) {
988569deafSKonstantin Belousov 			res = symlook_obj(&req, srcobj);
998569deafSKonstantin Belousov 			if (res == 0) {
1008569deafSKonstantin Belousov 				srcsym = req.sym_out;
1018569deafSKonstantin Belousov 				defobj = req.defobj_out;
10227bd4146SNathan Whitehorn 				break;
10327bd4146SNathan Whitehorn 			}
10427bd4146SNathan Whitehorn 		}
10527bd4146SNathan Whitehorn 
10627bd4146SNathan Whitehorn 		if (srcobj == NULL) {
10727bd4146SNathan Whitehorn 			_rtld_error("Undefined symbol \"%s\" "
10827bd4146SNathan Whitehorn 				    " referenced from COPY"
10927bd4146SNathan Whitehorn 				    " relocation in %s", name, dstobj->path);
11027bd4146SNathan Whitehorn 			return (-1);
11127bd4146SNathan Whitehorn 		}
11227bd4146SNathan Whitehorn 
1138569deafSKonstantin Belousov 		srcaddr = (const void *)(defobj->relocbase+srcsym->st_value);
11427bd4146SNathan Whitehorn 		memcpy(dstaddr, srcaddr, size);
11527bd4146SNathan Whitehorn 		dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
11627bd4146SNathan Whitehorn 	}
11727bd4146SNathan Whitehorn 
11827bd4146SNathan Whitehorn 	return (0);
11927bd4146SNathan Whitehorn }
12027bd4146SNathan Whitehorn 
12127bd4146SNathan Whitehorn 
12227bd4146SNathan Whitehorn /*
12327bd4146SNathan Whitehorn  * Perform early relocation of the run-time linker image
12427bd4146SNathan Whitehorn  */
12527bd4146SNathan Whitehorn void
12627bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
12727bd4146SNathan Whitehorn {
128a5d5e8ddSPedro F. Giffuni 	const Elf_Rela *rela = NULL, *relalim;
12927bd4146SNathan Whitehorn 	Elf_Addr relasz = 0;
13027bd4146SNathan Whitehorn 	Elf_Addr *where;
13127bd4146SNathan Whitehorn 
13227bd4146SNathan Whitehorn 	/*
13327bd4146SNathan Whitehorn 	 * Extract the rela/relasz values from the dynamic section
13427bd4146SNathan Whitehorn 	 */
13527bd4146SNathan Whitehorn 	for (; dynp->d_tag != DT_NULL; dynp++) {
13627bd4146SNathan Whitehorn 		switch (dynp->d_tag) {
13727bd4146SNathan Whitehorn 		case DT_RELA:
13827bd4146SNathan Whitehorn 			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
13927bd4146SNathan Whitehorn 			break;
14027bd4146SNathan Whitehorn 		case DT_RELASZ:
14127bd4146SNathan Whitehorn 			relasz = dynp->d_un.d_val;
14227bd4146SNathan Whitehorn 			break;
14327bd4146SNathan Whitehorn 		}
14427bd4146SNathan Whitehorn 	}
14527bd4146SNathan Whitehorn 
14627bd4146SNathan Whitehorn 	/*
14727bd4146SNathan Whitehorn 	 * Relocate these values
14827bd4146SNathan Whitehorn 	 */
149903e0ffdSAlex Richardson 	relalim = (const Elf_Rela *)((const char *)rela + relasz);
15027bd4146SNathan Whitehorn 	for (; rela < relalim; rela++) {
15127bd4146SNathan Whitehorn 		where = (Elf_Addr *)(relocbase + rela->r_offset);
15227bd4146SNathan Whitehorn 		*where = (Elf_Addr)(relocbase + rela->r_addend);
15327bd4146SNathan Whitehorn 	}
15427bd4146SNathan Whitehorn }
15527bd4146SNathan Whitehorn 
15627bd4146SNathan Whitehorn 
15727bd4146SNathan Whitehorn /*
15827bd4146SNathan Whitehorn  * Relocate a non-PLT object with addend.
15927bd4146SNathan Whitehorn  */
16027bd4146SNathan Whitehorn static int
161903e0ffdSAlex Richardson reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj,
162903e0ffdSAlex Richardson     const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate)
16327bd4146SNathan Whitehorn {
164*41b4ec8aSBrandon Bergren 	const Elf_Sym	*def = NULL;
16527bd4146SNathan Whitehorn 	const Obj_Entry	*defobj;
166*41b4ec8aSBrandon Bergren 	Elf_Addr	*where, symval = 0;
16727bd4146SNathan Whitehorn 
168*41b4ec8aSBrandon Bergren 	/*
169*41b4ec8aSBrandon Bergren 	 * First, resolve symbol for relocations which
170*41b4ec8aSBrandon Bergren 	 * reference symbols.
171*41b4ec8aSBrandon Bergren 	 */
17227bd4146SNathan Whitehorn 	switch (ELF_R_TYPE(rela->r_info)) {
17327bd4146SNathan Whitehorn 
1749cc92083SNathan Whitehorn 	case R_PPC64_UADDR64:    /* doubleword64 S + A */
1759cc92083SNathan Whitehorn 	case R_PPC64_ADDR64:
17627bd4146SNathan Whitehorn 	case R_PPC_GLOB_DAT:
177*41b4ec8aSBrandon Bergren 	case R_PPC64_DTPMOD64:
178*41b4ec8aSBrandon Bergren 	case R_PPC64_TPREL64:
179*41b4ec8aSBrandon Bergren 	case R_PPC64_DTPREL64:
18027bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
181082f959aSKonstantin Belousov 		    flags, cache, lockstate);
18227bd4146SNathan Whitehorn 		if (def == NULL) {
18327bd4146SNathan Whitehorn 			return (-1);
18427bd4146SNathan Whitehorn 		}
18527bd4146SNathan Whitehorn 		/*
186*41b4ec8aSBrandon Bergren 		 * If symbol is IFUNC, only perform relocation
187*41b4ec8aSBrandon Bergren 		 * when caller allowed it by passing
188*41b4ec8aSBrandon Bergren 		 * SYMLOOK_IFUNC flag.  Skip the relocations
189*41b4ec8aSBrandon Bergren 		 * otherwise.
190*41b4ec8aSBrandon Bergren 		 *
191*41b4ec8aSBrandon Bergren 		 * Also error out in case IFUNC relocations
192*41b4ec8aSBrandon Bergren 		 * are specified for TLS, which cannot be
193*41b4ec8aSBrandon Bergren 		 * usefully interpreted.
19427bd4146SNathan Whitehorn 		 */
195*41b4ec8aSBrandon Bergren 		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
196*41b4ec8aSBrandon Bergren 			switch (ELF_R_TYPE(rela->r_info)) {
197*41b4ec8aSBrandon Bergren 			case R_PPC64_UADDR64:
198*41b4ec8aSBrandon Bergren 			case R_PPC64_ADDR64:
199*41b4ec8aSBrandon Bergren 			case R_PPC_GLOB_DAT:
200*41b4ec8aSBrandon Bergren 				if ((flags & SYMLOOK_IFUNC) == 0) {
201*41b4ec8aSBrandon Bergren 					dbg("Non-PLT reference to IFUNC found!");
202*41b4ec8aSBrandon Bergren 					obj->non_plt_gnu_ifunc = true;
203*41b4ec8aSBrandon Bergren 					return (0);
204*41b4ec8aSBrandon Bergren 				}
205*41b4ec8aSBrandon Bergren 				symval = (Elf_Addr)rtld_resolve_ifunc(
206*41b4ec8aSBrandon Bergren 					defobj, def);
207*41b4ec8aSBrandon Bergren 				break;
208*41b4ec8aSBrandon Bergren 			default:
209*41b4ec8aSBrandon Bergren 				_rtld_error("%s: IFUNC for TLS reloc",
21027bd4146SNathan Whitehorn 					 obj->path);
21127bd4146SNathan Whitehorn 				return (-1);
21227bd4146SNathan Whitehorn 			}
213*41b4ec8aSBrandon Bergren 		} else {
214*41b4ec8aSBrandon Bergren 			if ((flags & SYMLOOK_IFUNC) != 0)
215*41b4ec8aSBrandon Bergren 				return (0);
216*41b4ec8aSBrandon Bergren 			symval = (Elf_Addr)defobj->relocbase +
217*41b4ec8aSBrandon Bergren 				def->st_value;
218*41b4ec8aSBrandon Bergren 		}
21927bd4146SNathan Whitehorn 		break;
220*41b4ec8aSBrandon Bergren 	default:
221*41b4ec8aSBrandon Bergren 		if ((flags & SYMLOOK_IFUNC) != 0)
222*41b4ec8aSBrandon Bergren 			return (0);
223*41b4ec8aSBrandon Bergren 	}
22427bd4146SNathan Whitehorn 
225*41b4ec8aSBrandon Bergren 	where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
226*41b4ec8aSBrandon Bergren 
227*41b4ec8aSBrandon Bergren 	switch (ELF_R_TYPE(rela->r_info)) {
228*41b4ec8aSBrandon Bergren 	case R_PPC_NONE:
22927bd4146SNathan Whitehorn 		break;
230*41b4ec8aSBrandon Bergren 	case R_PPC64_UADDR64:
231*41b4ec8aSBrandon Bergren 	case R_PPC64_ADDR64:
232*41b4ec8aSBrandon Bergren 	case R_PPC_GLOB_DAT:
233*41b4ec8aSBrandon Bergren 		/* Don't issue write if unnecessary; avoid COW page fault */
234*41b4ec8aSBrandon Bergren 		if (*where != symval + rela->r_addend) {
235*41b4ec8aSBrandon Bergren 			*where = symval + rela->r_addend;
236*41b4ec8aSBrandon Bergren 		}
237*41b4ec8aSBrandon Bergren 		break;
23827bd4146SNathan Whitehorn 	case R_PPC64_DTPMOD64:
23927bd4146SNathan Whitehorn 		*where = (Elf_Addr) defobj->tlsindex;
24027bd4146SNathan Whitehorn 		break;
24127bd4146SNathan Whitehorn 	case R_PPC64_TPREL64:
24227bd4146SNathan Whitehorn 		/*
24327bd4146SNathan Whitehorn 		 * We lazily allocate offsets for static TLS as we
24427bd4146SNathan Whitehorn 		 * see the first relocation that references the
24527bd4146SNathan Whitehorn 		 * TLS block. This allows us to support (small
24627bd4146SNathan Whitehorn 		 * amounts of) static TLS in dynamically loaded
24727bd4146SNathan Whitehorn 		 * modules. If we run out of space, we generate an
24827bd4146SNathan Whitehorn 		 * error.
24927bd4146SNathan Whitehorn 		 */
25027bd4146SNathan Whitehorn 		if (!defobj->tls_done) {
251903e0ffdSAlex Richardson 			if (!allocate_tls_offset(
252903e0ffdSAlex Richardson 				    __DECONST(Obj_Entry *, defobj))) {
25327bd4146SNathan Whitehorn 				_rtld_error("%s: No space available for static "
25427bd4146SNathan Whitehorn 				    "Thread Local Storage", obj->path);
25527bd4146SNathan Whitehorn 				return (-1);
25627bd4146SNathan Whitehorn 			}
25727bd4146SNathan Whitehorn 		}
25827bd4146SNathan Whitehorn 
25927bd4146SNathan Whitehorn 		*(Elf_Addr **)where = *where * sizeof(Elf_Addr)
26027bd4146SNathan Whitehorn 		    + (Elf_Addr *)(def->st_value + rela->r_addend
26145a18a1fSJustin Hibbits 		    + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
26227bd4146SNathan Whitehorn 		break;
26327bd4146SNathan Whitehorn 	case R_PPC64_DTPREL64:
26427bd4146SNathan Whitehorn 		*where += (Elf_Addr)(def->st_value + rela->r_addend
26527bd4146SNathan Whitehorn 		    - TLS_DTV_OFFSET);
266*41b4ec8aSBrandon Bergren 		break;
267*41b4ec8aSBrandon Bergren 	case R_PPC_RELATIVE:  /* doubleword64 B + A */
268*41b4ec8aSBrandon Bergren 		symval = (Elf_Addr)(obj->relocbase + rela->r_addend);
26927bd4146SNathan Whitehorn 
270*41b4ec8aSBrandon Bergren 		/* As above, don't issue write unnecessarily */
271*41b4ec8aSBrandon Bergren 		if (*where != symval) {
272*41b4ec8aSBrandon Bergren 			*where = symval;
273*41b4ec8aSBrandon Bergren 		}
274*41b4ec8aSBrandon Bergren 		break;
275*41b4ec8aSBrandon Bergren 	case R_PPC_COPY:
276*41b4ec8aSBrandon Bergren 		/*
277*41b4ec8aSBrandon Bergren 		 * These are deferred until all other relocations
278*41b4ec8aSBrandon Bergren 		 * have been done.  All we do here is make sure
279*41b4ec8aSBrandon Bergren 		 * that the COPY relocation is not in a shared
280*41b4ec8aSBrandon Bergren 		 * library.  They are allowed only in executable
281*41b4ec8aSBrandon Bergren 		 * files.
282*41b4ec8aSBrandon Bergren 		 */
283*41b4ec8aSBrandon Bergren 		if (!obj->mainprog) {
284*41b4ec8aSBrandon Bergren 			_rtld_error("%s: Unexpected R_COPY "
285*41b4ec8aSBrandon Bergren 				    " relocation in shared library",
286*41b4ec8aSBrandon Bergren 				    obj->path);
287*41b4ec8aSBrandon Bergren 			return (-1);
288*41b4ec8aSBrandon Bergren 		}
289*41b4ec8aSBrandon Bergren 		break;
290*41b4ec8aSBrandon Bergren 	case R_PPC_IRELATIVE:
291*41b4ec8aSBrandon Bergren 		/*
292*41b4ec8aSBrandon Bergren 		 * These will be handled by reloc_iresolve().
293*41b4ec8aSBrandon Bergren 		 */
294*41b4ec8aSBrandon Bergren 		obj->irelative = true;
295*41b4ec8aSBrandon Bergren 		break;
296*41b4ec8aSBrandon Bergren 	case R_PPC_JMP_SLOT:
297*41b4ec8aSBrandon Bergren 		/*
298*41b4ec8aSBrandon Bergren 		 * These will be handled by the plt/jmpslot routines
299*41b4ec8aSBrandon Bergren 		 */
30027bd4146SNathan Whitehorn 		break;
30127bd4146SNathan Whitehorn 
30227bd4146SNathan Whitehorn 	default:
30327bd4146SNathan Whitehorn 		_rtld_error("%s: Unsupported relocation type %ld"
30427bd4146SNathan Whitehorn 			    " in non-PLT relocations\n", obj->path,
30527bd4146SNathan Whitehorn 			    ELF_R_TYPE(rela->r_info));
30627bd4146SNathan Whitehorn 		return (-1);
30727bd4146SNathan Whitehorn 	}
30827bd4146SNathan Whitehorn 	return (0);
30927bd4146SNathan Whitehorn }
31027bd4146SNathan Whitehorn 
31127bd4146SNathan Whitehorn 
31227bd4146SNathan Whitehorn /*
31327bd4146SNathan Whitehorn  * Process non-PLT relocations
31427bd4146SNathan Whitehorn  */
31527bd4146SNathan Whitehorn int
316082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
317082f959aSKonstantin Belousov     RtldLockState *lockstate)
31827bd4146SNathan Whitehorn {
31927bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
32027bd4146SNathan Whitehorn 	const Elf_Rela *rela;
321f846c80aSKonstantin Belousov 	const Elf_Phdr *phdr;
32227bd4146SNathan Whitehorn 	SymCache *cache;
323f6265192SKonstantin Belousov 	int bytes = obj->dynsymcount * sizeof(SymCache);
32427bd4146SNathan Whitehorn 	int r = -1;
32527bd4146SNathan Whitehorn 
32627bd4146SNathan Whitehorn 	/*
32727bd4146SNathan Whitehorn 	 * The dynamic loader may be called from a thread, we have
32827bd4146SNathan Whitehorn 	 * limited amounts of stack available so we cannot use alloca().
32927bd4146SNathan Whitehorn 	 */
33027bd4146SNathan Whitehorn 	if (obj != obj_rtld) {
33127bd4146SNathan Whitehorn 		cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
33227bd4146SNathan Whitehorn 		    -1, 0);
33327bd4146SNathan Whitehorn 		if (cache == MAP_FAILED)
33427bd4146SNathan Whitehorn 			cache = NULL;
33527bd4146SNathan Whitehorn 	} else
33627bd4146SNathan Whitehorn 		cache = NULL;
33727bd4146SNathan Whitehorn 
33827bd4146SNathan Whitehorn 	/*
33927bd4146SNathan Whitehorn 	 * From the SVR4 PPC ABI:
34027bd4146SNathan Whitehorn 	 * "The PowerPC family uses only the Elf32_Rela relocation
34127bd4146SNathan Whitehorn 	 *  entries with explicit addends."
34227bd4146SNathan Whitehorn 	 */
343903e0ffdSAlex Richardson 	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
34427bd4146SNathan Whitehorn 	for (rela = obj->rela; rela < relalim; rela++) {
345082f959aSKonstantin Belousov 		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
346082f959aSKonstantin Belousov 		    lockstate) < 0)
34727bd4146SNathan Whitehorn 			goto done;
34827bd4146SNathan Whitehorn 	}
34927bd4146SNathan Whitehorn 	r = 0;
35027bd4146SNathan Whitehorn done:
3514b51c699SNathan Whitehorn 	if (cache)
35227bd4146SNathan Whitehorn 		munmap(cache, bytes);
3534b51c699SNathan Whitehorn 
354f846c80aSKonstantin Belousov 	/*
355f846c80aSKonstantin Belousov 	 * Synchronize icache for executable segments in case we made
356f846c80aSKonstantin Belousov 	 * any changes.
357f846c80aSKonstantin Belousov 	 */
358f846c80aSKonstantin Belousov 	for (phdr = obj->phdr;
359f846c80aSKonstantin Belousov 	    (const char *)phdr < (const char *)obj->phdr + obj->phsize;
360f846c80aSKonstantin Belousov 	    phdr++) {
361f846c80aSKonstantin Belousov 		if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
362f846c80aSKonstantin Belousov 			__syncicache(obj->relocbase + phdr->p_vaddr,
363f846c80aSKonstantin Belousov 			    phdr->p_memsz);
364f846c80aSKonstantin Belousov 		}
365f846c80aSKonstantin Belousov 	}
3664b51c699SNathan Whitehorn 
36727bd4146SNathan Whitehorn 	return (r);
36827bd4146SNathan Whitehorn }
36927bd4146SNathan Whitehorn 
37027bd4146SNathan Whitehorn 
37127bd4146SNathan Whitehorn /*
37227bd4146SNathan Whitehorn  * Initialise a PLT slot to the resolving trampoline
37327bd4146SNathan Whitehorn  */
37427bd4146SNathan Whitehorn static int
37527bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
37627bd4146SNathan Whitehorn {
37727bd4146SNathan Whitehorn 	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
37827bd4146SNathan Whitehorn 	long reloff;
37927bd4146SNathan Whitehorn 
38027bd4146SNathan Whitehorn 	reloff = rela - obj->pltrela;
38127bd4146SNathan Whitehorn 
382a4c5dfc0SNathan Whitehorn 	dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where,
383a4c5dfc0SNathan Whitehorn 	    reloff, obj->glink);
384a4c5dfc0SNathan Whitehorn 
38529ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
386a4c5dfc0SNathan Whitehorn 	/* Glink code is 3 instructions after the first 32k, 2 before */
387a4c5dfc0SNathan Whitehorn 	*where = (Elf_Addr)obj->glink + 32 +
388a4c5dfc0SNathan Whitehorn 	    8*((reloff < 0x8000) ? reloff : 0x8000) +
389a4c5dfc0SNathan Whitehorn 	    12*((reloff < 0x8000) ? 0 : (reloff - 0x8000));
39029ba9b61SNathan Whitehorn #else
391*41b4ec8aSBrandon Bergren 	/* 64-Bit ELF V2 ABI Specification, sec. 4.2.5.3. */
39229ba9b61SNathan Whitehorn 	*where = (Elf_Addr)obj->glink + 4*reloff + 32;
39329ba9b61SNathan Whitehorn #endif
39427bd4146SNathan Whitehorn 
39527bd4146SNathan Whitehorn 	return (0);
39627bd4146SNathan Whitehorn }
39727bd4146SNathan Whitehorn 
39827bd4146SNathan Whitehorn /*
39927bd4146SNathan Whitehorn  * Process the PLT relocations.
40027bd4146SNathan Whitehorn  */
40127bd4146SNathan Whitehorn int
4024849c3a5SMichal Meloun reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
40327bd4146SNathan Whitehorn {
40427bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
40527bd4146SNathan Whitehorn 	const Elf_Rela *rela;
40627bd4146SNathan Whitehorn 
40727bd4146SNathan Whitehorn 	if (obj->pltrelasize != 0) {
408903e0ffdSAlex Richardson 		relalim = (const Elf_Rela *)((const char *)obj->pltrela +
40927bd4146SNathan Whitehorn 		    obj->pltrelasize);
41027bd4146SNathan Whitehorn 		for (rela = obj->pltrela;  rela < relalim;  rela++) {
411*41b4ec8aSBrandon Bergren 
412*41b4ec8aSBrandon Bergren #if defined(_CALL_ELF) && _CALL_ELF == 2
413*41b4ec8aSBrandon Bergren 			if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
414*41b4ec8aSBrandon Bergren 				dbg("ABI violation - found IRELATIVE in the PLT.");
415*41b4ec8aSBrandon Bergren 				obj->irelative = true;
416*41b4ec8aSBrandon Bergren 				continue;
417*41b4ec8aSBrandon Bergren 			}
418*41b4ec8aSBrandon Bergren #endif
419*41b4ec8aSBrandon Bergren 			/*
420*41b4ec8aSBrandon Bergren 			 * PowerPC(64) .rela.plt is composed of an array of
421*41b4ec8aSBrandon Bergren 			 * R_PPC_JMP_SLOT relocations. Unlike other platforms,
422*41b4ec8aSBrandon Bergren 			 * this is the ONLY relocation type that is valid here.
423*41b4ec8aSBrandon Bergren 			 */
42427bd4146SNathan Whitehorn 			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
42527bd4146SNathan Whitehorn 
42627bd4146SNathan Whitehorn 			if (reloc_plt_object(obj, rela) < 0) {
42727bd4146SNathan Whitehorn 				return (-1);
42827bd4146SNathan Whitehorn 			}
42927bd4146SNathan Whitehorn 		}
43027bd4146SNathan Whitehorn 	}
43127bd4146SNathan Whitehorn 
43227bd4146SNathan Whitehorn 	return (0);
43327bd4146SNathan Whitehorn }
43427bd4146SNathan Whitehorn 
43527bd4146SNathan Whitehorn /*
43627bd4146SNathan Whitehorn  * LD_BIND_NOW was set - force relocation for all jump slots
43727bd4146SNathan Whitehorn  */
43827bd4146SNathan Whitehorn int
439082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
44027bd4146SNathan Whitehorn {
44127bd4146SNathan Whitehorn 	const Obj_Entry *defobj;
44227bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
44327bd4146SNathan Whitehorn 	const Elf_Rela *rela;
44427bd4146SNathan Whitehorn 	const Elf_Sym *def;
44527bd4146SNathan Whitehorn 	Elf_Addr *where;
44627bd4146SNathan Whitehorn 	Elf_Addr target;
44727bd4146SNathan Whitehorn 
448903e0ffdSAlex Richardson 	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
449903e0ffdSAlex Richardson 	    obj->pltrelasize);
45027bd4146SNathan Whitehorn 	for (rela = obj->pltrela; rela < relalim; rela++) {
451*41b4ec8aSBrandon Bergren 		/* This isn't actually a jump slot, ignore it. */
452*41b4ec8aSBrandon Bergren 		if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE)
453*41b4ec8aSBrandon Bergren 			continue;
45427bd4146SNathan Whitehorn 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
45527bd4146SNathan Whitehorn 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
45627bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
457082f959aSKonstantin Belousov 		    SYMLOOK_IN_PLT | flags, NULL, lockstate);
45827bd4146SNathan Whitehorn 		if (def == NULL) {
45927bd4146SNathan Whitehorn 			dbg("reloc_jmpslots: sym not found");
46027bd4146SNathan Whitehorn 			return (-1);
46127bd4146SNathan Whitehorn 		}
46227bd4146SNathan Whitehorn 
46327bd4146SNathan Whitehorn 		target = (Elf_Addr)(defobj->relocbase + def->st_value);
46427bd4146SNathan Whitehorn 
465d48dde6fSNathan Whitehorn 		if (def == &sym_zero) {
466d48dde6fSNathan Whitehorn 			/* Zero undefined weak symbols */
46729ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
468d48dde6fSNathan Whitehorn 			bzero(where, sizeof(struct funcdesc));
46929ba9b61SNathan Whitehorn #else
47029ba9b61SNathan Whitehorn 			*where = 0;
47129ba9b61SNathan Whitehorn #endif
472d48dde6fSNathan Whitehorn 		} else {
473*41b4ec8aSBrandon Bergren 			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
474*41b4ec8aSBrandon Bergren 				/* LD_BIND_NOW, ifunc in shared lib.*/
475*41b4ec8aSBrandon Bergren 				obj->gnu_ifunc = true;
476*41b4ec8aSBrandon Bergren 				continue;
477*41b4ec8aSBrandon Bergren 			}
47827bd4146SNathan Whitehorn 			reloc_jmpslot(where, target, defobj, obj,
47927bd4146SNathan Whitehorn 			    (const Elf_Rel *) rela);
48027bd4146SNathan Whitehorn 		}
481d48dde6fSNathan Whitehorn 	}
48227bd4146SNathan Whitehorn 
48327bd4146SNathan Whitehorn 	obj->jmpslots_done = true;
48427bd4146SNathan Whitehorn 
48527bd4146SNathan Whitehorn 	return (0);
48627bd4146SNathan Whitehorn }
48727bd4146SNathan Whitehorn 
48827bd4146SNathan Whitehorn 
48927bd4146SNathan Whitehorn /*
49027bd4146SNathan Whitehorn  * Update the value of a PLT jump slot.
49127bd4146SNathan Whitehorn  */
49227bd4146SNathan Whitehorn Elf_Addr
493b6abe132SJustin Hibbits reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj __unused,
494903e0ffdSAlex Richardson     const Obj_Entry *obj __unused, const Elf_Rel *rel __unused)
49527bd4146SNathan Whitehorn {
49627bd4146SNathan Whitehorn 
49727bd4146SNathan Whitehorn 	/*
49827bd4146SNathan Whitehorn 	 * At the PLT entry pointed at by `wherep', construct
49927bd4146SNathan Whitehorn 	 * a direct transfer to the now fully resolved function
50027bd4146SNathan Whitehorn 	 * address.
50127bd4146SNathan Whitehorn 	 */
50227bd4146SNathan Whitehorn 
50329ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
50429ba9b61SNathan Whitehorn 	dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
50529ba9b61SNathan Whitehorn 	    (void *)wherep, (void *)target, *(Elf_Addr *)target,
50629ba9b61SNathan Whitehorn 	    (Elf_Addr)defobj->relocbase);
50729ba9b61SNathan Whitehorn 
508e35ddbe4SKonstantin Belousov 	if (ld_bind_not)
509e35ddbe4SKonstantin Belousov 		goto out;
510e35ddbe4SKonstantin Belousov 
511a4c5dfc0SNathan Whitehorn 	/*
512a4c5dfc0SNathan Whitehorn 	 * For the trampoline, the second two elements of the function
513a4c5dfc0SNathan Whitehorn 	 * descriptor are unused, so we are fine replacing those at any time
514a4c5dfc0SNathan Whitehorn 	 * with the real ones with no thread safety implications. However, we
515a4c5dfc0SNathan Whitehorn 	 * need to make sure the main entry point pointer ([0]) is seen to be
516a4c5dfc0SNathan Whitehorn 	 * modified *after* the second two elements. This can't be done in
517a4c5dfc0SNathan Whitehorn 	 * general, since there are no barriers in the reading code, but put in
518a4c5dfc0SNathan Whitehorn 	 * some isyncs to at least make it a little better.
519a4c5dfc0SNathan Whitehorn 	 */
52027bd4146SNathan Whitehorn 	memcpy(wherep, (void *)target, sizeof(struct funcdesc));
521a4c5dfc0SNathan Whitehorn 	wherep[2] = ((Elf_Addr *)target)[2];
522a4c5dfc0SNathan Whitehorn 	wherep[1] = ((Elf_Addr *)target)[1];
523a4c5dfc0SNathan Whitehorn 	__asm __volatile ("isync" : : : "memory");
524a4c5dfc0SNathan Whitehorn 	wherep[0] = ((Elf_Addr *)target)[0];
525a4c5dfc0SNathan Whitehorn 	__asm __volatile ("isync" : : : "memory");
526a4c5dfc0SNathan Whitehorn 
52727bd4146SNathan Whitehorn 	if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
52827bd4146SNathan Whitehorn 		/*
529a4c5dfc0SNathan Whitehorn 		 * It is possible (LD_BIND_NOW) that the function
53027bd4146SNathan Whitehorn 		 * descriptor we are copying has not yet been relocated.
531a4c5dfc0SNathan Whitehorn 		 * If this happens, fix it. Don't worry about threading in
532a4c5dfc0SNathan Whitehorn 		 * this case since LD_BIND_NOW makes it irrelevant.
53327bd4146SNathan Whitehorn 		 */
53427bd4146SNathan Whitehorn 
53527bd4146SNathan Whitehorn 		((struct funcdesc *)(wherep))->addr +=
53627bd4146SNathan Whitehorn 		    (Elf_Addr)defobj->relocbase;
53727bd4146SNathan Whitehorn 		((struct funcdesc *)(wherep))->toc +=
53827bd4146SNathan Whitehorn 		    (Elf_Addr)defobj->relocbase;
53927bd4146SNathan Whitehorn 	}
54029ba9b61SNathan Whitehorn #else
54129ba9b61SNathan Whitehorn 	dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
54229ba9b61SNathan Whitehorn 	    (void *)target);
54327bd4146SNathan Whitehorn 
544*41b4ec8aSBrandon Bergren 	assert(target >= (Elf_Addr)defobj->relocbase);
545*41b4ec8aSBrandon Bergren 
546*41b4ec8aSBrandon Bergren 	if (ld_bind_not)
547*41b4ec8aSBrandon Bergren 		goto out;
548*41b4ec8aSBrandon Bergren 
549*41b4ec8aSBrandon Bergren 	if (*wherep != target)
55029ba9b61SNathan Whitehorn 		*wherep = target;
551*41b4ec8aSBrandon Bergren 
55229ba9b61SNathan Whitehorn #endif
553*41b4ec8aSBrandon Bergren out:
55429ba9b61SNathan Whitehorn 
55527bd4146SNathan Whitehorn 	return (target);
55627bd4146SNathan Whitehorn }
55727bd4146SNathan Whitehorn 
5586be4b697SKonstantin Belousov int
559*41b4ec8aSBrandon Bergren reloc_iresolve(Obj_Entry *obj,
560*41b4ec8aSBrandon Bergren     struct Struct_RtldLockState *lockstate)
5616be4b697SKonstantin Belousov {
562*41b4ec8aSBrandon Bergren 	/*
563*41b4ec8aSBrandon Bergren 	 * Since PLT slots on PowerPC64 are always R_PPC_JMP_SLOT,
564*41b4ec8aSBrandon Bergren 	 * R_PPC_IRELATIVE is in RELA.
565*41b4ec8aSBrandon Bergren 	 */
566*41b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1
567*41b4ec8aSBrandon Bergren 	(void)(obj);
568*41b4ec8aSBrandon Bergren 	(void)(lockstate);
5696be4b697SKonstantin Belousov 	/* XXX not implemented */
5706be4b697SKonstantin Belousov 	return (0);
571*41b4ec8aSBrandon Bergren #else
572*41b4ec8aSBrandon Bergren 	const Elf_Rela *relalim;
573*41b4ec8aSBrandon Bergren 	const Elf_Rela *rela;
574*41b4ec8aSBrandon Bergren 	Elf_Addr *where, target, *ptr;
575*41b4ec8aSBrandon Bergren 
576*41b4ec8aSBrandon Bergren 	if (!obj->irelative)
577*41b4ec8aSBrandon Bergren 		return (0);
578*41b4ec8aSBrandon Bergren 
579*41b4ec8aSBrandon Bergren 	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
580*41b4ec8aSBrandon Bergren 	for (rela = obj->rela;  rela < relalim;  rela++) {
581*41b4ec8aSBrandon Bergren 		if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
582*41b4ec8aSBrandon Bergren 			ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
583*41b4ec8aSBrandon Bergren 			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
584*41b4ec8aSBrandon Bergren 
585*41b4ec8aSBrandon Bergren 			lock_release(rtld_bind_lock, lockstate);
586*41b4ec8aSBrandon Bergren 			target = call_ifunc_resolver(ptr);
587*41b4ec8aSBrandon Bergren 			wlock_acquire(rtld_bind_lock, lockstate);
588*41b4ec8aSBrandon Bergren 
589*41b4ec8aSBrandon Bergren 			*where = target;
590*41b4ec8aSBrandon Bergren 		}
591*41b4ec8aSBrandon Bergren 	}
592*41b4ec8aSBrandon Bergren 	/*
593*41b4ec8aSBrandon Bergren 	 * XXX Remove me when lld is fixed!
594*41b4ec8aSBrandon Bergren 	 * LLD currently makes illegal relocations in the PLT.
595*41b4ec8aSBrandon Bergren 	 */
596*41b4ec8aSBrandon Bergren         relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
597*41b4ec8aSBrandon Bergren         for (rela = obj->pltrela;  rela < relalim;  rela++) {
598*41b4ec8aSBrandon Bergren                 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
599*41b4ec8aSBrandon Bergren                         ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
600*41b4ec8aSBrandon Bergren                         where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
601*41b4ec8aSBrandon Bergren 
602*41b4ec8aSBrandon Bergren                         lock_release(rtld_bind_lock, lockstate);
603*41b4ec8aSBrandon Bergren                         target = call_ifunc_resolver(ptr);
604*41b4ec8aSBrandon Bergren                         wlock_acquire(rtld_bind_lock, lockstate);
605*41b4ec8aSBrandon Bergren 
606*41b4ec8aSBrandon Bergren                         *where = target;
607*41b4ec8aSBrandon Bergren                 }
608*41b4ec8aSBrandon Bergren         }
609*41b4ec8aSBrandon Bergren 
610*41b4ec8aSBrandon Bergren 	obj->irelative = false;
611*41b4ec8aSBrandon Bergren 	return (0);
612*41b4ec8aSBrandon Bergren #endif
6136be4b697SKonstantin Belousov }
6146be4b697SKonstantin Belousov 
6156be4b697SKonstantin Belousov int
616903e0ffdSAlex Richardson reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
617903e0ffdSAlex Richardson     struct Struct_RtldLockState *lockstate __unused)
6186be4b697SKonstantin Belousov {
619*41b4ec8aSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1
620*41b4ec8aSBrandon Bergren 	_rtld_error("reloc_gnu_ifunc(): Not implemented!");
6216be4b697SKonstantin Belousov 	/* XXX not implemented */
622*41b4ec8aSBrandon Bergren 	return (-1);
623*41b4ec8aSBrandon Bergren #else
624*41b4ec8aSBrandon Bergren 
625*41b4ec8aSBrandon Bergren 	const Elf_Rela *relalim;
626*41b4ec8aSBrandon Bergren 	const Elf_Rela *rela;
627*41b4ec8aSBrandon Bergren 	Elf_Addr *where, target;
628*41b4ec8aSBrandon Bergren 	const Elf_Sym *def;
629*41b4ec8aSBrandon Bergren 	const Obj_Entry *defobj;
630*41b4ec8aSBrandon Bergren 
631*41b4ec8aSBrandon Bergren 	if (!obj->gnu_ifunc)
6326be4b697SKonstantin Belousov 		return (0);
633*41b4ec8aSBrandon Bergren 	relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
634*41b4ec8aSBrandon Bergren 	for (rela = obj->pltrela;  rela < relalim;  rela++) {
635*41b4ec8aSBrandon Bergren 		if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) {
636*41b4ec8aSBrandon Bergren 			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
637*41b4ec8aSBrandon Bergren 			def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
638*41b4ec8aSBrandon Bergren 			    SYMLOOK_IN_PLT | flags, NULL, lockstate);
639*41b4ec8aSBrandon Bergren 			if (def == NULL)
640*41b4ec8aSBrandon Bergren 				return (-1);
641*41b4ec8aSBrandon Bergren 			if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
642*41b4ec8aSBrandon Bergren 				continue;
643*41b4ec8aSBrandon Bergren 			lock_release(rtld_bind_lock, lockstate);
644*41b4ec8aSBrandon Bergren 			target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
645*41b4ec8aSBrandon Bergren 			wlock_acquire(rtld_bind_lock, lockstate);
646*41b4ec8aSBrandon Bergren 			reloc_jmpslot(where, target, defobj, obj,
647*41b4ec8aSBrandon Bergren 			    (const Elf_Rel *)rela);
648*41b4ec8aSBrandon Bergren 		}
649*41b4ec8aSBrandon Bergren 	}
650*41b4ec8aSBrandon Bergren 	obj->gnu_ifunc = false;
651*41b4ec8aSBrandon Bergren 	return (0);
652*41b4ec8aSBrandon Bergren #endif
6536be4b697SKonstantin Belousov }
6546be4b697SKonstantin Belousov 
65527bd4146SNathan Whitehorn void
65627bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj)
65727bd4146SNathan Whitehorn {
65829ba9b61SNathan Whitehorn 	Elf_Addr *pltcall;
65929ba9b61SNathan Whitehorn 
66029ba9b61SNathan Whitehorn 	pltcall = obj->pltgot;
66129ba9b61SNathan Whitehorn 
66229ba9b61SNathan Whitehorn 	if (pltcall == NULL) {
66329ba9b61SNathan Whitehorn 		return;
66429ba9b61SNathan Whitehorn 	}
66529ba9b61SNathan Whitehorn 
666a4c5dfc0SNathan Whitehorn #if defined(_CALL_ELF) && _CALL_ELF == 2
66729ba9b61SNathan Whitehorn 	pltcall[0] = (Elf_Addr)&_rtld_bind_start;
66829ba9b61SNathan Whitehorn 	pltcall[1] = (Elf_Addr)obj;
669a4c5dfc0SNathan Whitehorn #else
670a4c5dfc0SNathan Whitehorn 	memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc));
671a4c5dfc0SNathan Whitehorn 	pltcall[2] = (Elf_Addr)obj;
67229ba9b61SNathan Whitehorn #endif
67327bd4146SNathan Whitehorn }
67427bd4146SNathan Whitehorn 
675*41b4ec8aSBrandon Bergren /*
676*41b4ec8aSBrandon Bergren  * Actual values are 32 bit.
677*41b4ec8aSBrandon Bergren  */
678*41b4ec8aSBrandon Bergren u_long cpu_features;
679*41b4ec8aSBrandon Bergren u_long cpu_features2;
680*41b4ec8aSBrandon Bergren 
681*41b4ec8aSBrandon Bergren void
682*41b4ec8aSBrandon Bergren powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info)
683*41b4ec8aSBrandon Bergren {
684*41b4ec8aSBrandon Bergren 	/*
685*41b4ec8aSBrandon Bergren 	 * Since aux_info[] is easier to work with than aux, go ahead and
686*41b4ec8aSBrandon Bergren 	 * initialize cpu_features / cpu_features2.
687*41b4ec8aSBrandon Bergren 	 */
688*41b4ec8aSBrandon Bergren 	cpu_features = -1UL;
689*41b4ec8aSBrandon Bergren 	cpu_features2 = -1UL;
690*41b4ec8aSBrandon Bergren 	if (aux_info[AT_HWCAP] != NULL)
691*41b4ec8aSBrandon Bergren 		cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val;
692*41b4ec8aSBrandon Bergren 	if (aux_info[AT_HWCAP2] != NULL)
693*41b4ec8aSBrandon Bergren 		cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val;
694*41b4ec8aSBrandon Bergren }
695*41b4ec8aSBrandon Bergren 
69627bd4146SNathan Whitehorn void
697d27078f9SKonstantin Belousov ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
6984352999eSKonstantin Belousov {
69941fc6f68SMarius Strobl 
70041fc6f68SMarius Strobl }
70141fc6f68SMarius Strobl 
70241fc6f68SMarius Strobl void
70341fc6f68SMarius Strobl pre_init(void)
70441fc6f68SMarius Strobl {
70541fc6f68SMarius Strobl 
7064352999eSKonstantin Belousov }
7074352999eSKonstantin Belousov 
7084352999eSKonstantin Belousov void
70927bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list)
71027bd4146SNathan Whitehorn {
711746ae9dfSNathan Whitehorn 	Elf_Addr **tp;
71227bd4146SNathan Whitehorn 
71327bd4146SNathan Whitehorn 	/*
71427bd4146SNathan Whitehorn 	* Fix the size of the static TLS block by using the maximum
71527bd4146SNathan Whitehorn 	* offset allocated so far and adding a bit for dynamic modules to
71627bd4146SNathan Whitehorn 	* use.
71727bd4146SNathan Whitehorn 	*/
71827bd4146SNathan Whitehorn 
71927bd4146SNathan Whitehorn 	tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
72027bd4146SNathan Whitehorn 
721746ae9dfSNathan Whitehorn 	tp = (Elf_Addr **)((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16)
72227bd4146SNathan Whitehorn 	    + TLS_TP_OFFSET + TLS_TCB_SIZE);
72327bd4146SNathan Whitehorn 
724746ae9dfSNathan Whitehorn 	__asm __volatile("mr 13,%0" :: "r"(tp));
72527bd4146SNathan Whitehorn }
72627bd4146SNathan Whitehorn 
72727bd4146SNathan Whitehorn void*
72827bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti)
72927bd4146SNathan Whitehorn {
730746ae9dfSNathan Whitehorn 	Elf_Addr **tp;
73127bd4146SNathan Whitehorn 	char *p;
73227bd4146SNathan Whitehorn 
733746ae9dfSNathan Whitehorn 	__asm __volatile("mr %0,13" : "=r"(tp));
73427bd4146SNathan Whitehorn 	p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET
73527bd4146SNathan Whitehorn 	    - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
73627bd4146SNathan Whitehorn 
73727bd4146SNathan Whitehorn 	return (p + TLS_DTV_OFFSET);
73827bd4146SNathan Whitehorn }
739