]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/dl-machine.h
Update.
[thirdparty/glibc.git] / sysdeps / powerpc / dl-machine.h
CommitLineData
4cca6b86 1/* Machine-dependent ELF dynamic relocation inline functions. PowerPC version.
b0cf070b 2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
4cca6b86
UD
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
1f205a47
UD
20#ifndef dl_machine_h
21#define dl_machine_h
22
4cca6b86
UD
23#define ELF_MACHINE_NAME "powerpc"
24
25#include <assert.h>
26#include <string.h>
27#include <link.h>
1f07e617
UD
28#include <sys/param.h>
29
4cca6b86
UD
30
31/* stuff for the PLT */
32#define PLT_INITIAL_ENTRY_WORDS 18
33#define PLT_LONGBRANCH_ENTRY_WORDS 10
e61abf83
UD
34#define PLT_DOUBLE_SIZE (1<<13)
35#define PLT_ENTRY_START_WORDS(entry_number) \
36 (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2 + \
37 ((entry_number) > PLT_DOUBLE_SIZE ? \
38 ((entry_number) - PLT_DOUBLE_SIZE)*2 : \
39 0))
40#define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
41
4cca6b86
UD
42#define OPCODE_ADDI(rd,ra,simm) \
43 (0x38000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
44#define OPCODE_ADDIS(rd,ra,simm) \
45 (0x3c000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
46#define OPCODE_ADD(rd,ra,rb) \
47 (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
48#define OPCODE_B(target) (0x48000000 | (target) & 0x03fffffc)
49#define OPCODE_BA(target) (0x48000002 | (target) & 0x03fffffc)
50#define OPCODE_BCTR() 0x4e800420
51#define OPCODE_LWZ(rd,d,ra) \
52 (0x80000000 | (rd) << 21 | (ra) << 16 | (d) & 0xffff)
53#define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
54#define OPCODE_RLWINM(ra,rs,sh,mb,me) \
55 (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
56
57#define OPCODE_LI(rd,simm) OPCODE_ADDI(rd,0,simm)
58#define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
59
0413b54c
UD
60#define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where))
61#define PPC_SYNC asm volatile ("sync")
62#define PPC_ISYNC asm volatile ("sync; isync")
63#define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where))
64#define PPC_DIE asm volatile ("tweq 0,0")
e61abf83
UD
65
66/* Use this when you've modified some code, but it won't be in the
67 instruction fetch queue (or when it doesn't matter if it is). */
68#define MODIFIED_CODE_NOQUEUE(where) \
69 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
70/* Use this when it might be in the instruction queue. */
71#define MODIFIED_CODE(where) \
72 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
73
4cca6b86
UD
74
75/* Return nonzero iff E_MACHINE is compatible with the running host. */
76static inline int
77elf_machine_matches_host (Elf32_Half e_machine)
78{
79 return e_machine == EM_PPC;
80}
81
82
e61abf83
UD
83/* Return the link-time address of _DYNAMIC, stored as
84 the first value in the GOT. */
4cca6b86
UD
85static inline Elf32_Addr
86elf_machine_dynamic (void)
87{
88 Elf32_Addr *got;
89 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
90 : "=l"(got));
91 return *got;
92}
93
94/* Return the run-time load address of the shared object. */
95static inline Elf32_Addr
96elf_machine_load_address (void)
97{
98 unsigned *got;
99 unsigned *branchaddr;
100
101 /* This is much harder than you'd expect. Possibly I'm missing something.
102 The 'obvious' way:
103
104 Apparently, "bcl 20,31,$+4" is what should be used to load LR
105 with the address of the next instruction.
106 I think this is so that machines that do bl/blr pairing don't
107 get confused.
108
109 asm ("bcl 20,31,0f ;"
e61abf83
UD
110 "0: mflr 0 ;"
111 "lis %0,0b@ha;"
112 "addi %0,%0,0b@l;"
113 "subf %0,%0,0"
114 : "=b" (addr) : : "r0", "lr");
4cca6b86
UD
115
116 doesn't work, because the linker doesn't have to (and in fact doesn't)
117 update the @ha and @l references; the loader (which runs after this
118 code) will do that.
119
120 Instead, we use the following trick:
121
122 The linker puts the _link-time_ address of _DYNAMIC at the first
123 word in the GOT. We could branch to that address, if we wanted,
124 by using an @local reloc; the linker works this out, so it's safe
125 to use now. We can't, of course, actually branch there, because
126 we'd cause an illegal instruction exception; so we need to compute
127 the address ourselves. That gives us the following code: */
128
129 /* Get address of the 'b _DYNAMIC@local'... */
130 asm ("bl 0f ;"
131 "b _DYNAMIC@local;"
132 "0:"
133 : "=l"(branchaddr));
134
135 /* ... and the address of the GOT. */
136 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
137 : "=l"(got));
138
139 /* So now work out the difference between where the branch actually points,
140 and the offset of that location in memory from the start of the file. */
1f205a47
UD
141 return ((Elf32_Addr)branchaddr - *got
142 + (*branchaddr & 0x3fffffc
143 | (int)(*branchaddr << 6 & 0x80000000) >> 6));
4cca6b86
UD
144}
145
146#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
147
1f205a47
UD
148/* The PLT uses Elf32_Rela relocs. */
149#define elf_machine_relplt elf_machine_rela
4cca6b86 150
0413b54c 151/* This code is used in dl-runtime.c to call the `fixup' function
9a0a462c
UD
152 and then redirect to the address it returns. It is called
153 from code built in the PLT by elf_machine_runtime_setup. */
1f205a47
UD
154#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
155 .section \".text\"
156 .align 2
157 .globl _dl_runtime_resolve
158 .type _dl_runtime_resolve,@function
159_dl_runtime_resolve:
9a0a462c
UD
160 # We need to save the registers used to pass parameters, and register 0,
161 # which is used by _mcount; the registers are saved in a stack frame.
1f205a47 162 stwu 1,-48(1)
9a0a462c 163 stw 0,12(1)
1f205a47
UD
164 stw 3,16(1)
165 stw 4,20(1)
9a0a462c
UD
166 # The code that calls this has put parameters for `fixup' in r12 and r11.
167 mr 3,12
1f205a47 168 stw 5,24(1)
9a0a462c 169 mr 4,11
1f205a47 170 stw 6,28(1)
9a0a462c
UD
171 mflr 0
172 # We also need to save some of the condition register fields.
1f205a47 173 stw 7,32(1)
9a0a462c 174 stw 0,52(1)
1f205a47 175 stw 8,36(1)
9a0a462c 176 mfcr 0
1f205a47
UD
177 stw 9,40(1)
178 stw 10,44(1)
9a0a462c 179 stw 0,8(1)
1f205a47
UD
180 bl fixup@local
181 # 'fixup' returns the address we want to branch to.
182 mtctr 3
183 # Put the registers back...
184 lwz 0,52(1)
185 lwz 10,44(1)
186 lwz 9,40(1)
187 mtlr 0
1f205a47 188 lwz 8,36(1)
9a0a462c 189 lwz 0,8(1)
1f205a47
UD
190 lwz 7,32(1)
191 lwz 6,28(1)
192 mtcrf 0xFF,0
193 lwz 5,24(1)
194 lwz 4,20(1)
195 lwz 3,16(1)
9a0a462c 196 lwz 0,12(1)
1f205a47
UD
197 # ...unwind the stack frame, and jump to the PLT entry we updated.
198 addi 1,1,48
199 bctr
a2b08ee5 200 .size _dl_runtime_resolve,.-_dl_runtime_resolve
650425ce
UD
201
202 .align 2
203 .globl _dl_prof_resolve
204 .type _dl_prof_resolve,@function
205_dl_prof_resolve:
206 # We need to save the registers used to pass parameters, and register 0,
207 # which is used by _mcount; the registers are saved in a stack frame.
208 stwu 1,-48(1)
209 stw 0,12(1)
210 stw 3,16(1)
211 stw 4,20(1)
212 # The code that calls this has put parameters for `fixup' in r12 and r11.
213 mr 3,12
214 stw 5,24(1)
215 mr 4,11
216 stw 6,28(1)
217 mflr 5
218 # We also need to save some of the condition register fields.
219 stw 7,32(1)
220 stw 5,52(1)
221 stw 8,36(1)
222 mfcr 0
223 stw 9,40(1)
224 stw 10,44(1)
225 stw 0,8(1)
226 bl profile_fixup@local
227 # 'fixup' returns the address we want to branch to.
228 mtctr 3
229 # Put the registers back...
230 lwz 0,52(1)
231 lwz 10,44(1)
232 lwz 9,40(1)
233 mtlr 0
234 lwz 8,36(1)
235 lwz 0,8(1)
236 lwz 7,32(1)
237 lwz 6,28(1)
238 mtcrf 0xFF,0
239 lwz 5,24(1)
240 lwz 4,20(1)
241 lwz 3,16(1)
242 lwz 0,12(1)
243 # ...unwind the stack frame, and jump to the PLT entry we updated.
244 addi 1,1,48
245 bctr
af6f3906 246 .size _dl_prof_resolve,.-_dl_prof_resolve
9a0a462c 247 # Undo '.section text'.
1f205a47
UD
248 .previous
249");
4cca6b86 250
1f205a47
UD
251/* Initial entry point code for the dynamic linker.
252 The C function `_dl_start' is the real entry point;
253 its return value is the user program's entry point. */
254#define RTLD_START \
255static ElfW(Addr) _dl_start (void *arg) __attribute__((unused)); \
256asm ("\
257 .section \".text\"
258 .align 2
259 .globl _start
260 .type _start,@function
261_start:
262 # We start with the following on the stack, from top:
9a0a462c
UD
263 # argc (4 bytes);
264 # arguments for program (terminated by NULL);
265 # environment variables (terminated by NULL);
266 # arguments for the program loader.
1f205a47 267 # FIXME: perhaps this should do the same trick as elf/start.c?
4cca6b86 268
1f205a47 269 # Call _dl_start with one parameter pointing at argc
9a0a462c 270 mr 3,1
1f205a47
UD
271 # (we have to frob the stack pointer a bit to allow room for
272 # _dl_start to save the link register)
9a0a462c 273 li 4,0
1f205a47 274 addi 1,1,-16
9a0a462c
UD
275 stw 4,0(1)
276 bl _dl_start@local
4cca6b86 277
1f205a47
UD
278 # Now, we do our main work of calling initialisation procedures.
279 # The ELF ABI doesn't say anything about parameters for these,
280 # so we just pass argc, argv, and the environment.
281 # Changing these is strongly discouraged (not least because argc is
282 # passed by value!).
e61abf83 283
9a0a462c
UD
284 # Put our GOT pointer in r31,
285 bl _GLOBAL_OFFSET_TABLE_-4@local
1f205a47 286 mflr 31
9a0a462c
UD
287 # the address of _start in r30,
288 mr 30,3
289 # &_dl_argc in 29, &_dl_argv in 27, and _dl_default_scope in 28.
290 lwz 28,_dl_default_scope@got(31)
291 lwz 29,_dl_argc@got(31)
292 lwz 27,_dl_argv@got(31)
1f205a47 2930:
9a0a462c
UD
294 # Set initfunc = _dl_init_next(_dl_default_scope[2])
295 lwz 3,8(28)
296 bl _dl_init_next@plt
297 # If initfunc is NULL, we exit the loop; otherwise,
298 cmpwi 3,0
299 beq 1f
1f205a47 300 # call initfunc(_dl_argc, _dl_argv, _dl_argv+_dl_argc+1)
9a0a462c
UD
301 mtlr 3
302 lwz 3,0(29)
303 lwz 4,0(27)
1f205a47 304 slwi 5,3,2
9a0a462c 305 add 5,4,5
1f205a47
UD
306 addi 5,5,4
307 blrl
308 # and loop.
9a0a462c 309 b 0b
1f205a47
UD
3101:
311 # Now, to conform to the ELF ABI, we have to:
9a0a462c
UD
312 # Pass argc (actually _dl_argc) in r3;
313 lwz 3,0(29)
314 # pass argv (actually _dl_argv) in r4;
315 lwz 4,0(27)
316 # pass envp (actually _dl_argv+_dl_argc+1) in r5;
1f205a47 317 slwi 5,3,2
9a0a462c
UD
318 add 6,4,5
319 addi 5,6,4
320 # pass the auxilary vector in r6. This is passed to us just after _envp.
1f205a47 3212: lwzu 0,4(6)
9a0a462c
UD
322 cmpwi 0,0,0
323 bne 2b
1f205a47 324 addi 6,6,4
9a0a462c
UD
325 # Pass a termination function pointer (in this case _dl_fini) in r7.
326 lwz 7,_dl_fini@got(31)
327 # Now, call the start function in r30...
1f205a47 328 mtctr 30
9a0a462c
UD
329 lwz 26,_dl_starting_up@got(31)
330 # Pass the stack pointer in r1 (so far so good), pointing to a NULL value.
331 # (This lets our startup code distinguish between a program linked statically,
1f205a47
UD
332 # which linux will call with argc on top of the stack which will hopefully
333 # never be zero, and a dynamically linked program which will always have
334 # a NULL on the top of the stack).
335 # Take the opportunity to clear LR, so anyone who accidentally returns
9a0a462c
UD
336 # from _start gets SEGV. Also clear the next few words of the stack.
337 li 31,0
338 stw 31,0(1)
339 mtlr 31
340 stw 31,4(1)
341 stw 31,8(1)
342 stw 31,12(1)
343 # Clear _dl_starting_up.
344 stw 31,0(26)
345 # Go do it!
1f205a47
UD
346 bctr
3470:
348 .size _start,0b-_start
9a0a462c 349 # Undo '.section text'.
1f205a47
UD
350 .previous
351");
4cca6b86 352
1f205a47
UD
353/* The idea here is that to conform to the ABI, we are supposed to try
354 to load dynamic objects between 0x10000 (we actually use 0x40000 as
355 the lower bound, to increase the chance of a memory reference from
356 a null pointer giving a segfault) and the program's load address.
357 Regrettably, in this code we can't find the program's load address,
358 so we punt and choose 0x01800000, which is below the ABI's
359 recommended default, and what GNU ld currently chooses. We only use
360 the address as a preference for mmap, so if we get it wrong the
361 worst that happens is that it gets mapped somewhere else.
1f07e617 362
1f205a47
UD
363 FIXME: Unfortunately, 'somewhere else' is probably right after the
364 program's break, which causes malloc to fail. We really need more
365 information here about the way memory is mapped. */
5929563f 366
1f205a47
UD
367#define ELF_PREFERRED_ADDRESS_DATA \
368static ElfW(Addr) _dl_preferred_address = 1
e61abf83 369
1f205a47
UD
370#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
371( { \
372 ElfW(Addr) prefd; \
373 if (mapstartpref != 0 && _dl_preferred_address == 1) \
374 _dl_preferred_address = mapstartpref; \
375 if (mapstartpref != 0) \
376 prefd = mapstartpref; \
377 else if (_dl_preferred_address == 1) \
378 prefd = _dl_preferred_address = \
379 (0x01800000 - maplength - 0x10000) & \
380 ~(_dl_pagesize - 1); \
381 else if (_dl_preferred_address < maplength + 0x50000) \
382 prefd = 0; \
383 else \
384 prefd = _dl_preferred_address = \
385 ((_dl_preferred_address - maplength - 0x10000) \
386 & ~(_dl_pagesize - 1)); \
387 prefd; \
388} )
e61abf83 389
1f205a47
UD
390#define ELF_FIXED_ADDRESS(loader, mapstart) \
391( { \
392 if (mapstart != 0 && _dl_preferred_address == 1) \
393 _dl_preferred_address = mapstart; \
394} )
e61abf83 395
1f205a47
UD
396/* Nonzero iff TYPE should not be allowed to resolve to one of
397 the main executable's symbols, as for a COPY reloc. */
398#define elf_machine_lookup_noexec_p(type) ((type) == R_PPC_COPY)
4cca6b86 399
1f205a47
UD
400/* Nonzero iff TYPE describes relocation of a PLT entry, so
401 PLT entries should not be allowed to define the value. */
402/* We never want to use a PLT entry as the destination of a
403 reloc, when what is being relocated is a branch. This is
404 partly for efficiency, but mostly so we avoid loops. */
405#define elf_machine_lookup_noplt_p(type) ((type) == R_PPC_REL24 || \
406 (type) == R_PPC_ADDR24 || \
407 (type) == R_PPC_JMP_SLOT)
4cca6b86 408
1f205a47 409/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
a2b08ee5 410#define ELF_MACHINE_JMP_SLOT R_PPC_JMP_SLOT
4cca6b86
UD
411
412/* Nonzero iff TYPE describes relocation of a PLT entry, so
413 PLT entries should not be allowed to define the value. */
414#define elf_machine_pltrel_p(type) ((type) == R_PPC_JMP_SLOT)
415
416/* Set up the loaded object described by L so its unrelocated PLT
5929563f
UD
417 entries will jump to the on-demand fixup code in dl-runtime.c.
418 Also install a small trampoline to be used by entries that have
419 been relocated to an address too far away for a single branch. */
420
421/* A PLT entry does one of three things:
422 (i) Jumps to the actual routine. Such entries are set up above, in
423 elf_machine_rela.
424
425 (ii) Jumps to the actual routine via glue at the start of the PLT.
426 We do this by putting the address of the routine in space
427 allocated at the end of the PLT, and when the PLT entry is
428 called we load the offset of that word (from the start of the
429 space) into r11, then call the glue, which loads the word and
430 branches to that address. These entries are set up in
431 elf_machine_rela, but the glue is set up here.
432
433 (iii) Loads the index of this PLT entry (we count the double-size
434 entries as one entry for this purpose) into r11, then
435 branches to code at the start of the PLT. This code then
436 calls `fixup', in dl-runtime.c, via the glue in the macro
437 ELF_MACHINE_RUNTIME_TRAMPOLINE, which resets the PLT entry to
438 be one of the above two types. These entries are set up here. */
0501d603 439static inline int
3996f34b 440elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
4cca6b86 441{
4cca6b86
UD
442 if (map->l_info[DT_JMPREL])
443 {
9a0a462c 444 Elf32_Word i;
4cca6b86
UD
445 /* Fill in the PLT. Its initial contents are directed to a
446 function earlier in the PLT which arranges for the dynamic
447 linker to be called back. */
e61abf83
UD
448 Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr
449 + map->l_info[DT_PLTGOT]->d_un.d_val);
450 Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
451 / sizeof (Elf32_Rela));
452 Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
e61abf83 453 Elf32_Word size_modified;
650425ce
UD
454 extern void _dl_runtime_resolve (void);
455 extern void _dl_prof_resolve (void);
456 Elf32_Word dlrr;
457
458 dlrr = (Elf32_Word)(char *)(profile
459 ? _dl_prof_resolve
460 : _dl_runtime_resolve);
4cca6b86
UD
461
462 if (lazy)
463 for (i = 0; i < num_plt_entries; i++)
4cca6b86 464 {
5929563f 465 Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
e61abf83
UD
466
467 if (i >= PLT_DOUBLE_SIZE)
468 {
5929563f
UD
469 plt[offset ] = OPCODE_LI (11, i * 4);
470 plt[offset+1] = OPCODE_ADDIS (11, 11, (i * 4 + 0x8000) >> 16);
e61abf83
UD
471 plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
472 }
473 else
474 {
5929563f
UD
475 plt[offset ] = OPCODE_LI (11, i * 4);
476 plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
e61abf83 477 }
5929563f 478 }
e61abf83 479
5929563f
UD
480 /* Multiply index of entry by 3 (in r11). */
481 plt[0] = OPCODE_SLWI (12, 11, 1);
482 plt[1] = OPCODE_ADD (11, 12, 11);
650425ce 483 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
5929563f
UD
484 {
485 /* Load address of link map in r12. */
486 plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
487 plt[3] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
488 + 0x8000) >> 16));
489
490 /* Call _dl_runtime_resolve. */
650425ce 491 plt[4] = OPCODE_BA (dlrr);
4cca6b86
UD
492 }
493 else
494 {
5929563f 495 /* Get address of _dl_runtime_resolve in CTR. */
650425ce
UD
496 plt[2] = OPCODE_LI (12, dlrr);
497 plt[3] = OPCODE_ADDIS (12, 12, (dlrr + 0x8000) >> 16);
4cca6b86 498 plt[4] = OPCODE_MTCTR (12);
5929563f
UD
499
500 /* Load address of link map in r12. */
4cca6b86 501 plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
5929563f
UD
502 plt[6] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
503 + 0x8000) >> 16));
504
505 /* Call _dl_runtime_resolve. */
4cca6b86
UD
506 plt[7] = OPCODE_BCTR ();
507 }
5929563f
UD
508
509
510 /* Convert the index in r11 into an actual address, and get the
511 word at that address. */
4cca6b86 512 plt[PLT_LONGBRANCH_ENTRY_WORDS] =
5929563f
UD
513 OPCODE_ADDIS (11, 11, (((Elf32_Word) (char*) (plt + rel_offset_words)
514 + 0x8000) >> 16));
4cca6b86 515 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
5929563f
UD
516 OPCODE_LWZ (11, (Elf32_Word) (char*) (plt+rel_offset_words), 11);
517
518 /* Call the procedure at that address. */
4cca6b86
UD
519 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11);
520 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR ();
e61abf83 521
5929563f
UD
522
523 /* Now, we've modified code (quite a lot of code, possibly). We
524 need to write the changes from the data cache to a
525 second-level unified cache, then make sure that stale data in
526 the instruction cache is removed. (In a multiprocessor
527 system, the effect is more complex.)
528
529 Assumes the cache line size is at least 32 bytes, or at least
530 that dcbst and icbi apply to 32-byte lines. At present, all
531 PowerPC processors have line sizes of exactly 32 bytes. */
532
e61abf83 533 size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
e61abf83
UD
534 for (i = 0; i < size_modified; i+=8)
535 PPC_DCBST (plt + i);
536 PPC_SYNC;
537 for (i = 0; i < size_modified; i+=8)
538 PPC_ICBI (plt + i);
539 PPC_ISYNC;
4cca6b86 540 }
0501d603
UD
541
542 return lazy;
4cca6b86
UD
543}
544
545static inline void
b0cf070b 546elf_machine_lazy_rel (Elf32_Addr l_addr, const Elf32_Rela *reloc)
4cca6b86 547{
4cca6b86
UD
548 /* elf_machine_runtime_setup handles this. */
549}
550
a2b08ee5
UD
551static inline void
552elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
553 Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
554{
555 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
556 if (delta << 6 >> 6 == delta)
557 *reloc_addr = OPCODE_B (delta);
558 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
559 *reloc_addr = OPCODE_BA (finaladdr);
560 else
561 {
562 Elf32_Word *plt;
563 Elf32_Word index;
564
565 plt = (Elf32_Word *)((char *)map->l_addr
566 + map->l_info[DT_PLTGOT]->d_un.d_val);
567 index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
568 if (index >= PLT_DOUBLE_SIZE)
569 {
570 /* Slots greater than or equal to 2^13 have 4 words available
571 instead of two. */
572 /* FIXME: There are some possible race conditions in this code,
573 when called from 'fixup'.
574
575 1) Suppose that a lazy PLT entry is executing, a context switch
576 between threads (or a signal) occurs, and the new thread or
577 signal handler calls the same lazy PLT entry. Then the PLT entry
578 would be changed while it's being run, which will cause a segfault
579 (almost always).
580
581 2) Suppose the reverse: that a lazy PLT entry is being updated,
582 a context switch occurs, and the new code calls the lazy PLT
583 entry that is being updated. Then the half-fixed PLT entry will
584 be executed, which will also almost always cause a segfault.
585
586 These problems don't happen with the 2-word entries, because
587 only one of the two instructions are changed when a lazy entry
588 is retargeted at the actual PLT entry; the li instruction stays
589 the same (we have to update it anyway, because we might not be
590 updating a lazy PLT entry). */
591
592 reloc_addr[0] = OPCODE_LI (11, finaladdr);
593 reloc_addr[1] = OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16);
594 reloc_addr[2] = OPCODE_MTCTR (11);
595 reloc_addr[3] = OPCODE_BCTR ();
596 }
597 else
598 {
599 Elf32_Word num_plt_entries;
600
601 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
602 / sizeof(Elf32_Rela));
603
604 plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
605 reloc_addr[0] = OPCODE_LI (11, index*4);
606 reloc_addr[1] = OPCODE_B (-(4*(index*2
607 + 1
608 - PLT_LONGBRANCH_ENTRY_WORDS
609 + PLT_INITIAL_ENTRY_WORDS)));
610 }
611 }
612 MODIFIED_CODE (reloc_addr);
613}
614
dfd2257a
UD
615/* Return the final value of a plt relocation. */
616static inline Elf32_Addr
617elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
618 Elf32_Addr value)
619{
620 return value + reloc->r_addend;
621}
622
1f205a47 623#endif /* dl_machine_h */
4cca6b86 624
1f205a47 625#ifdef RESOLVE
4cca6b86 626
1f205a47
UD
627/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
628 LOADADDR is the load address of the object; INFO is an array indexed
629 by DT_* of the .dynamic section info. */
4cca6b86 630
650425ce 631static void
1f205a47 632elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
3996f34b 633 const Elf32_Sym *sym, const struct r_found_version *version,
0413b54c 634 Elf32_Addr *const reloc_addr)
1f205a47 635{
0413b54c 636#ifndef RTLD_BOOTSTRAP
1f205a47 637 const Elf32_Sym *const refsym = sym;
9a0a462c 638 extern char **_dl_argv;
0413b54c 639#endif
1f205a47
UD
640 Elf32_Word loadbase, finaladdr;
641 const int rinfo = ELF32_R_TYPE (reloc->r_info);
4cca6b86 642
1f205a47
UD
643 if (rinfo == R_PPC_NONE)
644 return;
4cca6b86 645
1f205a47
UD
646 assert (sym != NULL);
647 /* The condition on the next two lines is a hack around a bug in Solaris
648 tools on Sparc. It's not clear whether it should really be here at all,
649 but if not the binutils need to be changed. */
650 if ((sym->st_shndx != SHN_UNDEF
651 && ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
652 || rinfo == R_PPC_RELATIVE)
653 {
654 /* Has already been relocated. */
655 loadbase = map->l_addr;
656 finaladdr = loadbase + reloc->r_addend;
657 }
658 else
659 {
660 loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version,
661 ELF32_R_TYPE(reloc->r_info)));
662 if (sym == NULL)
663 {
664 /* Weak symbol that wasn't actually defined anywhere. */
665 assert(loadbase == 0);
666 finaladdr = reloc->r_addend;
667 }
668 else
669 finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
670 + reloc->r_addend);
671 }
4cca6b86 672
9a0a462c
UD
673 /* This is still an if/else if chain because GCC uses the GOT to find
674 the table for table-based switch statements, and we haven't set it
675 up yet. */
1f205a47
UD
676 if (rinfo == R_PPC_UADDR32 ||
677 rinfo == R_PPC_GLOB_DAT ||
678 rinfo == R_PPC_ADDR32 ||
679 rinfo == R_PPC_RELATIVE)
680 {
681 *reloc_addr = finaladdr;
682 }
9a0a462c 683#ifndef RTLD_BOOTSTRAP
1f205a47
UD
684 else if (rinfo == R_PPC_ADDR16_LO)
685 {
686 *(Elf32_Half*) reloc_addr = finaladdr;
687 }
688 else if (rinfo == R_PPC_ADDR16_HI)
689 {
690 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
691 }
692 else if (rinfo == R_PPC_ADDR16_HA)
693 {
694 *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
695 }
1f205a47
UD
696 else if (rinfo == R_PPC_REL24)
697 {
698 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
699 if (delta << 6 >> 6 != delta)
700 {
701 _dl_signal_error(0, map->l_name,
702 "R_PPC_REL24 relocation out of range");
703 }
704 *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
705 }
706 else if (rinfo == R_PPC_ADDR24)
707 {
708 if (finaladdr << 6 >> 6 != finaladdr)
709 {
710 _dl_signal_error(0, map->l_name,
711 "R_PPC_ADDR24 relocation out of range");
712 }
713 *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
714 }
715 else if (rinfo == R_PPC_COPY)
716 {
5107cf1d
UD
717 if (sym == NULL)
718 /* This can happen in trace mode when an object could not be
719 found. */
720 return;
cf29ffbe
UD
721 if (sym->st_size > refsym->st_size
722 || (_dl_verbose && sym->st_size < refsym->st_size))
1f205a47
UD
723 {
724 const char *strtab;
5929563f 725
1f205a47
UD
726 strtab = ((void *) map->l_addr
727 + map->l_info[DT_STRTAB]->d_un.d_ptr);
60c96635
UD
728 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
729 ": Symbol `", strtab + refsym->st_name,
1f205a47
UD
730 "' has different size in shared object, "
731 "consider re-linking\n", NULL);
732 }
733 memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
734 refsym->st_size));
735 }
736#endif
737 else if (rinfo == R_PPC_REL32)
738 {
739 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
740 }
741 else if (rinfo == R_PPC_JMP_SLOT)
742 {
af6f3906 743 elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
1f205a47
UD
744 }
745 else
0413b54c
UD
746 {
747#ifdef RTLD_BOOTSTRAP
748 PPC_DIE; /* There is no point calling _dl_sysdep_error, it
749 almost certainly hasn't been relocated properly. */
750#else
751 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
752 ": Unknown relocation type\n", NULL);
753#endif
754 }
1f205a47 755
9a0a462c 756#ifndef RTLD_BOOTSTRAP
1f205a47
UD
757 if (rinfo == R_PPC_ADDR16_LO ||
758 rinfo == R_PPC_ADDR16_HI ||
759 rinfo == R_PPC_ADDR16_HA ||
760 rinfo == R_PPC_REL24 ||
761 rinfo == R_PPC_ADDR24)
762 MODIFIED_CODE_NOQUEUE (reloc_addr);
9a0a462c 763#endif
1f205a47
UD
764}
765
766#define ELF_MACHINE_NO_REL 1
767
650425ce 768#endif /* RESOLVE */