1/*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (C) 1998   Tsubai Masanari
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/mman.h>
34#include <sys/sysctl.h>
35
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include <machine/cpu.h>
42#include <machine/md_var.h>
43
44#include "debug.h"
45#include "rtld.h"
46
47#if !defined(_CALL_ELF) || _CALL_ELF == 1
48struct funcdesc {
49	Elf_Addr addr;
50	Elf_Addr toc;
51	Elf_Addr env;
52};
53#endif
54
55bool
56arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp)
57{
58	if (dynp->d_tag == DT_PPC64_GLINK) {
59		obj->glink = (Elf_Addr)(obj->relocbase + dynp->d_un.d_ptr);
60		return (true);
61	}
62
63	return (false);
64}
65
66/*
67 * Process the R_PPC_COPY relocations
68 */
69int
70do_copy_relocations(Obj_Entry *dstobj)
71{
72	const Elf_Rela *relalim;
73	const Elf_Rela *rela;
74
75	/*
76	 * COPY relocs are invalid outside of the main program
77	 */
78	assert(dstobj->mainprog);
79
80	relalim = (const Elf_Rela *)((const char *) dstobj->rela +
81	    dstobj->relasize);
82	for (rela = dstobj->rela;  rela < relalim;  rela++) {
83		void *dstaddr;
84		const Elf_Sym *dstsym;
85		const char *name;
86		size_t size;
87		const void *srcaddr;
88		const Elf_Sym *srcsym = NULL;
89		const Obj_Entry *srcobj, *defobj;
90		SymLook req;
91		int res;
92
93		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
94			continue;
95		}
96
97		dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
98		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
99		name = dstobj->strtab + dstsym->st_name;
100		size = dstsym->st_size;
101		symlook_init(&req, name);
102		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
103		req.flags = SYMLOOK_EARLY;
104
105		for (srcobj = globallist_next(dstobj); srcobj != NULL;
106		     srcobj = globallist_next(srcobj)) {
107			res = symlook_obj(&req, srcobj);
108			if (res == 0) {
109				srcsym = req.sym_out;
110				defobj = req.defobj_out;
111				break;
112			}
113		}
114
115		if (srcobj == NULL) {
116			_rtld_error("Undefined symbol \"%s\" "
117				    " referenced from COPY"
118				    " relocation in %s", name, dstobj->path);
119			return (-1);
120		}
121
122		srcaddr = (const void *)(defobj->relocbase+srcsym->st_value);
123		memcpy(dstaddr, srcaddr, size);
124		dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
125	}
126
127	return (0);
128}
129
130
131/*
132 * Perform early relocation of the run-time linker image
133 */
134void
135reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
136{
137	const Elf_Rela *rela = NULL, *relalim;
138	Elf_Addr relasz = 0;
139	Elf_Addr *where;
140
141	/*
142	 * Extract the rela/relasz values from the dynamic section
143	 */
144	for (; dynp->d_tag != DT_NULL; dynp++) {
145		switch (dynp->d_tag) {
146		case DT_RELA:
147			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
148			break;
149		case DT_RELASZ:
150			relasz = dynp->d_un.d_val;
151			break;
152		}
153	}
154
155	/*
156	 * Relocate these values
157	 */
158	relalim = (const Elf_Rela *)((const char *)rela + relasz);
159	for (; rela < relalim; rela++) {
160		where = (Elf_Addr *)(relocbase + rela->r_offset);
161		*where = (Elf_Addr)(relocbase + rela->r_addend);
162	}
163}
164
165
166/*
167 * Relocate a non-PLT object with addend.
168 */
169static int
170reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj,
171    const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate)
172{
173	const Elf_Sym	*def = NULL;
174	const Obj_Entry	*defobj;
175	Elf_Addr	*where, symval = 0;
176
177	/*
178	 * First, resolve symbol for relocations which
179	 * reference symbols.
180	 */
181	switch (ELF_R_TYPE(rela->r_info)) {
182
183	case R_PPC64_UADDR64:    /* doubleword64 S + A */
184	case R_PPC64_ADDR64:
185	case R_PPC_GLOB_DAT:
186	case R_PPC64_DTPMOD64:
187	case R_PPC64_TPREL64:
188	case R_PPC64_DTPREL64:
189		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
190		    flags, cache, lockstate);
191		if (def == NULL) {
192			return (-1);
193		}
194		/*
195		 * If symbol is IFUNC, only perform relocation
196		 * when caller allowed it by passing
197		 * SYMLOOK_IFUNC flag.  Skip the relocations
198		 * otherwise.
199		 *
200		 * Also error out in case IFUNC relocations
201		 * are specified for TLS, which cannot be
202		 * usefully interpreted.
203		 */
204		if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
205			switch (ELF_R_TYPE(rela->r_info)) {
206			case R_PPC64_UADDR64:
207			case R_PPC64_ADDR64:
208			case R_PPC_GLOB_DAT:
209				if ((flags & SYMLOOK_IFUNC) == 0) {
210					dbg("Non-PLT reference to IFUNC found!");
211					obj->non_plt_gnu_ifunc = true;
212					return (0);
213				}
214				symval = (Elf_Addr)rtld_resolve_ifunc(
215					defobj, def);
216				break;
217			default:
218				_rtld_error("%s: IFUNC for TLS reloc",
219					 obj->path);
220				return (-1);
221			}
222		} else {
223			if ((flags & SYMLOOK_IFUNC) != 0)
224				return (0);
225			symval = (Elf_Addr)defobj->relocbase +
226				def->st_value;
227		}
228		break;
229	default:
230		if ((flags & SYMLOOK_IFUNC) != 0)
231			return (0);
232	}
233
234	where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
235
236	switch (ELF_R_TYPE(rela->r_info)) {
237	case R_PPC_NONE:
238		break;
239	case R_PPC64_UADDR64:
240	case R_PPC64_ADDR64:
241	case R_PPC_GLOB_DAT:
242		/* Don't issue write if unnecessary; avoid COW page fault */
243		if (*where != symval + rela->r_addend) {
244			*where = symval + rela->r_addend;
245		}
246		break;
247	case R_PPC64_DTPMOD64:
248		*where = (Elf_Addr) defobj->tlsindex;
249		break;
250	case R_PPC64_TPREL64:
251		/*
252		 * We lazily allocate offsets for static TLS as we
253		 * see the first relocation that references the
254		 * TLS block. This allows us to support (small
255		 * amounts of) static TLS in dynamically loaded
256		 * modules. If we run out of space, we generate an
257		 * error.
258		 */
259		if (!defobj->tls_static) {
260			if (!allocate_tls_offset(
261				    __DECONST(Obj_Entry *, defobj))) {
262				_rtld_error("%s: No space available for static "
263				    "Thread Local Storage", obj->path);
264				return (-1);
265			}
266		}
267
268		*(Elf_Addr **)where = *where * sizeof(Elf_Addr)
269		    + (Elf_Addr *)(def->st_value + rela->r_addend
270		    + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
271		break;
272	case R_PPC64_DTPREL64:
273		*where += (Elf_Addr)(def->st_value + rela->r_addend
274		    - TLS_DTV_OFFSET);
275		break;
276	case R_PPC_RELATIVE:  /* doubleword64 B + A */
277		symval = (Elf_Addr)(obj->relocbase + rela->r_addend);
278
279		/* As above, don't issue write unnecessarily */
280		if (*where != symval) {
281			*where = symval;
282		}
283		break;
284	case R_PPC_COPY:
285		/*
286		 * These are deferred until all other relocations
287		 * have been done.  All we do here is make sure
288		 * that the COPY relocation is not in a shared
289		 * library.  They are allowed only in executable
290		 * files.
291		 */
292		if (!obj->mainprog) {
293			_rtld_error("%s: Unexpected R_COPY "
294				    " relocation in shared library",
295				    obj->path);
296			return (-1);
297		}
298		break;
299	case R_PPC_IRELATIVE:
300		/*
301		 * These will be handled by reloc_iresolve().
302		 */
303		obj->irelative = true;
304		break;
305	case R_PPC_JMP_SLOT:
306		/*
307		 * These will be handled by the plt/jmpslot routines
308		 */
309		break;
310
311	default:
312		_rtld_error("%s: Unsupported relocation type %ld"
313			    " in non-PLT relocations\n", obj->path,
314			    ELF_R_TYPE(rela->r_info));
315		return (-1);
316	}
317	return (0);
318}
319
320
321/*
322 * Process non-PLT relocations
323 */
324int
325reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
326    RtldLockState *lockstate)
327{
328	const Elf_Rela *relalim;
329	const Elf_Rela *rela;
330	const Elf_Phdr *phdr;
331	SymCache *cache;
332	int bytes = obj->dynsymcount * sizeof(SymCache);
333	int r = -1;
334
335	/*
336	 * The dynamic loader may be called from a thread, we have
337	 * limited amounts of stack available so we cannot use alloca().
338	 */
339	if (obj != obj_rtld) {
340		cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
341		    -1, 0);
342		if (cache == MAP_FAILED)
343			cache = NULL;
344	} else
345		cache = NULL;
346
347	/*
348	 * From the SVR4 PPC ABI:
349	 * "The PowerPC family uses only the Elf32_Rela relocation
350	 *  entries with explicit addends."
351	 */
352	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
353	for (rela = obj->rela; rela < relalim; rela++) {
354		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
355		    lockstate) < 0)
356			goto done;
357	}
358	r = 0;
359done:
360	if (cache)
361		munmap(cache, bytes);
362
363	/*
364	 * Synchronize icache for executable segments in case we made
365	 * any changes.
366	 */
367	for (phdr = obj->phdr;
368	    (const char *)phdr < (const char *)obj->phdr + obj->phsize;
369	    phdr++) {
370		if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
371			__syncicache(obj->relocbase + phdr->p_vaddr,
372			    phdr->p_memsz);
373		}
374	}
375
376	return (r);
377}
378
379
380/*
381 * Initialise a PLT slot to the resolving trampoline
382 */
383static int
384reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
385{
386	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
387	long reloff;
388
389	reloff = rela - obj->pltrela;
390
391	dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where,
392	    reloff, obj->glink);
393
394#if !defined(_CALL_ELF) || _CALL_ELF == 1
395	/* Glink code is 3 instructions after the first 32k, 2 before */
396	*where = (Elf_Addr)obj->glink + 32 +
397	    8*((reloff < 0x8000) ? reloff : 0x8000) +
398	    12*((reloff < 0x8000) ? 0 : (reloff - 0x8000));
399#else
400	/* 64-Bit ELF V2 ABI Specification, sec. 4.2.5.3. */
401	*where = (Elf_Addr)obj->glink + 4*reloff + 32;
402#endif
403
404	return (0);
405}
406
407/*
408 * Process the PLT relocations.
409 */
410int
411reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
412{
413	const Elf_Rela *relalim;
414	const Elf_Rela *rela;
415
416	if (obj->pltrelasize != 0) {
417		relalim = (const Elf_Rela *)((const char *)obj->pltrela +
418		    obj->pltrelasize);
419		for (rela = obj->pltrela;  rela < relalim;  rela++) {
420
421#if defined(_CALL_ELF) && _CALL_ELF == 2
422			if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
423				dbg("ABI violation - found IRELATIVE in the PLT.");
424				obj->irelative = true;
425				continue;
426			}
427#endif
428			/*
429			 * PowerPC(64) .rela.plt is composed of an array of
430			 * R_PPC_JMP_SLOT relocations. Unlike other platforms,
431			 * this is the ONLY relocation type that is valid here.
432			 */
433			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
434
435			if (reloc_plt_object(obj, rela) < 0) {
436				return (-1);
437			}
438		}
439	}
440
441	return (0);
442}
443
444/*
445 * LD_BIND_NOW was set - force relocation for all jump slots
446 */
447int
448reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
449{
450	const Obj_Entry *defobj;
451	const Elf_Rela *relalim;
452	const Elf_Rela *rela;
453	const Elf_Sym *def;
454	Elf_Addr *where;
455	Elf_Addr target;
456
457	relalim = (const Elf_Rela *)((const char *)obj->pltrela +
458	    obj->pltrelasize);
459	for (rela = obj->pltrela; rela < relalim; rela++) {
460		/* This isn't actually a jump slot, ignore it. */
461		if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE)
462			continue;
463		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
464		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
465		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
466		    SYMLOOK_IN_PLT | flags, NULL, lockstate);
467		if (def == NULL) {
468			dbg("reloc_jmpslots: sym not found");
469			return (-1);
470		}
471
472		target = (Elf_Addr)(defobj->relocbase + def->st_value);
473
474		if (def == &sym_zero) {
475			/* Zero undefined weak symbols */
476#if !defined(_CALL_ELF) || _CALL_ELF == 1
477			bzero(where, sizeof(struct funcdesc));
478#else
479			*where = 0;
480#endif
481		} else {
482			if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
483				/* LD_BIND_NOW, ifunc in shared lib.*/
484				obj->gnu_ifunc = true;
485				continue;
486			}
487			reloc_jmpslot(where, target, defobj, obj,
488			    (const Elf_Rel *) rela);
489		}
490	}
491
492	obj->jmpslots_done = true;
493
494	return (0);
495}
496
497
498/*
499 * Update the value of a PLT jump slot.
500 */
501Elf_Addr
502reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj __unused,
503    const Obj_Entry *obj __unused, const Elf_Rel *rel __unused)
504{
505
506	/*
507	 * At the PLT entry pointed at by `wherep', construct
508	 * a direct transfer to the now fully resolved function
509	 * address.
510	 */
511
512#if !defined(_CALL_ELF) || _CALL_ELF == 1
513	dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
514	    (void *)wherep, (void *)target, *(Elf_Addr *)target,
515	    (Elf_Addr)defobj->relocbase);
516
517	if (ld_bind_not)
518		goto out;
519
520	/*
521	 * For the trampoline, the second two elements of the function
522	 * descriptor are unused, so we are fine replacing those at any time
523	 * with the real ones with no thread safety implications. However, we
524	 * need to make sure the main entry point pointer ([0]) is seen to be
525	 * modified *after* the second two elements. This can't be done in
526	 * general, since there are no barriers in the reading code, but put in
527	 * some isyncs to at least make it a little better.
528	 */
529	memcpy(wherep, (void *)target, sizeof(struct funcdesc));
530	wherep[2] = ((Elf_Addr *)target)[2];
531	wherep[1] = ((Elf_Addr *)target)[1];
532	__asm __volatile ("isync" : : : "memory");
533	wherep[0] = ((Elf_Addr *)target)[0];
534	__asm __volatile ("isync" : : : "memory");
535
536	if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
537		/*
538		 * It is possible (LD_BIND_NOW) that the function
539		 * descriptor we are copying has not yet been relocated.
540		 * If this happens, fix it. Don't worry about threading in
541		 * this case since LD_BIND_NOW makes it irrelevant.
542		 */
543
544		((struct funcdesc *)(wherep))->addr +=
545		    (Elf_Addr)defobj->relocbase;
546		((struct funcdesc *)(wherep))->toc +=
547		    (Elf_Addr)defobj->relocbase;
548	}
549#else
550	dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
551	    (void *)target);
552
553	assert(target >= (Elf_Addr)defobj->relocbase);
554
555	if (ld_bind_not)
556		goto out;
557
558	if (*wherep != target)
559		*wherep = target;
560
561#endif
562out:
563
564	return (target);
565}
566
567int
568reloc_iresolve(Obj_Entry *obj,
569    struct Struct_RtldLockState *lockstate)
570{
571	/*
572	 * Since PLT slots on PowerPC64 are always R_PPC_JMP_SLOT,
573	 * R_PPC_IRELATIVE is in RELA.
574	 */
575#if !defined(_CALL_ELF) || _CALL_ELF == 1
576	(void)(obj);
577	(void)(lockstate);
578	/* XXX not implemented */
579	return (0);
580#else
581	const Elf_Rela *relalim;
582	const Elf_Rela *rela;
583	Elf_Addr *where, target, *ptr;
584
585	if (!obj->irelative)
586		return (0);
587
588	relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
589	for (rela = obj->rela;  rela < relalim;  rela++) {
590		if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
591			ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
592			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
593
594			lock_release(rtld_bind_lock, lockstate);
595			target = call_ifunc_resolver(ptr);
596			wlock_acquire(rtld_bind_lock, lockstate);
597
598			*where = target;
599		}
600	}
601	/*
602	 * XXX Remove me when lld is fixed!
603	 * LLD currently makes illegal relocations in the PLT.
604	 */
605        relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
606        for (rela = obj->pltrela;  rela < relalim;  rela++) {
607                if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
608                        ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
609                        where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
610
611                        lock_release(rtld_bind_lock, lockstate);
612                        target = call_ifunc_resolver(ptr);
613                        wlock_acquire(rtld_bind_lock, lockstate);
614
615                        *where = target;
616                }
617        }
618
619	obj->irelative = false;
620	return (0);
621#endif
622}
623
624int
625reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
626    struct Struct_RtldLockState *lockstate __unused)
627{
628#if !defined(_CALL_ELF) || _CALL_ELF == 1
629	_rtld_error("reloc_gnu_ifunc(): Not implemented!");
630	/* XXX not implemented */
631	return (-1);
632#else
633
634	const Elf_Rela *relalim;
635	const Elf_Rela *rela;
636	Elf_Addr *where, target;
637	const Elf_Sym *def;
638	const Obj_Entry *defobj;
639
640	if (!obj->gnu_ifunc)
641		return (0);
642	relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
643	for (rela = obj->pltrela;  rela < relalim;  rela++) {
644		if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) {
645			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
646			def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
647			    SYMLOOK_IN_PLT | flags, NULL, lockstate);
648			if (def == NULL)
649				return (-1);
650			if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
651				continue;
652			lock_release(rtld_bind_lock, lockstate);
653			target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
654			wlock_acquire(rtld_bind_lock, lockstate);
655			reloc_jmpslot(where, target, defobj, obj,
656			    (const Elf_Rel *)rela);
657		}
658	}
659	obj->gnu_ifunc = false;
660	return (0);
661#endif
662}
663
664int
665reloc_iresolve_nonplt(Obj_Entry *obj __unused,
666    struct Struct_RtldLockState *lockstate __unused)
667{
668	return (0);
669}
670
671void
672init_pltgot(Obj_Entry *obj)
673{
674	Elf_Addr *pltcall;
675
676	pltcall = obj->pltgot;
677
678	if (pltcall == NULL) {
679		return;
680	}
681
682#if defined(_CALL_ELF) && _CALL_ELF == 2
683	pltcall[0] = (Elf_Addr)&_rtld_bind_start;
684	pltcall[1] = (Elf_Addr)obj;
685#else
686	memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc));
687	pltcall[2] = (Elf_Addr)obj;
688#endif
689}
690
691/*
692 * Actual values are 32 bit.
693 */
694u_long cpu_features;
695u_long cpu_features2;
696
697void
698powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info)
699{
700	/*
701	 * Since aux_info[] is easier to work with than aux, go ahead and
702	 * initialize cpu_features / cpu_features2.
703	 */
704	cpu_features = -1UL;
705	cpu_features2 = -1UL;
706	if (aux_info[AT_HWCAP] != NULL)
707		cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val;
708	if (aux_info[AT_HWCAP2] != NULL)
709		cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val;
710}
711
712void
713ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused)
714{
715
716}
717
718void
719allocate_initial_tls(Obj_Entry *list)
720{
721
722	/*
723	* Fix the size of the static TLS block by using the maximum
724	* offset allocated so far and adding a bit for dynamic modules to
725	* use.
726	*/
727
728	tls_static_space = tls_last_offset + tls_last_size +
729	    ld_static_tls_extra;
730
731	_tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
732}
733
734void*
735__tls_get_addr(tls_index* ti)
736{
737	uintptr_t **dtvp;
738	char *p;
739
740	dtvp = &_tcb_get()->tcb_dtv;
741	p = tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset);
742
743	return (p + TLS_DTV_OFFSET);
744}
745