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