Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/rtld-elf/powerpc/reloc.c
34923 views
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
35
#include <errno.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
#include <machine/cpu.h>
41
#include <machine/atomic.h>
42
#include <machine/md_var.h>
43
44
#include "debug.h"
45
#include "rtld.h"
46
47
#define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \
48
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
49
#define _ppc_la(x) ((u_int32_t)(x) & 0xffff)
50
51
#define min(a,b) (((a) < (b)) ? (a) : (b))
52
#define max(a,b) (((a) > (b)) ? (a) : (b))
53
54
#define PLT_EXTENDED_BEGIN (1 << 13)
55
#define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \
56
(N - PLT_EXTENDED_BEGIN)*2 : 0))
57
58
void _rtld_bind_secureplt_start(void);
59
60
bool
61
arch_digest_dynamic(struct Struct_Obj_Entry *obj, const Elf_Dyn *dynp)
62
{
63
if (dynp->d_tag == DT_PPC_GOT) {
64
obj->gotptr = (Elf_Addr *)(obj->relocbase + dynp->d_un.d_ptr);
65
return (true);
66
}
67
68
return (false);
69
}
70
71
/*
72
* Process the R_PPC_COPY relocations
73
*/
74
int
75
do_copy_relocations(Obj_Entry *dstobj)
76
{
77
const Elf_Rela *relalim;
78
const Elf_Rela *rela;
79
80
/*
81
* COPY relocs are invalid outside of the main program
82
*/
83
assert(dstobj->mainprog);
84
85
relalim = (const Elf_Rela *)((const char *) dstobj->rela +
86
dstobj->relasize);
87
for (rela = dstobj->rela; rela < relalim; rela++) {
88
void *dstaddr;
89
const Elf_Sym *dstsym;
90
const char *name;
91
size_t size;
92
const void *srcaddr;
93
const Elf_Sym *srcsym = NULL;
94
const Obj_Entry *srcobj, *defobj;
95
SymLook req;
96
int res;
97
98
if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
99
continue;
100
}
101
102
dstaddr = (void *)(dstobj->relocbase + rela->r_offset);
103
dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
104
name = dstobj->strtab + dstsym->st_name;
105
size = dstsym->st_size;
106
symlook_init(&req, name);
107
req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
108
req.flags = SYMLOOK_EARLY;
109
110
for (srcobj = globallist_next(dstobj); srcobj != NULL;
111
srcobj = globallist_next(srcobj)) {
112
res = symlook_obj(&req, srcobj);
113
if (res == 0) {
114
srcsym = req.sym_out;
115
defobj = req.defobj_out;
116
break;
117
}
118
}
119
120
if (srcobj == NULL) {
121
_rtld_error("Undefined symbol \"%s\" "
122
" referenced from COPY"
123
" relocation in %s", name, dstobj->path);
124
return (-1);
125
}
126
127
srcaddr = (const void *)(defobj->relocbase+srcsym->st_value);
128
memcpy(dstaddr, srcaddr, size);
129
dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
130
}
131
132
return (0);
133
}
134
135
136
/*
137
* Perform early relocation of the run-time linker image
138
*/
139
void
140
reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
141
{
142
const Elf_Rela *rela = NULL, *relalim;
143
Elf_Addr relasz = 0;
144
Elf_Addr *where;
145
146
/*
147
* Extract the rela/relasz values from the dynamic section
148
*/
149
for (; dynp->d_tag != DT_NULL; dynp++) {
150
switch (dynp->d_tag) {
151
case DT_RELA:
152
rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr);
153
break;
154
case DT_RELASZ:
155
relasz = dynp->d_un.d_val;
156
break;
157
}
158
}
159
160
/*
161
* Relocate these values
162
*/
163
relalim = (const Elf_Rela *)((const char *)rela + relasz);
164
for (; rela < relalim; rela++) {
165
where = (Elf_Addr *)(relocbase + rela->r_offset);
166
*where = (Elf_Addr)(relocbase + rela->r_addend);
167
}
168
}
169
170
171
/*
172
* Relocate a non-PLT object with addend.
173
*/
174
static int
175
reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj,
176
const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate)
177
{
178
const Elf_Sym *def = NULL;
179
const Obj_Entry *defobj;
180
Elf_Addr *where, symval = 0;
181
182
/*
183
* First, resolve symbol for relocations which
184
* reference symbols.
185
*/
186
switch (ELF_R_TYPE(rela->r_info)) {
187
188
case R_PPC_UADDR32: /* word32 S + A */
189
case R_PPC_ADDR32:
190
case R_PPC_GLOB_DAT: /* word32 S + A */
191
case R_PPC_DTPMOD32:
192
case R_PPC_TPREL32:
193
case R_PPC_DTPREL32:
194
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
195
flags, cache, lockstate);
196
if (def == NULL) {
197
return (-1);
198
}
199
200
/*
201
* If symbol is IFUNC, only perform relocation
202
* when caller allowed it by passing
203
* SYMLOOK_IFUNC flag. Skip the relocations
204
* otherwise.
205
*
206
* Also error out in case IFUNC relocations
207
* are specified for TLS, which cannot be
208
* usefully interpreted.
209
*/
210
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
211
switch (ELF_R_TYPE(rela->r_info)) {
212
case R_PPC_UADDR32:
213
case R_PPC_ADDR32:
214
case R_PPC_GLOB_DAT:
215
if ((flags & SYMLOOK_IFUNC) == 0) {
216
dbg("Non-PLT reference to IFUNC found!");
217
obj->non_plt_gnu_ifunc = true;
218
return (0);
219
}
220
symval = (Elf_Addr)rtld_resolve_ifunc(
221
defobj, def);
222
break;
223
default:
224
_rtld_error("%s: IFUNC for TLS reloc",
225
obj->path);
226
return (-1);
227
}
228
} else {
229
if ((flags & SYMLOOK_IFUNC) != 0)
230
return (0);
231
symval = (Elf_Addr)defobj->relocbase +
232
def->st_value;
233
}
234
break;
235
default:
236
if ((flags & SYMLOOK_IFUNC) != 0)
237
return (0);
238
}
239
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
240
241
switch (ELF_R_TYPE(rela->r_info)) {
242
case R_PPC_NONE:
243
break;
244
case R_PPC_UADDR32:
245
case R_PPC_ADDR32:
246
case R_PPC_GLOB_DAT:
247
/* Don't issue write if unnecessary; avoid COW page fault */
248
if (*where != symval + rela->r_addend) {
249
*where = symval + rela->r_addend;
250
}
251
break;
252
case R_PPC_DTPMOD32:
253
*where = (Elf_Addr) defobj->tlsindex;
254
break;
255
case R_PPC_TPREL32:
256
/*
257
* We lazily allocate offsets for static TLS as we
258
* see the first relocation that references the
259
* TLS block. This allows us to support (small
260
* amounts of) static TLS in dynamically loaded
261
* modules. If we run out of space, we generate an
262
* error.
263
*/
264
if (!defobj->tls_static) {
265
if (!allocate_tls_offset(
266
__DECONST(Obj_Entry *, defobj))) {
267
_rtld_error("%s: No space available for static "
268
"Thread Local Storage", obj->path);
269
return (-1);
270
}
271
}
272
273
*(Elf_Addr **)where = *where * sizeof(Elf_Addr)
274
+ (Elf_Addr *)(def->st_value + rela->r_addend
275
+ defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE);
276
break;
277
case R_PPC_DTPREL32:
278
*where += (Elf_Addr)(def->st_value + rela->r_addend
279
- TLS_DTV_OFFSET);
280
break;
281
case R_PPC_RELATIVE: /* word32 B + A */
282
symval = (Elf_Addr)(obj->relocbase + rela->r_addend);
283
284
/* As above, don't issue write unnecessarily */
285
if (*where != symval) {
286
*where = symval;
287
}
288
break;
289
case R_PPC_COPY:
290
/*
291
* These are deferred until all other relocations
292
* have been done. All we do here is make sure
293
* that the COPY relocation is not in a shared
294
* library. They are allowed only in executable
295
* files.
296
*/
297
if (!obj->mainprog) {
298
_rtld_error("%s: Unexpected R_COPY "
299
" relocation in shared library",
300
obj->path);
301
return (-1);
302
}
303
break;
304
case R_PPC_IRELATIVE:
305
/*
306
* These will be handled by reloc_iresolve().
307
*/
308
obj->irelative = true;
309
break;
310
case R_PPC_JMP_SLOT:
311
/*
312
* These will be handled by the plt/jmpslot routines
313
*/
314
break;
315
316
default:
317
_rtld_error("%s: Unsupported relocation type %d"
318
" in non-PLT relocations\n", obj->path,
319
ELF_R_TYPE(rela->r_info));
320
return (-1);
321
}
322
return (0);
323
}
324
325
326
/*
327
* Process non-PLT relocations
328
*/
329
int
330
reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
331
RtldLockState *lockstate)
332
{
333
const Elf_Rela *relalim;
334
const Elf_Rela *rela;
335
const Elf_Phdr *phdr;
336
SymCache *cache;
337
int r = -1;
338
339
/*
340
* The dynamic loader may be called from a thread, we have
341
* limited amounts of stack available so we cannot use alloca().
342
*/
343
if (obj != obj_rtld) {
344
cache = calloc(obj->dynsymcount, sizeof(SymCache));
345
/* No need to check for NULL here */
346
} else
347
cache = NULL;
348
349
/*
350
* From the SVR4 PPC ABI:
351
* "The PowerPC family uses only the Elf32_Rela relocation
352
* entries with explicit addends."
353
*/
354
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
355
for (rela = obj->rela; rela < relalim; rela++) {
356
if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
357
lockstate) < 0)
358
goto done;
359
}
360
r = 0;
361
done:
362
if (cache != NULL)
363
free(cache);
364
365
/*
366
* Synchronize icache for executable segments in case we made
367
* any changes.
368
*/
369
for (phdr = obj->phdr;
370
(const char *)phdr < (const char *)obj->phdr + obj->phsize;
371
phdr++) {
372
if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) {
373
__syncicache(obj->relocbase + phdr->p_vaddr,
374
phdr->p_memsz);
375
}
376
}
377
378
return (r);
379
}
380
381
/*
382
* Initialise a PLT slot to the resolving trampoline
383
*/
384
static int
385
reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
386
{
387
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
388
Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
389
Elf_Addr distance;
390
int N = obj->pltrelasize / sizeof(Elf_Rela);
391
int reloff;
392
393
reloff = rela - obj->pltrela;
394
395
if (reloff < 0)
396
return (-1);
397
398
if (obj->gotptr != NULL) {
399
*where += (Elf_Addr)obj->relocbase;
400
return (0);
401
}
402
403
pltlongresolve = obj->pltgot + 5;
404
pltresolve = pltlongresolve + 5;
405
406
distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
407
408
dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
409
(void *)where, (void *)pltresolve, reloff, distance);
410
411
if (reloff < PLT_EXTENDED_BEGIN) {
412
/* li r11,reloff */
413
/* b pltresolve */
414
where[0] = 0x39600000 | reloff;
415
where[1] = 0x48000000 | (distance & 0x03fffffc);
416
} else {
417
jmptab = obj->pltgot + JMPTAB_BASE(N);
418
jmptab[reloff] = (u_int)pltlongresolve;
419
420
/* lis r11,jmptab[reloff]@ha */
421
/* lwzu r12,jmptab[reloff]@l(r11) */
422
/* mtctr r12 */
423
/* bctr */
424
where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
425
where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
426
where[2] = 0x7d8903a6;
427
where[3] = 0x4e800420;
428
}
429
430
431
/*
432
* The icache will be sync'd in reloc_plt, which is called
433
* after all the slots have been updated
434
*/
435
436
return (0);
437
}
438
439
/*
440
* Process the PLT relocations.
441
*/
442
int
443
reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
444
{
445
const Elf_Rela *relalim;
446
const Elf_Rela *rela;
447
int N = obj->pltrelasize / sizeof(Elf_Rela);
448
449
if (obj->pltrelasize != 0) {
450
451
relalim = (const Elf_Rela *)((const char *)obj->pltrela +
452
obj->pltrelasize);
453
for (rela = obj->pltrela; rela < relalim; rela++) {
454
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
455
dbg("ABI violation - found IRELATIVE in the PLT.");
456
obj->irelative = true;
457
continue;
458
}
459
460
/*
461
* PowerPC(64) .rela.plt is composed of an array of
462
* R_PPC_JMP_SLOT relocations. Unlike other platforms,
463
* this is the ONLY relocation type that is valid here.
464
*/
465
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
466
467
if (reloc_plt_object(obj, rela) < 0) {
468
return (-1);
469
}
470
}
471
}
472
473
/*
474
* Sync the icache for the byte range represented by the
475
* trampoline routines and call slots.
476
*/
477
if (obj->pltgot != NULL && obj->gotptr == NULL)
478
__syncicache(obj->pltgot, JMPTAB_BASE(N)*4);
479
480
return (0);
481
}
482
483
/*
484
* LD_BIND_NOW was set - force relocation for all jump slots
485
*/
486
int
487
reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
488
{
489
const Obj_Entry *defobj;
490
const Elf_Rela *relalim;
491
const Elf_Rela *rela;
492
const Elf_Sym *def;
493
Elf_Addr *where;
494
Elf_Addr target;
495
496
relalim = (const Elf_Rela *)((const char *)obj->pltrela +
497
obj->pltrelasize);
498
for (rela = obj->pltrela; rela < relalim; rela++) {
499
/* This isn't actually a jump slot, ignore it. */
500
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE)
501
continue;
502
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
503
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
504
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
505
SYMLOOK_IN_PLT | flags, NULL, lockstate);
506
if (def == NULL) {
507
dbg("reloc_jmpslots: sym not found");
508
return (-1);
509
}
510
511
target = (Elf_Addr)(defobj->relocbase + def->st_value);
512
513
if (def == &sym_zero) {
514
/* Zero undefined weak symbols */
515
*where = 0;
516
} else {
517
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
518
/* LD_BIND_NOW, ifunc in shared lib.*/
519
obj->gnu_ifunc = true;
520
continue;
521
}
522
reloc_jmpslot(where, target, defobj, obj,
523
(const Elf_Rel *) rela);
524
}
525
}
526
527
obj->jmpslots_done = true;
528
529
return (0);
530
}
531
532
533
/*
534
* Update the value of a PLT jump slot.
535
*/
536
Elf_Addr
537
reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target,
538
const Obj_Entry *defobj __unused, const Obj_Entry *obj, const Elf_Rel *rel)
539
{
540
Elf_Addr offset;
541
const Elf_Rela *rela = (const Elf_Rela *) rel;
542
543
dbg(" reloc_jmpslot: where=%p, target=%p",
544
(void *)wherep, (void *)target);
545
546
if (ld_bind_not)
547
goto out;
548
549
550
/*
551
* Process Secure-PLT.
552
*/
553
if (obj->gotptr != NULL) {
554
assert(wherep >= (Elf_Word *)obj->pltgot);
555
assert(wherep <
556
(Elf_Word *)obj->pltgot + obj->pltrelasize);
557
if (*wherep != target)
558
*wherep = target;
559
goto out;
560
}
561
562
/*
563
* BSS-PLT optimization:
564
* Branch directly to the target if it is within +/- 32Mb,
565
* otherwise go indirectly via the pltcall trampoline call and
566
* jump table.
567
*/
568
offset = target - (Elf_Addr)wherep;
569
if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */
570
/*
571
* At the PLT entry pointed at by `wherep', construct
572
* a direct transfer to the now fully resolved function
573
* address.
574
*/
575
/* b value # branch directly */
576
*wherep = 0x48000000 | (offset & 0x03fffffc);
577
__syncicache(wherep, 4);
578
} else {
579
Elf_Addr *pltcall, *jmptab;
580
int distance;
581
int N = obj->pltrelasize / sizeof(Elf_Rela);
582
int reloff = rela - obj->pltrela;
583
584
if (reloff < 0)
585
return (-1);
586
587
pltcall = obj->pltgot;
588
589
dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
590
reloff, N);
591
592
jmptab = obj->pltgot + JMPTAB_BASE(N);
593
jmptab[reloff] = target;
594
mb(); /* Order jmptab update before next changes */
595
596
if (reloff < PLT_EXTENDED_BEGIN) {
597
/* for extended PLT entries, we keep the old code */
598
599
distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
600
601
/* li r11,reloff */
602
/* b pltcall # use indirect pltcall routine */
603
604
/* first instruction same as before */
605
wherep[1] = 0x48000000 | (distance & 0x03fffffc);
606
__syncicache(wherep, 8);
607
}
608
}
609
610
out:
611
return (target);
612
}
613
614
int
615
reloc_iresolve(Obj_Entry *obj,
616
struct Struct_RtldLockState *lockstate)
617
{
618
/*
619
* Since PLT slots on PowerPC are always R_PPC_JMP_SLOT,
620
* R_PPC_IRELATIVE is in RELA.
621
*/
622
const Elf_Rela *relalim;
623
const Elf_Rela *rela;
624
Elf_Addr *where, target, *ptr;
625
626
if (!obj->irelative)
627
return (0);
628
629
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
630
for (rela = obj->rela; rela < relalim; rela++) {
631
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
632
ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
633
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
634
635
lock_release(rtld_bind_lock, lockstate);
636
target = call_ifunc_resolver(ptr);
637
wlock_acquire(rtld_bind_lock, lockstate);
638
639
*where = target;
640
}
641
}
642
/*
643
* XXX Remove me when lld is fixed!
644
* LLD currently makes illegal relocations in the PLT.
645
*/
646
relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
647
for (rela = obj->pltrela; rela < relalim; rela++) {
648
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
649
ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
650
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
651
652
lock_release(rtld_bind_lock, lockstate);
653
target = call_ifunc_resolver(ptr);
654
wlock_acquire(rtld_bind_lock, lockstate);
655
656
*where = target;
657
}
658
}
659
660
obj->irelative = false;
661
return (0);
662
}
663
664
int
665
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
666
struct Struct_RtldLockState *lockstate __unused)
667
{
668
return (0);
669
}
670
671
int
672
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
673
struct Struct_RtldLockState *lockstate __unused)
674
{
675
const Elf_Rela *relalim;
676
const Elf_Rela *rela;
677
Elf_Addr *where, target;
678
const Elf_Sym *def;
679
const Obj_Entry *defobj;
680
681
if (!obj->gnu_ifunc)
682
return (0);
683
relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
684
for (rela = obj->pltrela; rela < relalim; rela++) {
685
if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) {
686
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
687
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
688
SYMLOOK_IN_PLT | flags, NULL, lockstate);
689
if (def == NULL)
690
return (-1);
691
if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
692
continue;
693
lock_release(rtld_bind_lock, lockstate);
694
target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
695
wlock_acquire(rtld_bind_lock, lockstate);
696
reloc_jmpslot(where, target, defobj, obj,
697
(const Elf_Rel *)rela);
698
}
699
}
700
obj->gnu_ifunc = false;
701
return (0);
702
}
703
704
/*
705
* Setup the plt glue routines.
706
*/
707
#define PLTCALL_SIZE 20
708
#define PLTLONGRESOLVE_SIZE 20
709
#define PLTRESOLVE_SIZE 24
710
711
void
712
init_pltgot(Obj_Entry *obj)
713
{
714
Elf_Word *pltcall, *pltresolve, *pltlongresolve;
715
Elf_Word *jmptab;
716
int N = obj->pltrelasize / sizeof(Elf_Rela);
717
718
pltcall = obj->pltgot;
719
720
if (pltcall == NULL) {
721
return;
722
}
723
724
/* Handle Secure-PLT first, if applicable. */
725
if (obj->gotptr != NULL) {
726
obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start;
727
obj->gotptr[2] = (Elf_Addr)obj;
728
dbg("obj %s secure-plt gotptr=%p start=%p obj=%p",
729
obj->path, obj->gotptr,
730
(void *)obj->gotptr[1], (void *)obj->gotptr[2]);
731
return;
732
}
733
734
/*
735
* From the SVR4 PPC ABI:
736
*
737
* 'The first 18 words (72 bytes) of the PLT are reserved for
738
* use by the dynamic linker.
739
* ...
740
* 'If the executable or shared object requires N procedure
741
* linkage table entries, the link editor shall reserve 3*N
742
* words (12*N bytes) following the 18 reserved words. The
743
* first 2*N of these words are the procedure linkage table
744
* entries themselves. The static linker directs calls to bytes
745
* (72 + (i-1)*8), for i between 1 and N inclusive. The remaining
746
* N words (4*N bytes) are reserved for use by the dynamic linker.'
747
*/
748
749
/*
750
* Copy the absolute-call assembler stub into the first part of
751
* the reserved PLT area.
752
*/
753
memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
754
755
/*
756
* Determine the address of the jumptable, which is the dyn-linker
757
* reserved area after the call cells. Write the absolute address
758
* of the jumptable into the absolute-call assembler code so it
759
* can determine this address.
760
*/
761
jmptab = obj->pltgot + JMPTAB_BASE(N);
762
pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */
763
pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */
764
765
/*
766
* Skip down 20 bytes into the initial reserved area and copy
767
* in the standard resolving assembler call. Into this assembler,
768
* insert the absolute address of the _rtld_bind_start routine
769
* and the address of the relocation object.
770
*
771
* We place pltlongresolve first, so it can fix up its arguments
772
* and then fall through to the regular PLT resolver.
773
*/
774
pltlongresolve = obj->pltgot + 5;
775
776
memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
777
PLTLONGRESOLVE_SIZE);
778
pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */
779
pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */
780
781
pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
782
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
783
pltresolve[0] |= _ppc_ha(_rtld_bind_start);
784
pltresolve[1] |= _ppc_la(_rtld_bind_start);
785
pltresolve[3] |= _ppc_ha(obj);
786
pltresolve[4] |= _ppc_la(obj);
787
788
/*
789
* The icache will be sync'd in reloc_plt, which is called
790
* after all the slots have been updated
791
*/
792
}
793
794
/*
795
* 32 bit cpu feature flag fields.
796
*/
797
u_long cpu_features;
798
u_long cpu_features2;
799
800
void
801
powerpc_abi_variant_hook(Elf_Auxinfo** aux_info)
802
{
803
/*
804
* Since aux_info[] is easier to work with than aux, go ahead and
805
* initialize cpu_features / cpu_features2.
806
*/
807
cpu_features = -1UL;
808
cpu_features2 = -1UL;
809
if (aux_info[AT_HWCAP] != NULL)
810
cpu_features = aux_info[AT_HWCAP]->a_un.a_val;
811
if (aux_info[AT_HWCAP2] != NULL)
812
cpu_features2 = aux_info[AT_HWCAP2]->a_un.a_val;
813
}
814
815
void
816
ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)] __unused)
817
{
818
819
}
820
821
void
822
allocate_initial_tls(Obj_Entry *list)
823
{
824
825
/*
826
* Fix the size of the static TLS block by using the maximum
827
* offset allocated so far and adding a bit for dynamic modules to
828
* use.
829
*/
830
831
tls_static_space = tls_last_offset + tls_last_size +
832
ld_static_tls_extra;
833
834
_tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
835
}
836
837
void*
838
__tls_get_addr(tls_index* ti)
839
{
840
return (tls_get_addr_common(_tcb_get(), ti->ti_module, ti->ti_offset +
841
TLS_DTV_OFFSET));
842
}
843
844