]> 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. */
4cca6b86
UD
393static inline void
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
UD
491 }
492}
493
494static inline void
495elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
496{
e61abf83 497 assert (ELF32_R_TYPE (reloc->r_info) == R_PPC_JMP_SLOT);
4cca6b86
UD
498 /* elf_machine_runtime_setup handles this. */
499}
500
1f205a47 501#endif /* dl_machine_h */
4cca6b86 502
1f205a47 503#ifdef RESOLVE
4cca6b86 504
1f205a47
UD
505/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
506 LOADADDR is the load address of the object; INFO is an array indexed
507 by DT_* of the .dynamic section info. */
4cca6b86 508
1f205a47
UD
509static inline void
510elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
511 const Elf32_Sym *sym, const struct r_found_version *version)
512{
513 const Elf32_Sym *const refsym = sym;
514 Elf32_Addr *const reloc_addr = (Elf32_Addr *)(map->l_addr + reloc->r_offset);
515 Elf32_Word loadbase, finaladdr;
516 const int rinfo = ELF32_R_TYPE (reloc->r_info);
4cca6b86 517
1f205a47
UD
518 if (rinfo == R_PPC_NONE)
519 return;
4cca6b86 520
1f205a47
UD
521 assert (sym != NULL);
522 /* The condition on the next two lines is a hack around a bug in Solaris
523 tools on Sparc. It's not clear whether it should really be here at all,
524 but if not the binutils need to be changed. */
525 if ((sym->st_shndx != SHN_UNDEF
526 && ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
527 || rinfo == R_PPC_RELATIVE)
528 {
529 /* Has already been relocated. */
530 loadbase = map->l_addr;
531 finaladdr = loadbase + reloc->r_addend;
532 }
533 else
534 {
535 loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version,
536 ELF32_R_TYPE(reloc->r_info)));
537 if (sym == NULL)
538 {
539 /* Weak symbol that wasn't actually defined anywhere. */
540 assert(loadbase == 0);
541 finaladdr = reloc->r_addend;
542 }
543 else
544 finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
545 + reloc->r_addend);
546 }
4cca6b86 547
1f205a47
UD
548 /* This is an if/else if chain because GCC 2.7.2.[012] turns case
549 statements into non-PIC table lookups. When a later version
550 comes out that fixes this, this should be changed. */
551 if (rinfo == R_PPC_UADDR32 ||
552 rinfo == R_PPC_GLOB_DAT ||
553 rinfo == R_PPC_ADDR32 ||
554 rinfo == R_PPC_RELATIVE)
555 {
556 *reloc_addr = finaladdr;
557 }
558 else if (rinfo == R_PPC_ADDR16_LO)
559 {
560 *(Elf32_Half*) reloc_addr = finaladdr;
561 }
562 else if (rinfo == R_PPC_ADDR16_HI)
563 {
564 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
565 }
566 else if (rinfo == R_PPC_ADDR16_HA)
567 {
568 *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
569 }
570#ifndef RTLD_BOOTSTRAP
571 else if (rinfo == R_PPC_REL24)
572 {
573 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
574 if (delta << 6 >> 6 != delta)
575 {
576 _dl_signal_error(0, map->l_name,
577 "R_PPC_REL24 relocation out of range");
578 }
579 *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
580 }
581 else if (rinfo == R_PPC_ADDR24)
582 {
583 if (finaladdr << 6 >> 6 != finaladdr)
584 {
585 _dl_signal_error(0, map->l_name,
586 "R_PPC_ADDR24 relocation out of range");
587 }
588 *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
589 }
590 else if (rinfo == R_PPC_COPY)
591 {
592 if (sym->st_size != refsym->st_size)
593 {
594 const char *strtab;
5929563f 595
1f205a47
UD
596 strtab = ((void *) map->l_addr
597 + map->l_info[DT_STRTAB]->d_un.d_ptr);
598 _dl_sysdep_error ("Symbol `", strtab + refsym->st_name,
599 "' has different size in shared object, "
600 "consider re-linking\n", NULL);
601 }
602 memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
603 refsym->st_size));
604 }
605#endif
606 else if (rinfo == R_PPC_REL32)
607 {
608 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
609 }
610 else if (rinfo == R_PPC_JMP_SLOT)
611 {
612 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
613 if (delta << 6 >> 6 == delta)
614 *reloc_addr = OPCODE_B (delta);
615 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
616 *reloc_addr = OPCODE_BA (finaladdr);
617 else
618 {
619 Elf32_Word *plt;
620 Elf32_Word index;
5929563f 621
1f205a47
UD
622 plt = (Elf32_Word *)((char *)map->l_addr
623 + map->l_info[DT_PLTGOT]->d_un.d_val);
624 index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
e61abf83 625
1f205a47
UD
626 if (index >= PLT_DOUBLE_SIZE)
627 {
628 /* Slots greater than or equal to 2^13 have 4 words available
629 instead of two. */
630 reloc_addr[0] = OPCODE_LI (11, finaladdr);
631 reloc_addr[1] = OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16);
632 reloc_addr[2] = OPCODE_MTCTR (11);
633 reloc_addr[3] = OPCODE_BCTR ();
634 }
635 else
636 {
637 Elf32_Word num_plt_entries;
638
639 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
640 / sizeof(Elf32_Rela));
641
642 reloc_addr[0] = OPCODE_LI (11, index*4);
643 reloc_addr[1] =
644 OPCODE_B (-(4*(index*2
645 + 1
646 - PLT_LONGBRANCH_ENTRY_WORDS
647 + PLT_INITIAL_ENTRY_WORDS)));
648 plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
649 }
650 }
651 MODIFIED_CODE (reloc_addr);
652 }
653 else
654 assert (! "unexpected dynamic reloc type");
655
656 if (rinfo == R_PPC_ADDR16_LO ||
657 rinfo == R_PPC_ADDR16_HI ||
658 rinfo == R_PPC_ADDR16_HA ||
659 rinfo == R_PPC_REL24 ||
660 rinfo == R_PPC_ADDR24)
661 MODIFIED_CODE_NOQUEUE (reloc_addr);
662}
663
664#define ELF_MACHINE_NO_REL 1
665
666#endif
e61abf83 667
4cca6b86 668