xref: /freebsd/libexec/rtld-elf/powerpc64/reloc.c (revision 9fee0541f2815c1ea70ccc13402f3ed6c4ed9fdf)
127bd4146SNathan Whitehorn /*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
227bd4146SNathan Whitehorn 
327bd4146SNathan Whitehorn /*-
427bd4146SNathan Whitehorn  * Copyright (C) 1998   Tsubai Masanari
527bd4146SNathan Whitehorn  * All rights reserved.
627bd4146SNathan Whitehorn  *
727bd4146SNathan Whitehorn  * Redistribution and use in source and binary forms, with or without
827bd4146SNathan Whitehorn  * modification, are permitted provided that the following conditions
927bd4146SNathan Whitehorn  * are met:
1027bd4146SNathan Whitehorn  * 1. Redistributions of source code must retain the above copyright
1127bd4146SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer.
1227bd4146SNathan Whitehorn  * 2. Redistributions in binary form must reproduce the above copyright
1327bd4146SNathan Whitehorn  *    notice, this list of conditions and the following disclaimer in the
1427bd4146SNathan Whitehorn  *    documentation and/or other materials provided with the distribution.
1527bd4146SNathan Whitehorn  * 3. The name of the author may not be used to endorse or promote products
1627bd4146SNathan Whitehorn  *    derived from this software without specific prior written permission.
1727bd4146SNathan Whitehorn  *
1827bd4146SNathan Whitehorn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1927bd4146SNathan Whitehorn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2027bd4146SNathan Whitehorn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2127bd4146SNathan Whitehorn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2227bd4146SNathan Whitehorn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2327bd4146SNathan Whitehorn  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2427bd4146SNathan Whitehorn  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2527bd4146SNathan Whitehorn  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2627bd4146SNathan Whitehorn  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2727bd4146SNathan Whitehorn  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2827bd4146SNathan Whitehorn  *
2927bd4146SNathan Whitehorn  * $FreeBSD$
3027bd4146SNathan Whitehorn  */
3127bd4146SNathan Whitehorn 
3227bd4146SNathan Whitehorn #include <sys/param.h>
3327bd4146SNathan Whitehorn #include <sys/mman.h>
3427bd4146SNathan Whitehorn 
3527bd4146SNathan Whitehorn #include <errno.h>
3627bd4146SNathan Whitehorn #include <stdio.h>
3727bd4146SNathan Whitehorn #include <stdlib.h>
3827bd4146SNathan Whitehorn #include <string.h>
3927bd4146SNathan Whitehorn #include <unistd.h>
40a29cc9a3SAndriy Gapon #include <machine/cpu.h>
4127bd4146SNathan Whitehorn #include <machine/md_var.h>
4227bd4146SNathan Whitehorn 
4327bd4146SNathan Whitehorn #include "debug.h"
4427bd4146SNathan Whitehorn #include "rtld.h"
4527bd4146SNathan Whitehorn 
4629ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
4727bd4146SNathan Whitehorn struct funcdesc {
4827bd4146SNathan Whitehorn 	Elf_Addr addr;
4927bd4146SNathan Whitehorn 	Elf_Addr toc;
5027bd4146SNathan Whitehorn 	Elf_Addr env;
5127bd4146SNathan Whitehorn };
5229ba9b61SNathan Whitehorn #endif
5327bd4146SNathan Whitehorn 
5427bd4146SNathan Whitehorn /*
5527bd4146SNathan Whitehorn  * Process the R_PPC_COPY relocations
5627bd4146SNathan Whitehorn  */
5727bd4146SNathan Whitehorn int
5827bd4146SNathan Whitehorn do_copy_relocations(Obj_Entry *dstobj)
5927bd4146SNathan Whitehorn {
6027bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
6127bd4146SNathan Whitehorn 	const Elf_Rela *rela;
6227bd4146SNathan Whitehorn 
6327bd4146SNathan Whitehorn 	/*
6427bd4146SNathan Whitehorn 	 * COPY relocs are invalid outside of the main program
6527bd4146SNathan Whitehorn 	 */
6627bd4146SNathan Whitehorn 	assert(dstobj->mainprog);
6727bd4146SNathan Whitehorn 
6827bd4146SNathan Whitehorn 	relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
6927bd4146SNathan Whitehorn 	    dstobj->relasize);
7027bd4146SNathan Whitehorn 	for (rela = dstobj->rela;  rela < relalim;  rela++) {
7127bd4146SNathan Whitehorn 		void *dstaddr;
7227bd4146SNathan Whitehorn 		const Elf_Sym *dstsym;
7327bd4146SNathan Whitehorn 		const char *name;
7427bd4146SNathan Whitehorn 		size_t size;
7527bd4146SNathan Whitehorn 		const void *srcaddr;
7627bd4146SNathan Whitehorn 		const Elf_Sym *srcsym = NULL;
778569deafSKonstantin Belousov 		const Obj_Entry *srcobj, *defobj;
788569deafSKonstantin Belousov 		SymLook req;
798569deafSKonstantin Belousov 		int res;
8027bd4146SNathan Whitehorn 
8127bd4146SNathan Whitehorn 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
8227bd4146SNathan Whitehorn 			continue;
8327bd4146SNathan Whitehorn 		}
8427bd4146SNathan Whitehorn 
8527bd4146SNathan Whitehorn 		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
8627bd4146SNathan Whitehorn 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
8727bd4146SNathan Whitehorn 		name = dstobj->strtab + dstsym->st_name;
8827bd4146SNathan Whitehorn 		size = dstsym->st_size;
898569deafSKonstantin Belousov 		symlook_init(&req, name);
908569deafSKonstantin Belousov 		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
91082f959aSKonstantin Belousov 		req.flags = SYMLOOK_EARLY;
9227bd4146SNathan Whitehorn 
93*9fee0541SKonstantin Belousov 		for (srcobj = globallist_next(dstobj); srcobj != NULL;
94*9fee0541SKonstantin Belousov 		     srcobj = globallist_next(srcobj)) {
958569deafSKonstantin Belousov 			res = symlook_obj(&req, srcobj);
968569deafSKonstantin Belousov 			if (res == 0) {
978569deafSKonstantin Belousov 				srcsym = req.sym_out;
988569deafSKonstantin Belousov 				defobj = req.defobj_out;
9927bd4146SNathan Whitehorn 				break;
10027bd4146SNathan Whitehorn 			}
10127bd4146SNathan Whitehorn 		}
10227bd4146SNathan Whitehorn 
10327bd4146SNathan Whitehorn 		if (srcobj == NULL) {
10427bd4146SNathan Whitehorn 			_rtld_error("Undefined symbol \"%s\" "
10527bd4146SNathan Whitehorn 				    " referenced from COPY"
10627bd4146SNathan Whitehorn 				    " relocation in %s", name, dstobj->path);
10727bd4146SNathan Whitehorn 			return (-1);
10827bd4146SNathan Whitehorn 		}
10927bd4146SNathan Whitehorn 
1108569deafSKonstantin Belousov 		srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
11127bd4146SNathan Whitehorn 		memcpy(dstaddr, srcaddr, size);
11227bd4146SNathan Whitehorn 		dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
11327bd4146SNathan Whitehorn 	}
11427bd4146SNathan Whitehorn 
11527bd4146SNathan Whitehorn 	return (0);
11627bd4146SNathan Whitehorn }
11727bd4146SNathan Whitehorn 
11827bd4146SNathan Whitehorn 
11927bd4146SNathan Whitehorn /*
12027bd4146SNathan Whitehorn  * Perform early relocation of the run-time linker image
12127bd4146SNathan Whitehorn  */
12227bd4146SNathan Whitehorn void
12327bd4146SNathan Whitehorn reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
12427bd4146SNathan Whitehorn {
12527bd4146SNathan Whitehorn 	const Elf_Rela *rela = 0, *relalim;
12627bd4146SNathan Whitehorn 	Elf_Addr relasz = 0;
12727bd4146SNathan Whitehorn 	Elf_Addr *where;
12827bd4146SNathan Whitehorn 
12927bd4146SNathan Whitehorn 	/*
13027bd4146SNathan Whitehorn 	 * Extract the rela/relasz values from the dynamic section
13127bd4146SNathan Whitehorn 	 */
13227bd4146SNathan Whitehorn 	for (; dynp->d_tag != DT_NULL; dynp++) {
13327bd4146SNathan Whitehorn 		switch (dynp->d_tag) {
13427bd4146SNathan Whitehorn 		case DT_RELA:
13527bd4146SNathan Whitehorn 			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
13627bd4146SNathan Whitehorn 			break;
13727bd4146SNathan Whitehorn 		case DT_RELASZ:
13827bd4146SNathan Whitehorn 			relasz = dynp->d_un.d_val;
13927bd4146SNathan Whitehorn 			break;
14027bd4146SNathan Whitehorn 		}
14127bd4146SNathan Whitehorn 	}
14227bd4146SNathan Whitehorn 
14327bd4146SNathan Whitehorn 	/*
14427bd4146SNathan Whitehorn 	 * Relocate these values
14527bd4146SNathan Whitehorn 	 */
14627bd4146SNathan Whitehorn 	relalim = (const Elf_Rela *)((caddr_t)rela + relasz);
14727bd4146SNathan Whitehorn 	for (; rela < relalim; rela++) {
14827bd4146SNathan Whitehorn 		where = (Elf_Addr *)(relocbase + rela->r_offset);
14927bd4146SNathan Whitehorn 		*where = (Elf_Addr)(relocbase + rela->r_addend);
15027bd4146SNathan Whitehorn 	}
15127bd4146SNathan Whitehorn }
15227bd4146SNathan Whitehorn 
15327bd4146SNathan Whitehorn 
15427bd4146SNathan Whitehorn /*
15527bd4146SNathan Whitehorn  * Relocate a non-PLT object with addend.
15627bd4146SNathan Whitehorn  */
15727bd4146SNathan Whitehorn static int
15827bd4146SNathan Whitehorn reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
159082f959aSKonstantin Belousov     SymCache *cache, int flags, RtldLockState *lockstate)
16027bd4146SNathan Whitehorn {
16127bd4146SNathan Whitehorn 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
16227bd4146SNathan Whitehorn 	const Elf_Sym   *def;
16327bd4146SNathan Whitehorn 	const Obj_Entry *defobj;
16427bd4146SNathan Whitehorn 	Elf_Addr         tmp;
16527bd4146SNathan Whitehorn 
16627bd4146SNathan Whitehorn 	switch (ELF_R_TYPE(rela->r_info)) {
16727bd4146SNathan Whitehorn 
16827bd4146SNathan Whitehorn 	case R_PPC_NONE:
16927bd4146SNathan Whitehorn 		break;
17027bd4146SNathan Whitehorn 
1719cc92083SNathan Whitehorn         case R_PPC64_UADDR64:    /* doubleword64 S + A */
1729cc92083SNathan Whitehorn         case R_PPC64_ADDR64:
17327bd4146SNathan Whitehorn         case R_PPC_GLOB_DAT:
17427bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
175082f959aSKonstantin Belousov 		    flags, cache, lockstate);
17627bd4146SNathan Whitehorn 		if (def == NULL) {
17727bd4146SNathan Whitehorn 			return (-1);
17827bd4146SNathan Whitehorn 		}
17927bd4146SNathan Whitehorn 
18027bd4146SNathan Whitehorn                 tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
18127bd4146SNathan Whitehorn                     rela->r_addend);
18227bd4146SNathan Whitehorn 
18327bd4146SNathan Whitehorn 		/* Don't issue write if unnecessary; avoid COW page fault */
18427bd4146SNathan Whitehorn                 if (*where != tmp) {
18527bd4146SNathan Whitehorn                         *where = tmp;
18627bd4146SNathan Whitehorn 		}
18727bd4146SNathan Whitehorn                 break;
18827bd4146SNathan Whitehorn 
18927bd4146SNathan Whitehorn         case R_PPC_RELATIVE:  /* doubleword64 B + A */
19027bd4146SNathan Whitehorn 		tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
19127bd4146SNathan Whitehorn 
19227bd4146SNathan Whitehorn 		/* As above, don't issue write unnecessarily */
19327bd4146SNathan Whitehorn 		if (*where != tmp) {
19427bd4146SNathan Whitehorn 			*where = tmp;
19527bd4146SNathan Whitehorn 		}
19627bd4146SNathan Whitehorn 		break;
19727bd4146SNathan Whitehorn 
19827bd4146SNathan Whitehorn 	case R_PPC_COPY:
19927bd4146SNathan Whitehorn 		/*
20027bd4146SNathan Whitehorn 		 * These are deferred until all other relocations
20127bd4146SNathan Whitehorn 		 * have been done.  All we do here is make sure
20227bd4146SNathan Whitehorn 		 * that the COPY relocation is not in a shared
20327bd4146SNathan Whitehorn 		 * library.  They are allowed only in executable
20427bd4146SNathan Whitehorn 		 * files.
20527bd4146SNathan Whitehorn 		 */
20627bd4146SNathan Whitehorn 		if (!obj->mainprog) {
20727bd4146SNathan Whitehorn 			_rtld_error("%s: Unexpected R_COPY "
20827bd4146SNathan Whitehorn 				    " relocation in shared library",
20927bd4146SNathan Whitehorn 				    obj->path);
21027bd4146SNathan Whitehorn 			return (-1);
21127bd4146SNathan Whitehorn 		}
21227bd4146SNathan Whitehorn 		break;
21327bd4146SNathan Whitehorn 
21427bd4146SNathan Whitehorn 	case R_PPC_JMP_SLOT:
21527bd4146SNathan Whitehorn 		/*
21627bd4146SNathan Whitehorn 		 * These will be handled by the plt/jmpslot routines
21727bd4146SNathan Whitehorn 		 */
21827bd4146SNathan Whitehorn 		break;
21927bd4146SNathan Whitehorn 
22027bd4146SNathan Whitehorn 	case R_PPC64_DTPMOD64:
22127bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
222082f959aSKonstantin Belousov 		    flags, cache, lockstate);
22327bd4146SNathan Whitehorn 
22427bd4146SNathan Whitehorn 		if (def == NULL)
22527bd4146SNathan Whitehorn 			return (-1);
22627bd4146SNathan Whitehorn 
22727bd4146SNathan Whitehorn 		*where = (Elf_Addr) defobj->tlsindex;
22827bd4146SNathan Whitehorn 
22927bd4146SNathan Whitehorn 		break;
23027bd4146SNathan Whitehorn 
23127bd4146SNathan Whitehorn 	case R_PPC64_TPREL64:
23227bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
233082f959aSKonstantin Belousov 		    flags, cache, lockstate);
23427bd4146SNathan Whitehorn 
23527bd4146SNathan Whitehorn 		if (def == NULL)
23627bd4146SNathan Whitehorn 			return (-1);
23727bd4146SNathan Whitehorn 
23827bd4146SNathan Whitehorn 		/*
23927bd4146SNathan Whitehorn 		 * We lazily allocate offsets for static TLS as we
24027bd4146SNathan Whitehorn 		 * see the first relocation that references the
24127bd4146SNathan Whitehorn 		 * TLS block. This allows us to support (small
24227bd4146SNathan Whitehorn 		 * amounts of) static TLS in dynamically loaded
24327bd4146SNathan Whitehorn 		 * modules. If we run out of space, we generate an
24427bd4146SNathan Whitehorn 		 * error.
24527bd4146SNathan Whitehorn 		 */
24627bd4146SNathan Whitehorn 		if (!defobj->tls_done) {
24727bd4146SNathan Whitehorn 			if (!allocate_tls_offset((Obj_Entry*) defobj)) {
24827bd4146SNathan Whitehorn 				_rtld_error("%s: No space available for static "
24927bd4146SNathan Whitehorn 				    "Thread Local Storage", obj->path);
25027bd4146SNathan Whitehorn 				return (-1);
25127bd4146SNathan Whitehorn 			}
25227bd4146SNathan Whitehorn 		}
25327bd4146SNathan Whitehorn 
25427bd4146SNathan Whitehorn 		*(Elf_Addr **)where = *where * sizeof(Elf_Addr)
25527bd4146SNathan Whitehorn 		    + (Elf_Addr *)(def->st_value + rela->r_addend
25627bd4146SNathan Whitehorn 		    + defobj->tlsoffset - TLS_TP_OFFSET);
25727bd4146SNathan Whitehorn 
25827bd4146SNathan Whitehorn 		break;
25927bd4146SNathan Whitehorn 
26027bd4146SNathan Whitehorn 	case R_PPC64_DTPREL64:
26127bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
262082f959aSKonstantin Belousov 		    flags, cache, lockstate);
26327bd4146SNathan Whitehorn 
26427bd4146SNathan Whitehorn 		if (def == NULL)
26527bd4146SNathan Whitehorn 			return (-1);
26627bd4146SNathan Whitehorn 
26727bd4146SNathan Whitehorn 		*where += (Elf_Addr)(def->st_value + rela->r_addend
26827bd4146SNathan Whitehorn 		    - TLS_DTV_OFFSET);
26927bd4146SNathan Whitehorn 
27027bd4146SNathan Whitehorn 		break;
27127bd4146SNathan Whitehorn 
27227bd4146SNathan Whitehorn 	default:
27327bd4146SNathan Whitehorn 		_rtld_error("%s: Unsupported relocation type %ld"
27427bd4146SNathan Whitehorn 			    " in non-PLT relocations\n", obj->path,
27527bd4146SNathan Whitehorn 			    ELF_R_TYPE(rela->r_info));
27627bd4146SNathan Whitehorn 		return (-1);
27727bd4146SNathan Whitehorn         }
27827bd4146SNathan Whitehorn 	return (0);
27927bd4146SNathan Whitehorn }
28027bd4146SNathan Whitehorn 
28127bd4146SNathan Whitehorn 
28227bd4146SNathan Whitehorn /*
28327bd4146SNathan Whitehorn  * Process non-PLT relocations
28427bd4146SNathan Whitehorn  */
28527bd4146SNathan Whitehorn int
286082f959aSKonstantin Belousov reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
287082f959aSKonstantin Belousov     RtldLockState *lockstate)
28827bd4146SNathan Whitehorn {
28927bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
29027bd4146SNathan Whitehorn 	const Elf_Rela *rela;
29127bd4146SNathan Whitehorn 	SymCache *cache;
292f6265192SKonstantin Belousov 	int bytes = obj->dynsymcount * sizeof(SymCache);
29327bd4146SNathan Whitehorn 	int r = -1;
29427bd4146SNathan Whitehorn 
29514c35647SKonstantin Belousov 	if ((flags & SYMLOOK_IFUNC) != 0)
29614c35647SKonstantin Belousov 		/* XXX not implemented */
29714c35647SKonstantin Belousov 		return (0);
29814c35647SKonstantin Belousov 
29927bd4146SNathan Whitehorn 	/*
30027bd4146SNathan Whitehorn 	 * The dynamic loader may be called from a thread, we have
30127bd4146SNathan Whitehorn 	 * limited amounts of stack available so we cannot use alloca().
30227bd4146SNathan Whitehorn 	 */
30327bd4146SNathan Whitehorn 	if (obj != obj_rtld) {
30427bd4146SNathan Whitehorn 		cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON,
30527bd4146SNathan Whitehorn 		    -1, 0);
30627bd4146SNathan Whitehorn 		if (cache == MAP_FAILED)
30727bd4146SNathan Whitehorn 			cache = NULL;
30827bd4146SNathan Whitehorn 	} else
30927bd4146SNathan Whitehorn 		cache = NULL;
31027bd4146SNathan Whitehorn 
31127bd4146SNathan Whitehorn 	/*
31227bd4146SNathan Whitehorn 	 * From the SVR4 PPC ABI:
31327bd4146SNathan Whitehorn 	 * "The PowerPC family uses only the Elf32_Rela relocation
31427bd4146SNathan Whitehorn 	 *  entries with explicit addends."
31527bd4146SNathan Whitehorn 	 */
31627bd4146SNathan Whitehorn 	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
31727bd4146SNathan Whitehorn 	for (rela = obj->rela; rela < relalim; rela++) {
318082f959aSKonstantin Belousov 		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
319082f959aSKonstantin Belousov 		    lockstate) < 0)
32027bd4146SNathan Whitehorn 			goto done;
32127bd4146SNathan Whitehorn 	}
32227bd4146SNathan Whitehorn 	r = 0;
32327bd4146SNathan Whitehorn done:
3244b51c699SNathan Whitehorn 	if (cache)
32527bd4146SNathan Whitehorn 		munmap(cache, bytes);
3264b51c699SNathan Whitehorn 
3274b51c699SNathan Whitehorn 	/* Synchronize icache for text seg in case we made any changes */
3284b51c699SNathan Whitehorn 	__syncicache(obj->mapbase, obj->textsize);
3294b51c699SNathan Whitehorn 
33027bd4146SNathan Whitehorn 	return (r);
33127bd4146SNathan Whitehorn }
33227bd4146SNathan Whitehorn 
33327bd4146SNathan Whitehorn 
33427bd4146SNathan Whitehorn /*
33527bd4146SNathan Whitehorn  * Initialise a PLT slot to the resolving trampoline
33627bd4146SNathan Whitehorn  */
33727bd4146SNathan Whitehorn static int
33827bd4146SNathan Whitehorn reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
33927bd4146SNathan Whitehorn {
34027bd4146SNathan Whitehorn 	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
34127bd4146SNathan Whitehorn 	long reloff;
34227bd4146SNathan Whitehorn 
34327bd4146SNathan Whitehorn 	reloff = rela - obj->pltrela;
34427bd4146SNathan Whitehorn 
345a4c5dfc0SNathan Whitehorn 	dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where,
346a4c5dfc0SNathan Whitehorn 	    reloff, obj->glink);
347a4c5dfc0SNathan Whitehorn 
34829ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
349a4c5dfc0SNathan Whitehorn 	/* Glink code is 3 instructions after the first 32k, 2 before */
350a4c5dfc0SNathan Whitehorn 	*where = (Elf_Addr)obj->glink + 32 +
351a4c5dfc0SNathan Whitehorn 	    8*((reloff < 0x8000) ? reloff : 0x8000) +
352a4c5dfc0SNathan Whitehorn 	    12*((reloff < 0x8000) ? 0 : (reloff - 0x8000));
35329ba9b61SNathan Whitehorn #else
35429ba9b61SNathan Whitehorn 	*where = (Elf_Addr)obj->glink + 4*reloff + 32;
35529ba9b61SNathan Whitehorn #endif
35627bd4146SNathan Whitehorn 
35727bd4146SNathan Whitehorn 	return (0);
35827bd4146SNathan Whitehorn }
35927bd4146SNathan Whitehorn 
36027bd4146SNathan Whitehorn 
36127bd4146SNathan Whitehorn /*
36227bd4146SNathan Whitehorn  * Process the PLT relocations.
36327bd4146SNathan Whitehorn  */
36427bd4146SNathan Whitehorn int
36527bd4146SNathan Whitehorn reloc_plt(Obj_Entry *obj)
36627bd4146SNathan Whitehorn {
36727bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
36827bd4146SNathan Whitehorn 	const Elf_Rela *rela;
36927bd4146SNathan Whitehorn 
37027bd4146SNathan Whitehorn 	if (obj->pltrelasize != 0) {
37127bd4146SNathan Whitehorn 		relalim = (const Elf_Rela *)((char *)obj->pltrela +
37227bd4146SNathan Whitehorn 		    obj->pltrelasize);
37327bd4146SNathan Whitehorn 		for (rela = obj->pltrela;  rela < relalim;  rela++) {
37427bd4146SNathan Whitehorn 			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
37527bd4146SNathan Whitehorn 
37627bd4146SNathan Whitehorn 			if (reloc_plt_object(obj, rela) < 0) {
37727bd4146SNathan Whitehorn 				return (-1);
37827bd4146SNathan Whitehorn 			}
37927bd4146SNathan Whitehorn 		}
38027bd4146SNathan Whitehorn 	}
38127bd4146SNathan Whitehorn 
38227bd4146SNathan Whitehorn 	return (0);
38327bd4146SNathan Whitehorn }
38427bd4146SNathan Whitehorn 
38527bd4146SNathan Whitehorn 
38627bd4146SNathan Whitehorn /*
38727bd4146SNathan Whitehorn  * LD_BIND_NOW was set - force relocation for all jump slots
38827bd4146SNathan Whitehorn  */
38927bd4146SNathan Whitehorn int
390082f959aSKonstantin Belousov reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
39127bd4146SNathan Whitehorn {
39227bd4146SNathan Whitehorn 	const Obj_Entry *defobj;
39327bd4146SNathan Whitehorn 	const Elf_Rela *relalim;
39427bd4146SNathan Whitehorn 	const Elf_Rela *rela;
39527bd4146SNathan Whitehorn 	const Elf_Sym *def;
39627bd4146SNathan Whitehorn 	Elf_Addr *where;
39727bd4146SNathan Whitehorn 	Elf_Addr target;
39827bd4146SNathan Whitehorn 
39927bd4146SNathan Whitehorn 	relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
40027bd4146SNathan Whitehorn 	for (rela = obj->pltrela; rela < relalim; rela++) {
40127bd4146SNathan Whitehorn 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
40227bd4146SNathan Whitehorn 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
40327bd4146SNathan Whitehorn 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
404082f959aSKonstantin Belousov 		    SYMLOOK_IN_PLT | flags, NULL, lockstate);
40527bd4146SNathan Whitehorn 		if (def == NULL) {
40627bd4146SNathan Whitehorn 			dbg("reloc_jmpslots: sym not found");
40727bd4146SNathan Whitehorn 			return (-1);
40827bd4146SNathan Whitehorn 		}
40927bd4146SNathan Whitehorn 
41027bd4146SNathan Whitehorn 		target = (Elf_Addr)(defobj->relocbase + def->st_value);
41127bd4146SNathan Whitehorn 
412d48dde6fSNathan Whitehorn 		if (def == &sym_zero) {
413d48dde6fSNathan Whitehorn 			/* Zero undefined weak symbols */
41429ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
415d48dde6fSNathan Whitehorn 			bzero(where, sizeof(struct funcdesc));
41629ba9b61SNathan Whitehorn #else
41729ba9b61SNathan Whitehorn 			*where = 0;
41829ba9b61SNathan Whitehorn #endif
419d48dde6fSNathan Whitehorn 		} else {
42027bd4146SNathan Whitehorn 			reloc_jmpslot(where, target, defobj, obj,
42127bd4146SNathan Whitehorn 			    (const Elf_Rel *) rela);
42227bd4146SNathan Whitehorn 		}
423d48dde6fSNathan Whitehorn 	}
42427bd4146SNathan Whitehorn 
42527bd4146SNathan Whitehorn 	obj->jmpslots_done = true;
42627bd4146SNathan Whitehorn 
42727bd4146SNathan Whitehorn 	return (0);
42827bd4146SNathan Whitehorn }
42927bd4146SNathan Whitehorn 
43027bd4146SNathan Whitehorn 
43127bd4146SNathan Whitehorn /*
43227bd4146SNathan Whitehorn  * Update the value of a PLT jump slot.
43327bd4146SNathan Whitehorn  */
43427bd4146SNathan Whitehorn Elf_Addr
43527bd4146SNathan Whitehorn reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
43627bd4146SNathan Whitehorn 	      const Obj_Entry *obj, const Elf_Rel *rel)
43727bd4146SNathan Whitehorn {
43827bd4146SNathan Whitehorn 
43927bd4146SNathan Whitehorn 	/*
44027bd4146SNathan Whitehorn 	 * At the PLT entry pointed at by `wherep', construct
44127bd4146SNathan Whitehorn 	 * a direct transfer to the now fully resolved function
44227bd4146SNathan Whitehorn 	 * address.
44327bd4146SNathan Whitehorn 	 */
44427bd4146SNathan Whitehorn 
44529ba9b61SNathan Whitehorn #if !defined(_CALL_ELF) || _CALL_ELF == 1
44629ba9b61SNathan Whitehorn 	dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)",
44729ba9b61SNathan Whitehorn 	    (void *)wherep, (void *)target, *(Elf_Addr *)target,
44829ba9b61SNathan Whitehorn 	    (Elf_Addr)defobj->relocbase);
44929ba9b61SNathan Whitehorn 
450a4c5dfc0SNathan Whitehorn 	/*
451a4c5dfc0SNathan Whitehorn 	 * For the trampoline, the second two elements of the function
452a4c5dfc0SNathan Whitehorn 	 * descriptor are unused, so we are fine replacing those at any time
453a4c5dfc0SNathan Whitehorn 	 * with the real ones with no thread safety implications. However, we
454a4c5dfc0SNathan Whitehorn 	 * need to make sure the main entry point pointer ([0]) is seen to be
455a4c5dfc0SNathan Whitehorn 	 * modified *after* the second two elements. This can't be done in
456a4c5dfc0SNathan Whitehorn 	 * general, since there are no barriers in the reading code, but put in
457a4c5dfc0SNathan Whitehorn 	 * some isyncs to at least make it a little better.
458a4c5dfc0SNathan Whitehorn 	 */
45927bd4146SNathan Whitehorn 	memcpy(wherep, (void *)target, sizeof(struct funcdesc));
460a4c5dfc0SNathan Whitehorn 	wherep[2] = ((Elf_Addr *)target)[2];
461a4c5dfc0SNathan Whitehorn 	wherep[1] = ((Elf_Addr *)target)[1];
462a4c5dfc0SNathan Whitehorn 	__asm __volatile ("isync" : : : "memory");
463a4c5dfc0SNathan Whitehorn 	wherep[0] = ((Elf_Addr *)target)[0];
464a4c5dfc0SNathan Whitehorn 	__asm __volatile ("isync" : : : "memory");
465a4c5dfc0SNathan Whitehorn 
46627bd4146SNathan Whitehorn 	if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) {
46727bd4146SNathan Whitehorn 		/*
468a4c5dfc0SNathan Whitehorn 		 * It is possible (LD_BIND_NOW) that the function
46927bd4146SNathan Whitehorn 		 * descriptor we are copying has not yet been relocated.
470a4c5dfc0SNathan Whitehorn 		 * If this happens, fix it. Don't worry about threading in
471a4c5dfc0SNathan Whitehorn 		 * this case since LD_BIND_NOW makes it irrelevant.
47227bd4146SNathan Whitehorn 		 */
47327bd4146SNathan Whitehorn 
47427bd4146SNathan Whitehorn 		((struct funcdesc *)(wherep))->addr +=
47527bd4146SNathan Whitehorn 		    (Elf_Addr)defobj->relocbase;
47627bd4146SNathan Whitehorn 		((struct funcdesc *)(wherep))->toc +=
47727bd4146SNathan Whitehorn 		    (Elf_Addr)defobj->relocbase;
47827bd4146SNathan Whitehorn 	}
47929ba9b61SNathan Whitehorn #else
48029ba9b61SNathan Whitehorn 	dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep,
48129ba9b61SNathan Whitehorn 	    (void *)target);
48227bd4146SNathan Whitehorn 
48329ba9b61SNathan Whitehorn 	*wherep = target;
48429ba9b61SNathan Whitehorn #endif
48529ba9b61SNathan Whitehorn 
48627bd4146SNathan Whitehorn 	return (target);
48727bd4146SNathan Whitehorn }
48827bd4146SNathan Whitehorn 
4896be4b697SKonstantin Belousov int
4906be4b697SKonstantin Belousov reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate)
4916be4b697SKonstantin Belousov {
4926be4b697SKonstantin Belousov 
4936be4b697SKonstantin Belousov 	/* XXX not implemented */
4946be4b697SKonstantin Belousov 	return (0);
4956be4b697SKonstantin Belousov }
4966be4b697SKonstantin Belousov 
4976be4b697SKonstantin Belousov int
498082f959aSKonstantin Belousov reloc_gnu_ifunc(Obj_Entry *obj, int flags,
499082f959aSKonstantin Belousov     struct Struct_RtldLockState *lockstate)
5006be4b697SKonstantin Belousov {
5016be4b697SKonstantin Belousov 
5026be4b697SKonstantin Belousov 	/* XXX not implemented */
5036be4b697SKonstantin Belousov 	return (0);
5046be4b697SKonstantin Belousov }
5056be4b697SKonstantin Belousov 
50627bd4146SNathan Whitehorn void
50727bd4146SNathan Whitehorn init_pltgot(Obj_Entry *obj)
50827bd4146SNathan Whitehorn {
50929ba9b61SNathan Whitehorn 	Elf_Addr *pltcall;
51029ba9b61SNathan Whitehorn 
51129ba9b61SNathan Whitehorn 	pltcall = obj->pltgot;
51229ba9b61SNathan Whitehorn 
51329ba9b61SNathan Whitehorn 	if (pltcall == NULL) {
51429ba9b61SNathan Whitehorn 		return;
51529ba9b61SNathan Whitehorn 	}
51629ba9b61SNathan Whitehorn 
517a4c5dfc0SNathan Whitehorn #if defined(_CALL_ELF) && _CALL_ELF == 2
51829ba9b61SNathan Whitehorn 	pltcall[0] = (Elf_Addr)&_rtld_bind_start;
51929ba9b61SNathan Whitehorn 	pltcall[1] = (Elf_Addr)obj;
520a4c5dfc0SNathan Whitehorn #else
521a4c5dfc0SNathan Whitehorn 	memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc));
522a4c5dfc0SNathan Whitehorn 	pltcall[2] = (Elf_Addr)obj;
52329ba9b61SNathan Whitehorn #endif
52427bd4146SNathan Whitehorn }
52527bd4146SNathan Whitehorn 
52627bd4146SNathan Whitehorn void
52727bd4146SNathan Whitehorn allocate_initial_tls(Obj_Entry *list)
52827bd4146SNathan Whitehorn {
529746ae9dfSNathan Whitehorn 	Elf_Addr **tp;
53027bd4146SNathan Whitehorn 
53127bd4146SNathan Whitehorn 	/*
53227bd4146SNathan Whitehorn 	* Fix the size of the static TLS block by using the maximum
53327bd4146SNathan Whitehorn 	* offset allocated so far and adding a bit for dynamic modules to
53427bd4146SNathan Whitehorn 	* use.
53527bd4146SNathan Whitehorn 	*/
53627bd4146SNathan Whitehorn 
53727bd4146SNathan Whitehorn 	tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA;
53827bd4146SNathan Whitehorn 
539746ae9dfSNathan Whitehorn 	tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16)
54027bd4146SNathan Whitehorn 	    + TLS_TP_OFFSET + TLS_TCB_SIZE);
54127bd4146SNathan Whitehorn 
542746ae9dfSNathan Whitehorn 	__asm __volatile("mr 13,%0" :: "r"(tp));
54327bd4146SNathan Whitehorn }
54427bd4146SNathan Whitehorn 
54527bd4146SNathan Whitehorn void*
54627bd4146SNathan Whitehorn __tls_get_addr(tls_index* ti)
54727bd4146SNathan Whitehorn {
548746ae9dfSNathan Whitehorn 	Elf_Addr **tp;
54927bd4146SNathan Whitehorn 	char *p;
55027bd4146SNathan Whitehorn 
551746ae9dfSNathan Whitehorn 	__asm __volatile("mr %0,13" : "=r"(tp));
55227bd4146SNathan Whitehorn 	p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET
55327bd4146SNathan Whitehorn 	    - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset);
55427bd4146SNathan Whitehorn 
55527bd4146SNathan Whitehorn 	return (p + TLS_DTV_OFFSET);
55627bd4146SNathan Whitehorn }
557