reloc.c revision 115396
1107572Sgrehan/*      $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $   */
2107572Sgrehan
3107572Sgrehan/*-
4107572Sgrehan * Copyright (C) 1998   Tsubai Masanari
5107572Sgrehan * All rights reserved.
6107572Sgrehan *
7107572Sgrehan * Redistribution and use in source and binary forms, with or without
8107572Sgrehan * modification, are permitted provided that the following conditions
9107572Sgrehan * are met:
10107572Sgrehan * 1. Redistributions of source code must retain the above copyright
11107572Sgrehan *    notice, this list of conditions and the following disclaimer.
12107572Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
13107572Sgrehan *    notice, this list of conditions and the following disclaimer in the
14107572Sgrehan *    documentation and/or other materials provided with the distribution.
15107572Sgrehan * 3. The name of the author may not be used to endorse or promote products
16107572Sgrehan *    derived from this software without specific prior written permission.
17107572Sgrehan *
18107572Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19107572Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20107572Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21107572Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22107572Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23107572Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24107572Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25107572Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26107572Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27107572Sgrehan * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28107572Sgrehan *
29107572Sgrehan * $FreeBSD: head/libexec/rtld-elf/powerpc/reloc.c 115396 2003-05-29 22:58:26Z kan $
30107572Sgrehan */
31107572Sgrehan
32107572Sgrehan#include <sys/param.h>
33107572Sgrehan#include <sys/mman.h>
34107572Sgrehan
35107572Sgrehan#include <errno.h>
36107572Sgrehan#include <stdio.h>
37107572Sgrehan#include <stdlib.h>
38107572Sgrehan#include <string.h>
39107572Sgrehan#include <unistd.h>
40107572Sgrehan#include <machine/cpu.h>
41107572Sgrehan
42107572Sgrehan#include "debug.h"
43107572Sgrehan#include "rtld.h"
44107572Sgrehan
45107572Sgrehan#define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \
46107572Sgrehan                        ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
47107572Sgrehan#define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
48107572Sgrehan
49107572Sgrehan/*
50107572Sgrehan * Process the R_PPC_COPY relocations
51107572Sgrehan */
52107572Sgrehanint
53107572Sgrehando_copy_relocations(Obj_Entry *dstobj)
54107572Sgrehan{
55107572Sgrehan	const Elf_Rela *relalim;
56107572Sgrehan	const Elf_Rela *rela;
57107572Sgrehan
58115396Skan	/*
59107572Sgrehan	 * COPY relocs are invalid outside of the main program
60107572Sgrehan	 */
61115396Skan	assert(dstobj->mainprog);
62107572Sgrehan
63115396Skan	relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela +
64107572Sgrehan	    dstobj->relasize);
65107572Sgrehan	for (rela = dstobj->rela;  rela < relalim;  rela++) {
66107572Sgrehan		void *dstaddr;
67107572Sgrehan		const Elf_Sym *dstsym;
68107572Sgrehan		const char *name;
69107572Sgrehan		unsigned long hash;
70107572Sgrehan		size_t size;
71107572Sgrehan		const void *srcaddr;
72107572Sgrehan		const Elf_Sym *srcsym = NULL;
73107572Sgrehan		Obj_Entry *srcobj;
74107572Sgrehan
75107572Sgrehan		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
76107572Sgrehan			continue;
77107572Sgrehan		}
78107572Sgrehan
79107572Sgrehan		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
80107572Sgrehan		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
81107572Sgrehan		name = dstobj->strtab + dstsym->st_name;
82107572Sgrehan		hash = elf_hash(name);
83107572Sgrehan		size = dstsym->st_size;
84115396Skan
85115396Skan		for (srcobj = dstobj->next;  srcobj != NULL;
86107572Sgrehan		     srcobj = srcobj->next) {
87107572Sgrehan			if ((srcsym = symlook_obj(name, hash, srcobj, false))
88107572Sgrehan			    != NULL) {
89107572Sgrehan				break;
90107572Sgrehan			}
91107572Sgrehan		}
92107572Sgrehan
93107572Sgrehan		if (srcobj == NULL) {
94107572Sgrehan			_rtld_error("Undefined symbol \"%s\" "
95107572Sgrehan				    " referenced from COPY"
96107572Sgrehan				    " relocation in %s", name, dstobj->path);
97107572Sgrehan			return (-1);
98107572Sgrehan		}
99115396Skan
100107572Sgrehan		srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
101115396Skan		memcpy(dstaddr, srcaddr, size);
102107572Sgrehan		dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
103107572Sgrehan	}
104115396Skan
105107572Sgrehan	return (0);
106107572Sgrehan}
107107572Sgrehan
108107572Sgrehan
109107572Sgrehan/*
110107572Sgrehan * Perform early relocation of the run-time linker image
111107572Sgrehan */
112107572Sgrehanvoid
113107572Sgrehanreloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
114107572Sgrehan{
115107572Sgrehan	const Elf_Rela *rela = 0, *relalim;
116107572Sgrehan	Elf_Addr relasz = 0;
117107572Sgrehan	Elf_Addr *where;
118107572Sgrehan
119107572Sgrehan	/*
120107572Sgrehan	 * Extract the rela/relasz values from the dynamic section
121107572Sgrehan	 */
122107572Sgrehan	for (; dynp->d_tag != DT_NULL; dynp++) {
123107572Sgrehan		switch (dynp->d_tag) {
124107572Sgrehan		case DT_RELA:
125107572Sgrehan			rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
126107572Sgrehan			break;
127107572Sgrehan		case DT_RELASZ:
128107572Sgrehan			relasz = dynp->d_un.d_val;
129107572Sgrehan			break;
130107572Sgrehan		}
131107572Sgrehan	}
132107572Sgrehan
133107572Sgrehan	/*
134115396Skan	 * Relocate these values
135107572Sgrehan	 */
136107572Sgrehan	relalim = (const Elf_Rela *)((caddr_t)rela + relasz);
137107572Sgrehan	for (; rela < relalim; rela++) {
138107572Sgrehan		where = (Elf_Addr *)(relocbase + rela->r_offset);
139107572Sgrehan		*where = (Elf_Addr)(relocbase + rela->r_addend);
140107572Sgrehan	}
141107572Sgrehan}
142107572Sgrehan
143107572Sgrehan
144107572Sgrehan/*
145115396Skan * Relocate a non-PLT object with addend.
146107572Sgrehan */
147107572Sgrehanstatic int
148107572Sgrehanreloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
149107572Sgrehan		    SymCache *cache)
150107572Sgrehan{
151107572Sgrehan	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
152107572Sgrehan	const Elf_Sym   *def;
153107572Sgrehan	const Obj_Entry *defobj;
154107572Sgrehan	Elf_Addr         tmp;
155107572Sgrehan
156107572Sgrehan	switch (ELF_R_TYPE(rela->r_info)) {
157115396Skan
158107572Sgrehan	case R_PPC_NONE:
159107572Sgrehan		break;
160107572Sgrehan
161107572Sgrehan        case R_PPC_ADDR32:    /* word32 S + A */
162107572Sgrehan        case R_PPC_GLOB_DAT:  /* word32 S + A */
163107572Sgrehan		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
164107572Sgrehan				  false, cache);
165107572Sgrehan		if (def == NULL) {
166107572Sgrehan			return (-1);
167107572Sgrehan		}
168107572Sgrehan
169107572Sgrehan                tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
170107572Sgrehan                    rela->r_addend);
171107572Sgrehan
172107572Sgrehan		/* Don't issue write if unnecessary; avoid COW page fault */
173107572Sgrehan                if (*where != tmp) {
174107572Sgrehan                        *where = tmp;
175107572Sgrehan		}
176107572Sgrehan                break;
177107572Sgrehan
178107572Sgrehan        case R_PPC_RELATIVE:  /* word32 B + A */
179107572Sgrehan		tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
180115396Skan
181107572Sgrehan		/* As above, don't issue write unnecessarily */
182107572Sgrehan		if (*where != tmp) {
183107572Sgrehan			*where = tmp;
184107572Sgrehan		}
185107572Sgrehan		break;
186107572Sgrehan
187107572Sgrehan	case R_PPC_COPY:
188107572Sgrehan		/*
189107572Sgrehan		 * These are deferred until all other relocations
190107572Sgrehan		 * have been done.  All we do here is make sure
191107572Sgrehan		 * that the COPY relocation is not in a shared
192107572Sgrehan		 * library.  They are allowed only in executable
193107572Sgrehan		 * files.
194107572Sgrehan		 */
195107572Sgrehan		if (!obj->mainprog) {
196107572Sgrehan			_rtld_error("%s: Unexpected R_COPY "
197107572Sgrehan				    " relocation in shared library",
198107572Sgrehan				    obj->path);
199107572Sgrehan			return (-1);
200115396Skan		}
201107572Sgrehan		break;
202107572Sgrehan
203107572Sgrehan	case R_PPC_JMP_SLOT:
204107572Sgrehan		/*
205107572Sgrehan		 * These will be handled by the plt/jmpslot routines
206107572Sgrehan		 */
207107572Sgrehan		break;
208107572Sgrehan
209107572Sgrehan	default:
210107572Sgrehan		_rtld_error("%s: Unsupported relocation type %d"
211107572Sgrehan			    " in non-PLT relocations\n", obj->path,
212115396Skan			    ELF_R_TYPE(rela->r_info));
213107572Sgrehan		return (-1);
214107572Sgrehan        }
215115396Skan	return (0);
216107572Sgrehan}
217107572Sgrehan
218107572Sgrehan
219107572Sgrehan/*
220107572Sgrehan * Process non-PLT relocations
221107572Sgrehan */
222107572Sgrehanint
223107572Sgrehanreloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
224107572Sgrehan{
225107572Sgrehan	const Elf_Rela *relalim;
226107572Sgrehan	const Elf_Rela *rela;
227107572Sgrehan	SymCache *cache;
228107572Sgrehan	int bytes = obj->nchains * sizeof(SymCache);
229107572Sgrehan	int r = -1;
230107572Sgrehan
231107572Sgrehan	/*
232107572Sgrehan	 * The dynamic loader may be called from a thread, we have
233107572Sgrehan	 * limited amounts of stack available so we cannot use alloca().
234107572Sgrehan	 */
235107572Sgrehan	cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
236112242Skan	if (cache == MAP_FAILED)
237107572Sgrehan		cache = NULL;
238107572Sgrehan
239107572Sgrehan	/*
240107572Sgrehan	 * From the SVR4 PPC ABI:
241115396Skan	 * "The PowerPC family uses only the Elf32_Rela relocation
242107572Sgrehan	 *  entries with explicit addends."
243107572Sgrehan	 */
244107572Sgrehan	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
245107572Sgrehan	for (rela = obj->rela; rela < relalim; rela++) {
246107572Sgrehan		if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
247107572Sgrehan			goto done;
248107572Sgrehan	}
249107572Sgrehan	r = 0;
250107572Sgrehandone:
251107572Sgrehan	if (cache) {
252107572Sgrehan		munmap(cache, bytes);
253107572Sgrehan	}
254107572Sgrehan	return (r);
255107572Sgrehan}
256107572Sgrehan
257107572Sgrehan
258107572Sgrehan/*
259107572Sgrehan * Initialise a PLT slot to the resolving trampoline
260107572Sgrehan */
261107572Sgrehanstatic int
262107572Sgrehanreloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
263107572Sgrehan{
264107572Sgrehan	Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
265107572Sgrehan	Elf_Addr *pltresolve;
266107572Sgrehan	Elf_Addr distance;
267107572Sgrehan	int reloff;
268107572Sgrehan
269107572Sgrehan	reloff = rela - obj->pltrela;
270107572Sgrehan
271107572Sgrehan	if ((reloff < 0) || (reloff >= 0x8000)) {
272107572Sgrehan		return (-1);
273107572Sgrehan	}
274107572Sgrehan
275107572Sgrehan	pltresolve = obj->pltgot + 8;
276107572Sgrehan
277107572Sgrehan	distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
278107572Sgrehan
279115396Skan	dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
280107572Sgrehan	    (void *)where, (void *)pltresolve, reloff, distance);
281107572Sgrehan
282107572Sgrehan	/* li   r11,reloff  */
283107572Sgrehan	/* b    pltresolve  */
284107572Sgrehan	where[0] = 0x39600000 | reloff;
285107572Sgrehan	where[1] = 0x48000000 | (distance & 0x03fffffc);
286107572Sgrehan
287107572Sgrehan	/*
288107572Sgrehan	 * The icache will be sync'd in init_pltgot, which is called
289107572Sgrehan	 * after all the slots have been updated
290107572Sgrehan	 */
291107572Sgrehan
292107572Sgrehan	return (0);
293107572Sgrehan}
294107572Sgrehan
295107572Sgrehan
296107572Sgrehan/*
297107572Sgrehan * Process the PLT relocations.
298107572Sgrehan */
299107572Sgrehanint
300107572Sgrehanreloc_plt(Obj_Entry *obj)
301107572Sgrehan{
302107572Sgrehan	const Elf_Rela *relalim;
303107572Sgrehan	const Elf_Rela *rela;
304107572Sgrehan
305107572Sgrehan	if (obj->pltrelasize != 0) {
306107572Sgrehan
307115396Skan		relalim = (const Elf_Rela *)((char *)obj->pltrela +
308107572Sgrehan		    obj->pltrelasize);
309107572Sgrehan		for (rela = obj->pltrela;  rela < relalim;  rela++) {
310107572Sgrehan			assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
311107572Sgrehan
312107572Sgrehan			if (reloc_plt_object(obj, rela) < 0) {
313107572Sgrehan				return (-1);
314107572Sgrehan			}
315107572Sgrehan		}
316107572Sgrehan	}
317107572Sgrehan
318107572Sgrehan	return (0);
319107572Sgrehan}
320107572Sgrehan
321107572Sgrehan
322107572Sgrehan/*
323107572Sgrehan * LD_BIND_NOW was set - force relocation for all jump slots
324107572Sgrehan */
325107572Sgrehanint
326107572Sgrehanreloc_jmpslots(Obj_Entry *obj)
327107572Sgrehan{
328107572Sgrehan	const Obj_Entry *defobj;
329107572Sgrehan	const Elf_Rela *relalim;
330107572Sgrehan	const Elf_Rela *rela;
331107572Sgrehan	const Elf_Sym *def;
332107572Sgrehan	Elf_Addr *where;
333107572Sgrehan	Elf_Addr target;
334107572Sgrehan
335107572Sgrehan	relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize);
336107572Sgrehan	for (rela = obj->pltrela; rela < relalim; rela++) {
337107572Sgrehan		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
338107572Sgrehan		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
339107572Sgrehan		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
340107572Sgrehan		   true, NULL);
341107572Sgrehan		if (def == NULL) {
342107572Sgrehan			dbg("reloc_jmpslots: sym not found");
343107572Sgrehan			return (-1);
344107572Sgrehan		}
345107572Sgrehan
346107572Sgrehan		target = (Elf_Addr)(defobj->relocbase + def->st_value);
347107572Sgrehan
348107572Sgrehan#if 0
349107572Sgrehan		/* PG XXX */
350107572Sgrehan		dbg("\"%s\" in \"%s\" --> %p in \"%s\"",
351107572Sgrehan		    defobj->strtab + def->st_name, basename(obj->path),
352107572Sgrehan		    (void *)target, basename(defobj->path));
353107572Sgrehan#endif
354107572Sgrehan
355115396Skan		reloc_jmpslot(where, target, defobj, obj,
356107572Sgrehan		    (const Elf_Rel *) rela);
357107572Sgrehan	}
358107572Sgrehan
359107572Sgrehan	obj->jmpslots_done = true;
360107572Sgrehan
361107572Sgrehan	return (0);
362107572Sgrehan}
363107572Sgrehan
364107572Sgrehan
365107572Sgrehan/*
366107572Sgrehan * Update the value of a PLT jump slot. Branch directly to the target if
367107572Sgrehan * it is within +/- 32Mb, otherwise go indirectly via the pltcall
368107572Sgrehan * trampoline call and jump table.
369107572Sgrehan */
370107572SgrehanElf_Addr
371107572Sgrehanreloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj,
372107572Sgrehan	      const Obj_Entry *obj, const Elf_Rel *rel)
373107572Sgrehan{
374107572Sgrehan	Elf_Addr offset;
375107572Sgrehan	const Elf_Rela *rela = (const Elf_Rela *) rel;
376107572Sgrehan
377115396Skan	dbg(" reloc_jmpslot: where=%p, target=%p",
378107572Sgrehan	    (void *)wherep, (void *)target);
379107572Sgrehan
380107572Sgrehan	/*
381107572Sgrehan	 * At the PLT entry pointed at by `wherep', construct
382107572Sgrehan	 * a direct transfer to the now fully resolved function
383107572Sgrehan	 * address.
384107572Sgrehan	 */
385107572Sgrehan	offset = target - (Elf_Addr)wherep;
386107572Sgrehan
387107572Sgrehan	if (abs(offset) < 32*1024*1024) {     /* inside 32MB? */
388107572Sgrehan		/* b    value   # branch directly */
389107572Sgrehan		*wherep = 0x48000000 | (offset & 0x03fffffc);
390107572Sgrehan		__syncicache(wherep, 4);
391107572Sgrehan	} else {
392107572Sgrehan		Elf_Addr *pltcall, *jmptab;
393107572Sgrehan		int distance;
394107572Sgrehan		int N = obj->pltrelasize / sizeof(Elf_Rela);
395107572Sgrehan		int reloff = rela - obj->pltrela;
396107572Sgrehan
397107572Sgrehan		if ((reloff < 0) || (reloff >= 0x8000)) {
398107572Sgrehan			return (-1);
399107572Sgrehan		}
400107572Sgrehan
401107572Sgrehan		pltcall = obj->pltgot;
402107572Sgrehan
403107572Sgrehan		dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n",
404107572Sgrehan		    reloff, N);
405107572Sgrehan
406107572Sgrehan		jmptab = obj->pltgot + 18 + N * 2;
407107572Sgrehan		jmptab[reloff] = target;
408107572Sgrehan
409107572Sgrehan		distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
410107572Sgrehan
411107572Sgrehan		/* li   r11,reloff */
412107572Sgrehan		/* b    pltcall  # use indirect pltcall routine */
413107572Sgrehan		wherep[0] = 0x39600000 | reloff;
414107572Sgrehan		wherep[1] = 0x48000000 | (distance & 0x03fffffc);
415107572Sgrehan		__syncicache(wherep, 8);
416107572Sgrehan	}
417107572Sgrehan
418107572Sgrehan	return (target);
419107572Sgrehan}
420107572Sgrehan
421107572Sgrehan
422107572Sgrehan/*
423107572Sgrehan * Setup the plt glue routines.
424107572Sgrehan */
425107572Sgrehan#define PLTCALL_SIZE    20
426107572Sgrehan#define PLTRESOLVE_SIZE 24
427107572Sgrehan
428107572Sgrehanvoid
429107572Sgrehaninit_pltgot(Obj_Entry *obj)
430107572Sgrehan{
431107572Sgrehan	Elf_Word *pltcall, *pltresolve;
432107572Sgrehan	Elf_Word *jmptab;
433107572Sgrehan	int N = obj->pltrelasize / sizeof(Elf_Rela);
434107572Sgrehan
435107572Sgrehan	pltcall = obj->pltgot;
436107572Sgrehan
437107572Sgrehan	if (pltcall == NULL) {
438107572Sgrehan		return;
439107572Sgrehan	}
440107572Sgrehan
441107572Sgrehan	/*
442107572Sgrehan	 * From the SVR4 PPC ABI:
443107572Sgrehan	 *
444107572Sgrehan	 * 'The first 18 words (72 bytes) of the PLT are reserved for
445107572Sgrehan	 * use by the dynamic linker.
446107572Sgrehan	 *   ...
447115396Skan	 * 'If the executable or shared object requires N procedure
448115396Skan	 *  linkage table entries, the link editor shall reserve 3*N
449115396Skan	 *  words (12*N bytes) following the 18 reserved words. The
450115396Skan	 *  first 2*N of these words are the procedure linkage table
451115396Skan	 *  entries themselves. The static linker directs calls to bytes
452115396Skan	 *  (72 + (i-1)*8), for i between 1 and N inclusive. The remaining
453107572Sgrehan	 *  N words (4*N bytes) are reserved for use by the dynamic linker.'
454107572Sgrehan	 */
455107572Sgrehan
456107572Sgrehan	/*
457107572Sgrehan	 * Copy the absolute-call assembler stub into the first part of
458107572Sgrehan	 * the reserved PLT area.
459107572Sgrehan	 */
460107572Sgrehan	memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
461107572Sgrehan
462107572Sgrehan	/*
463107572Sgrehan	 * Determine the address of the jumptable, which is the dyn-linker
464107572Sgrehan	 * reserved area after the call cells. Write the absolute address
465107572Sgrehan	 * of the jumptable into the absolute-call assembler code so it
466107572Sgrehan	 * can determine this address.
467107572Sgrehan	 */
468107572Sgrehan	jmptab = pltcall + 18 + N * 2;
469107572Sgrehan	pltcall[1] |= _ppc_ha(jmptab);	   /* addis 11,11,jmptab@ha */
470107572Sgrehan	pltcall[2] |= _ppc_la(jmptab);     /* lwz   11,jmptab@l(11) */
471107572Sgrehan
472107572Sgrehan	/*
473107572Sgrehan	 * Skip down 32 bytes into the initial reserved area and copy
474107572Sgrehan	 * in the standard resolving assembler call. Into this assembler,
475107572Sgrehan	 * insert the absolute address of the _rtld_bind_start routine
476107572Sgrehan	 * and the address of the relocation object.
477107572Sgrehan	 */
478107572Sgrehan	pltresolve = obj->pltgot + 8;
479107572Sgrehan
480107572Sgrehan	memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
481107572Sgrehan	pltresolve[0] |= _ppc_ha(_rtld_bind_start);
482107572Sgrehan	pltresolve[1] |= _ppc_la(_rtld_bind_start);
483107572Sgrehan	pltresolve[3] |= _ppc_ha(obj);
484107572Sgrehan	pltresolve[4] |= _ppc_la(obj);
485107572Sgrehan
486107572Sgrehan	/*
487107572Sgrehan	 * Sync the icache for the byte range represented by the
488107572Sgrehan	 * trampoline routines and call slots.
489107572Sgrehan	 */
490107572Sgrehan	__syncicache(pltcall, 72 + N * 8);
491107572Sgrehan}
492