Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/rtld-elf/powerpc/reloc.c
104970 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
SymCache *cache;
336
int r = -1;
337
338
/*
339
* The dynamic loader may be called from a thread, we have
340
* limited amounts of stack available so we cannot use alloca().
341
*/
342
if (obj != obj_rtld) {
343
cache = calloc(obj->dynsymcount, sizeof(SymCache));
344
/* No need to check for NULL here */
345
} else
346
cache = NULL;
347
348
/*
349
* From the SVR4 PPC ABI:
350
* "The PowerPC family uses only the Elf32_Rela relocation
351
* entries with explicit addends."
352
*/
353
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
354
for (rela = obj->rela; rela < relalim; rela++) {
355
if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags,
356
lockstate) < 0)
357
goto done;
358
}
359
r = 0;
360
done:
361
if (cache != NULL)
362
free(cache);
363
return (r);
364
}
365
366
/*
367
* Initialise a PLT slot to the resolving trampoline
368
*/
369
static int
370
reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela)
371
{
372
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
373
Elf_Addr *pltresolve, *pltlongresolve, *jmptab;
374
Elf_Addr distance;
375
int N = obj->pltrelasize / sizeof(Elf_Rela);
376
int reloff;
377
378
reloff = rela - obj->pltrela;
379
380
if (reloff < 0)
381
return (-1);
382
383
if (obj->gotptr != NULL) {
384
*where += (Elf_Addr)obj->relocbase;
385
return (0);
386
}
387
388
pltlongresolve = obj->pltgot + 5;
389
pltresolve = pltlongresolve + 5;
390
391
distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1);
392
393
dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x",
394
(void *)where, (void *)pltresolve, reloff, distance);
395
396
if (reloff < PLT_EXTENDED_BEGIN) {
397
/* li r11,reloff */
398
/* b pltresolve */
399
where[0] = 0x39600000 | reloff;
400
where[1] = 0x48000000 | (distance & 0x03fffffc);
401
} else {
402
jmptab = obj->pltgot + JMPTAB_BASE(N);
403
jmptab[reloff] = (u_int)pltlongresolve;
404
405
/* lis r11,jmptab[reloff]@ha */
406
/* lwzu r12,jmptab[reloff]@l(r11) */
407
/* mtctr r12 */
408
/* bctr */
409
where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]);
410
where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]);
411
where[2] = 0x7d8903a6;
412
where[3] = 0x4e800420;
413
}
414
415
416
/*
417
* The icache will be sync'd in reloc_plt, which is called
418
* after all the slots have been updated
419
*/
420
421
return (0);
422
}
423
424
/*
425
* Process the PLT relocations.
426
*/
427
int
428
reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused)
429
{
430
const Elf_Rela *relalim;
431
const Elf_Rela *rela;
432
int N = obj->pltrelasize / sizeof(Elf_Rela);
433
434
if (obj->pltrelasize != 0) {
435
436
relalim = (const Elf_Rela *)((const char *)obj->pltrela +
437
obj->pltrelasize);
438
for (rela = obj->pltrela; rela < relalim; rela++) {
439
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
440
dbg("ABI violation - found IRELATIVE in the PLT.");
441
obj->irelative = true;
442
continue;
443
}
444
445
/*
446
* PowerPC(64) .rela.plt is composed of an array of
447
* R_PPC_JMP_SLOT relocations. Unlike other platforms,
448
* this is the ONLY relocation type that is valid here.
449
*/
450
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
451
452
if (reloc_plt_object(obj, rela) < 0) {
453
return (-1);
454
}
455
}
456
}
457
458
/*
459
* Sync the icache for the byte range represented by the
460
* trampoline routines and call slots.
461
*/
462
if (obj->pltgot != NULL && obj->gotptr == NULL)
463
__syncicache(obj->pltgot, JMPTAB_BASE(N)*4);
464
465
return (0);
466
}
467
468
/*
469
* LD_BIND_NOW was set - force relocation for all jump slots
470
*/
471
int
472
reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate)
473
{
474
const Obj_Entry *defobj;
475
const Elf_Rela *relalim;
476
const Elf_Rela *rela;
477
const Elf_Sym *def;
478
Elf_Addr *where;
479
Elf_Addr target;
480
481
relalim = (const Elf_Rela *)((const char *)obj->pltrela +
482
obj->pltrelasize);
483
for (rela = obj->pltrela; rela < relalim; rela++) {
484
/* This isn't actually a jump slot, ignore it. */
485
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE)
486
continue;
487
assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
488
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
489
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
490
SYMLOOK_IN_PLT | flags, NULL, lockstate);
491
if (def == NULL) {
492
dbg("reloc_jmpslots: sym not found");
493
return (-1);
494
}
495
496
target = (Elf_Addr)(defobj->relocbase + def->st_value);
497
498
if (def == &sym_zero) {
499
/* Zero undefined weak symbols */
500
*where = 0;
501
} else {
502
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
503
/* LD_BIND_NOW, ifunc in shared lib.*/
504
obj->gnu_ifunc = true;
505
continue;
506
}
507
reloc_jmpslot(where, target, defobj, obj,
508
(const Elf_Rel *) rela);
509
}
510
}
511
512
obj->jmpslots_done = true;
513
514
return (0);
515
}
516
517
518
/*
519
* Update the value of a PLT jump slot.
520
*/
521
Elf_Addr
522
reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target,
523
const Obj_Entry *defobj __unused, const Obj_Entry *obj, const Elf_Rel *rel)
524
{
525
Elf_Addr offset;
526
const Elf_Rela *rela = (const Elf_Rela *) rel;
527
528
dbg(" reloc_jmpslot: where=%p, target=%p",
529
(void *)wherep, (void *)target);
530
531
if (ld_bind_not)
532
goto out;
533
534
535
/*
536
* Process Secure-PLT.
537
*/
538
if (obj->gotptr != NULL) {
539
assert(wherep >= (Elf_Word *)obj->pltgot);
540
assert(wherep <
541
(Elf_Word *)obj->pltgot + obj->pltrelasize);
542
if (*wherep != target)
543
*wherep = target;
544
goto out;
545
}
546
547
/*
548
* BSS-PLT optimization:
549
* Branch directly to the target if it is within +/- 32Mb,
550
* otherwise go indirectly via the pltcall trampoline call and
551
* jump table.
552
*/
553
offset = target - (Elf_Addr)wherep;
554
if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */
555
/*
556
* At the PLT entry pointed at by `wherep', construct
557
* a direct transfer to the now fully resolved function
558
* address.
559
*/
560
/* b value # branch directly */
561
*wherep = 0x48000000 | (offset & 0x03fffffc);
562
__syncicache(wherep, 4);
563
} else {
564
Elf_Addr *pltcall, *jmptab;
565
int distance;
566
int N = obj->pltrelasize / sizeof(Elf_Rela);
567
int reloff = rela - obj->pltrela;
568
569
if (reloff < 0)
570
return (-1);
571
572
pltcall = obj->pltgot;
573
574
dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n",
575
reloff, N);
576
577
jmptab = obj->pltgot + JMPTAB_BASE(N);
578
jmptab[reloff] = target;
579
mb(); /* Order jmptab update before next changes */
580
581
if (reloff < PLT_EXTENDED_BEGIN) {
582
/* for extended PLT entries, we keep the old code */
583
584
distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1);
585
586
/* li r11,reloff */
587
/* b pltcall # use indirect pltcall routine */
588
589
/* first instruction same as before */
590
wherep[1] = 0x48000000 | (distance & 0x03fffffc);
591
__syncicache(wherep, 8);
592
}
593
}
594
595
out:
596
return (target);
597
}
598
599
int
600
reloc_iresolve(Obj_Entry *obj,
601
struct Struct_RtldLockState *lockstate)
602
{
603
/*
604
* Since PLT slots on PowerPC are always R_PPC_JMP_SLOT,
605
* R_PPC_IRELATIVE is in RELA.
606
*/
607
const Elf_Rela *relalim;
608
const Elf_Rela *rela;
609
Elf_Addr *where, target, *ptr;
610
611
if (!obj->irelative)
612
return (0);
613
614
relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize);
615
for (rela = obj->rela; rela < relalim; rela++) {
616
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
617
ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
618
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
619
620
lock_release(rtld_bind_lock, lockstate);
621
target = call_ifunc_resolver(ptr);
622
wlock_acquire(rtld_bind_lock, lockstate);
623
624
*where = target;
625
}
626
}
627
/*
628
* XXX Remove me when lld is fixed!
629
* LLD currently makes illegal relocations in the PLT.
630
*/
631
relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
632
for (rela = obj->pltrela; rela < relalim; rela++) {
633
if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) {
634
ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend);
635
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
636
637
lock_release(rtld_bind_lock, lockstate);
638
target = call_ifunc_resolver(ptr);
639
wlock_acquire(rtld_bind_lock, lockstate);
640
641
*where = target;
642
}
643
}
644
645
obj->irelative = false;
646
return (0);
647
}
648
649
int
650
reloc_iresolve_nonplt(Obj_Entry *obj __unused,
651
struct Struct_RtldLockState *lockstate __unused)
652
{
653
return (0);
654
}
655
656
int
657
reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused,
658
struct Struct_RtldLockState *lockstate __unused)
659
{
660
const Elf_Rela *relalim;
661
const Elf_Rela *rela;
662
Elf_Addr *where, target;
663
const Elf_Sym *def;
664
const Obj_Entry *defobj;
665
666
if (!obj->gnu_ifunc)
667
return (0);
668
relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize);
669
for (rela = obj->pltrela; rela < relalim; rela++) {
670
if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) {
671
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
672
def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
673
SYMLOOK_IN_PLT | flags, NULL, lockstate);
674
if (def == NULL)
675
return (-1);
676
if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC)
677
continue;
678
lock_release(rtld_bind_lock, lockstate);
679
target = (Elf_Addr)rtld_resolve_ifunc(defobj, def);
680
wlock_acquire(rtld_bind_lock, lockstate);
681
reloc_jmpslot(where, target, defobj, obj,
682
(const Elf_Rel *)rela);
683
}
684
}
685
obj->gnu_ifunc = false;
686
return (0);
687
}
688
689
/*
690
* Setup the plt glue routines.
691
*/
692
#define PLTCALL_SIZE 20
693
#define PLTLONGRESOLVE_SIZE 20
694
#define PLTRESOLVE_SIZE 24
695
696
void
697
init_pltgot(Obj_Entry *obj)
698
{
699
Elf_Word *pltcall, *pltresolve, *pltlongresolve;
700
Elf_Word *jmptab;
701
int N = obj->pltrelasize / sizeof(Elf_Rela);
702
703
pltcall = obj->pltgot;
704
705
if (pltcall == NULL) {
706
return;
707
}
708
709
/* Handle Secure-PLT first, if applicable. */
710
if (obj->gotptr != NULL) {
711
obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start;
712
obj->gotptr[2] = (Elf_Addr)obj;
713
dbg("obj %s secure-plt gotptr=%p start=%p obj=%p",
714
obj->path, obj->gotptr,
715
(void *)obj->gotptr[1], (void *)obj->gotptr[2]);
716
return;
717
}
718
719
/*
720
* From the SVR4 PPC ABI:
721
*
722
* 'The first 18 words (72 bytes) of the PLT are reserved for
723
* use by the dynamic linker.
724
* ...
725
* 'If the executable or shared object requires N procedure
726
* linkage table entries, the link editor shall reserve 3*N
727
* words (12*N bytes) following the 18 reserved words. The
728
* first 2*N of these words are the procedure linkage table
729
* entries themselves. The static linker directs calls to bytes
730
* (72 + (i-1)*8), for i between 1 and N inclusive. The remaining
731
* N words (4*N bytes) are reserved for use by the dynamic linker.'
732
*/
733
734
/*
735
* Copy the absolute-call assembler stub into the first part of
736
* the reserved PLT area.
737
*/
738
memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
739
740
/*
741
* Determine the address of the jumptable, which is the dyn-linker
742
* reserved area after the call cells. Write the absolute address
743
* of the jumptable into the absolute-call assembler code so it
744
* can determine this address.
745
*/
746
jmptab = obj->pltgot + JMPTAB_BASE(N);
747
pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */
748
pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */
749
750
/*
751
* Skip down 20 bytes into the initial reserved area and copy
752
* in the standard resolving assembler call. Into this assembler,
753
* insert the absolute address of the _rtld_bind_start routine
754
* and the address of the relocation object.
755
*
756
* We place pltlongresolve first, so it can fix up its arguments
757
* and then fall through to the regular PLT resolver.
758
*/
759
pltlongresolve = obj->pltgot + 5;
760
761
memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve,
762
PLTLONGRESOLVE_SIZE);
763
pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */
764
pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */
765
766
pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t);
767
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
768
pltresolve[0] |= _ppc_ha(_rtld_bind_start);
769
pltresolve[1] |= _ppc_la(_rtld_bind_start);
770
pltresolve[3] |= _ppc_ha(obj);
771
pltresolve[4] |= _ppc_la(obj);
772
773
/*
774
* The icache will be sync'd in reloc_plt, which is called
775
* after all the slots have been updated
776
*/
777
}
778
779
/*
780
* 32 bit cpu feature flag fields.
781
*/
782
u_long cpu_features;
783
u_long cpu_features2;
784
785
void
786
powerpc_abi_variant_hook(Elf_Auxinfo** aux_info)
787
{
788
/*
789
* Since aux_info[] is easier to work with than aux, go ahead and
790
* initialize cpu_features / cpu_features2.
791
*/
792
cpu_features = -1UL;
793
cpu_features2 = -1UL;
794
if (aux_info[AT_HWCAP] != NULL)
795
cpu_features = aux_info[AT_HWCAP]->a_un.a_val;
796
if (aux_info[AT_HWCAP2] != NULL)
797
cpu_features2 = aux_info[AT_HWCAP2]->a_un.a_val;
798
}
799
800
void
801
ifunc_init(Elf_Auxinfo *aux_info[__min_size(AT_COUNT)] __unused)
802
{
803
804
}
805
806
void
807
allocate_initial_tls(Obj_Entry *list)
808
{
809
810
/*
811
* Fix the size of the static TLS block by using the maximum
812
* offset allocated so far and adding a bit for dynamic modules to
813
* use.
814
*/
815
816
tls_static_space = tls_last_offset + tls_last_size +
817
ld_static_tls_extra;
818
819
_tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN));
820
}
821
822
void*
823
__tls_get_addr(tls_index* ti)
824
{
825
return (tls_get_addr_common(_tcb_get(), ti->ti_module, ti->ti_offset +
826
TLS_DTV_OFFSET));
827
}
828
829
void
830
arch_fix_auxv(Elf_Auxinfo *aux, Elf_Auxinfo *aux_info[])
831
{
832
Elf_Auxinfo *auxp;
833
834
for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
835
if (auxp->a_type == 23) /* AT_STACKPROT */
836
return;
837
}
838
839
/* Remap from old-style auxv numbers. */
840
aux_info[23] = aux_info[21]; /* AT_STACKPROT */
841
aux_info[21] = aux_info[19]; /* AT_PAGESIZESLEN */
842
aux_info[19] = aux_info[17]; /* AT_NCPUS */
843
aux_info[17] = aux_info[15]; /* AT_CANARYLEN */
844
aux_info[15] = aux_info[13]; /* AT_EXECPATH */
845
aux_info[13] = NULL; /* AT_GID */
846
847
aux_info[20] = aux_info[18]; /* AT_PAGESIZES */
848
aux_info[18] = aux_info[16]; /* AT_OSRELDATE */
849
aux_info[16] = aux_info[14]; /* AT_CANARY */
850
aux_info[14] = NULL; /* AT_EGID */
851
}
852
853