Update.
[glibc.git] / sysdeps / powerpc / dl-machine.h
blob526887da18c566937332e8680f1f6f52d373937e
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.
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.
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.
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. */
20 #define ELF_MACHINE_NAME "powerpc"
22 #include <assert.h>
23 #include <string.h>
24 #include <link.h>
26 /* stuff for the PLT */
27 #define PLT_INITIAL_ENTRY_WORDS 18
28 #define PLT_LONGBRANCH_ENTRY_WORDS 10
29 #define PLT_DOUBLE_SIZE (1<<13)
30 #define PLT_ENTRY_START_WORDS(entry_number) \
31 (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2 + \
32 ((entry_number) > PLT_DOUBLE_SIZE ? \
33 ((entry_number) - PLT_DOUBLE_SIZE)*2 : \
34 0))
35 #define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
37 #define OPCODE_ADDI(rd,ra,simm) \
38 (0x38000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
39 #define OPCODE_ADDIS(rd,ra,simm) \
40 (0x3c000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
41 #define OPCODE_ADD(rd,ra,rb) \
42 (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
43 #define OPCODE_B(target) (0x48000000 | (target) & 0x03fffffc)
44 #define OPCODE_BA(target) (0x48000002 | (target) & 0x03fffffc)
45 #define OPCODE_BCTR() 0x4e800420
46 #define OPCODE_LWZ(rd,d,ra) \
47 (0x80000000 | (rd) << 21 | (ra) << 16 | (d) & 0xffff)
48 #define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
49 #define OPCODE_RLWINM(ra,rs,sh,mb,me) \
50 (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
52 #define OPCODE_LI(rd,simm) OPCODE_ADDI(rd,0,simm)
53 #define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
55 #define PPC_DCBST(where) asm __volatile__ ("dcbst 0,%0" : : "r"(where))
56 #define PPC_SYNC asm __volatile__ ("sync")
57 #define PPC_ISYNC asm __volatile__ ("sync; isync")
58 #define PPC_ICBI(where) asm __volatile__ ("icbi 0,%0" : : "r"(where))
60 /* Use this when you've modified some code, but it won't be in the
61 instruction fetch queue (or when it doesn't matter if it is). */
62 #define MODIFIED_CODE_NOQUEUE(where) \
63 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
64 /* Use this when it might be in the instruction queue. */
65 #define MODIFIED_CODE(where) \
66 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
69 /* Return nonzero iff E_MACHINE is compatible with the running host. */
70 static inline int
71 elf_machine_matches_host (Elf32_Half e_machine)
73 return e_machine == EM_PPC;
77 /* Return the link-time address of _DYNAMIC, stored as
78 the first value in the GOT. */
79 static inline Elf32_Addr
80 elf_machine_dynamic (void)
82 Elf32_Addr *got;
83 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
84 : "=l"(got));
85 return *got;
88 /* Return the run-time load address of the shared object. */
89 static inline Elf32_Addr
90 elf_machine_load_address (void)
92 unsigned *got;
93 unsigned *branchaddr;
95 /* This is much harder than you'd expect. Possibly I'm missing something.
96 The 'obvious' way:
98 Apparently, "bcl 20,31,$+4" is what should be used to load LR
99 with the address of the next instruction.
100 I think this is so that machines that do bl/blr pairing don't
101 get confused.
103 asm ("bcl 20,31,0f ;"
104 "0: mflr 0 ;"
105 "lis %0,0b@ha;"
106 "addi %0,%0,0b@l;"
107 "subf %0,%0,0"
108 : "=b" (addr) : : "r0", "lr");
110 doesn't work, because the linker doesn't have to (and in fact doesn't)
111 update the @ha and @l references; the loader (which runs after this
112 code) will do that.
114 Instead, we use the following trick:
116 The linker puts the _link-time_ address of _DYNAMIC at the first
117 word in the GOT. We could branch to that address, if we wanted,
118 by using an @local reloc; the linker works this out, so it's safe
119 to use now. We can't, of course, actually branch there, because
120 we'd cause an illegal instruction exception; so we need to compute
121 the address ourselves. That gives us the following code: */
123 /* Get address of the 'b _DYNAMIC@local'... */
124 asm ("bl 0f ;"
125 "b _DYNAMIC@local;"
126 "0:"
127 : "=l"(branchaddr));
129 /* ... and the address of the GOT. */
130 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
131 : "=l"(got));
133 /* So now work out the difference between where the branch actually points,
134 and the offset of that location in memory from the start of the file. */
135 return (Elf32_Addr)branchaddr - *got +
136 (*branchaddr & 0x3fffffc |
137 (int)(*branchaddr << 6 & 0x80000000) >> 6);
140 #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
142 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
143 LOADADDR is the load address of the object; INFO is an array indexed
144 by DT_* of the .dynamic section info. */
146 #ifdef RESOLVE
148 static inline void
149 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
150 const Elf32_Sym *sym, const struct r_found_version *version)
152 Elf32_Addr *const reloc_addr = (Elf32_Addr *)(map->l_addr + reloc->r_offset);
153 Elf32_Word loadbase, finaladdr;
154 const int rinfo = ELF32_R_TYPE (reloc->r_info);
156 if (rinfo == R_PPC_NONE)
157 return;
159 assert (sym != NULL);
160 if (ELF32_ST_TYPE (sym->st_info) == STT_SECTION ||
161 rinfo == R_PPC_RELATIVE)
163 /* Has already been relocated. */
164 loadbase = map->l_addr;
165 finaladdr = loadbase + reloc->r_addend;
167 else
169 int flags;
171 /* We never want to use a PLT entry as the destination of a
172 reloc, when what is being relocated is a branch. This is
173 partly for efficiency, but mostly so we avoid loops. */
174 if (rinfo == R_PPC_REL24 ||
175 rinfo == R_PPC_ADDR24 ||
176 rinfo == R_PPC_JMP_SLOT)
177 flags = DL_LOOKUP_NOPLT;
178 else if (rinfo == R_PPC_COPY)
179 flags = DL_LOOKUP_NOEXEC;
180 else
181 flags = 0;
183 loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version, flags));
184 if (sym == NULL)
186 /* Weak symbol that wasn't actually defined anywhere. */
187 assert(loadbase == 0);
188 finaladdr = reloc->r_addend;
190 else
191 finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value +
192 reloc->r_addend);
195 /* This is an if/else if chain because GCC 2.7.2.[012] turns case
196 statements into non-PIC table lookups. When a later version
197 comes out that fixes this, this should be changed. */
198 if (rinfo == R_PPC_ADDR16_LO)
200 *(Elf32_Half*) reloc_addr = finaladdr;
202 else if (rinfo == R_PPC_ADDR16_HI)
204 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
206 else if (rinfo == R_PPC_ADDR16_HA)
208 *(Elf32_Half*) reloc_addr = finaladdr + 0x8000 >> 16;
210 else if (rinfo == R_PPC_REL24)
212 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
213 assert (delta << 6 >> 6 == delta);
214 *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
216 else if (rinfo == R_PPC_UADDR32 ||
217 rinfo == R_PPC_GLOB_DAT ||
218 rinfo == R_PPC_ADDR32 ||
219 rinfo == R_PPC_RELATIVE)
221 *reloc_addr = finaladdr;
223 else if (rinfo == R_PPC_ADDR24)
225 assert (finaladdr << 6 >> 6 == finaladdr);
226 *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
228 else if (rinfo == R_PPC_COPY)
230 /* Memcpy is safe to use here, because ld.so doesn't have any
231 COPY relocs (it's self-contained). */
232 memcpy (reloc_addr, (char *) finaladdr, sym->st_size);
234 else if (rinfo == R_PPC_REL32)
236 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
238 else if (rinfo == R_PPC_JMP_SLOT)
240 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
241 if (delta << 6 >> 6 == delta)
242 *reloc_addr = OPCODE_B(delta);
243 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
244 *reloc_addr = OPCODE_BA(finaladdr);
245 else
247 Elf32_Word *plt = (Elf32_Word *)((char *)map->l_addr +
248 map->l_info[DT_PLTGOT]->d_un.d_val);
249 Elf32_Word index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
250 Elf32_Word offset = index * 2 + PLT_INITIAL_ENTRY_WORDS;
252 if (index >= PLT_DOUBLE_SIZE)
254 /* Slots greater than or equal to 2^13 have 4 words
255 available instead of two. */
256 plt[offset ] = OPCODE_LI (11,finaladdr);
257 plt[offset+1] = OPCODE_ADDIS (11,11,finaladdr + 0x8000 >> 16);
258 plt[offset+2] = OPCODE_MTCTR (11);
259 plt[offset+3] = OPCODE_BCTR ();
261 else
263 Elf32_Word num_plt_entries;
264 Elf32_Word rel_offset_words;
266 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
267 / sizeof(Elf32_Rela));
268 rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
270 plt[offset ] = OPCODE_LI (11,index * 4);
271 plt[offset+1] = OPCODE_B (-(4 * (offset + 1
272 - PLT_LONGBRANCH_ENTRY_WORDS)));
273 plt[index + rel_offset_words] = finaladdr;
276 MODIFIED_CODE(reloc_addr);
278 else
279 assert (! "unexpected dynamic reloc type");
281 if (rinfo == R_PPC_ADDR16_LO ||
282 rinfo == R_PPC_ADDR16_HI ||
283 rinfo == R_PPC_ADDR16_HA ||
284 rinfo == R_PPC_REL24 ||
285 rinfo == R_PPC_ADDR24)
286 MODIFIED_CODE_NOQUEUE (reloc_addr);
289 #define ELF_MACHINE_NO_REL 1
291 #endif
293 /* Nonzero iff TYPE describes relocation of a PLT entry, so
294 PLT entries should not be allowed to define the value. */
295 #define elf_machine_pltrel_p(type) ((type) == R_PPC_JMP_SLOT)
297 /* Set up the loaded object described by L so its unrelocated PLT
298 entries will jump to the on-demand fixup code in dl-runtime.c. */
299 static inline void
300 elf_machine_runtime_setup (struct link_map *map, int lazy)
302 if (map->l_info[DT_JMPREL])
304 int i;
305 /* Fill in the PLT. Its initial contents are directed to a
306 function earlier in the PLT which arranges for the dynamic
307 linker to be called back. */
308 Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr
309 + map->l_info[DT_PLTGOT]->d_un.d_val);
310 Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
311 / sizeof (Elf32_Rela));
312 Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
313 extern void _dl_runtime_resolve (void);
314 Elf32_Word size_modified;
316 if (lazy)
317 for (i = 0; i < num_plt_entries; i++)
319 Elf32_Word offset = PLT_ENTRY_START_WORDS(i);
321 if (i >= PLT_DOUBLE_SIZE)
323 plt[offset ] = OPCODE_LI (11, i * 4);
324 plt[offset+1] = OPCODE_ADDIS (11, 11, i * 4 + 0x8000 >> 16);
325 plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
327 else
329 plt[offset ] = OPCODE_LI (11, i * 4);
330 plt[offset+1] = OPCODE_B(-(4 * (offset + 1)));
333 /* Multiply index of entry, by 0xC. */
334 plt[0] = OPCODE_SLWI (12, 11, 1);
335 plt[1] = OPCODE_ADD (11, 12, 11);
336 if ((Elf32_Word) (char *) _dl_runtime_resolve <= 0x01fffffc
337 || (Elf32_Word) (char *) _dl_runtime_resolve >= 0xfe000000)
339 plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
340 plt[3] = OPCODE_ADDIS (12, 12,
341 (Elf32_Word) (char *) map + 0x8000 >> 16);
342 plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve);
345 else
347 plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) _dl_runtime_resolve);
348 plt[3] = OPCODE_ADDIS(12, 12, 0x8000 +
349 ((Elf32_Word) (char *) _dl_runtime_resolve
350 >> 16));
351 plt[4] = OPCODE_MTCTR (12);
352 plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
353 plt[6] = OPCODE_ADDIS (12, 12, ((Elf32_Word) (char *) map
354 + 0x8000 >> 16));
355 plt[7] = OPCODE_BCTR ();
357 plt[PLT_LONGBRANCH_ENTRY_WORDS] =
358 OPCODE_ADDIS (11, 11, (Elf32_Word) (char*) (plt + rel_offset_words)
359 + 0x8000 >> 16);
360 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
361 OPCODE_LWZ(11,(Elf32_Word)(char*)(plt+rel_offset_words),11);
362 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11);
363 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR ();
365 size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
366 /* Now we need to keep the caches in sync. */
367 for (i = 0; i < size_modified; i+=8)
368 PPC_DCBST (plt + i);
369 PPC_SYNC;
370 for (i = 0; i < size_modified; i+=8)
371 PPC_ICBI (plt + i);
372 PPC_ISYNC;
376 static inline void
377 elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
379 assert (ELF32_R_TYPE (reloc->r_info) == R_PPC_JMP_SLOT);
380 /* elf_machine_runtime_setup handles this. */
383 /* The PLT uses Elf32_Rela relocs. */
384 #define elf_machine_relplt elf_machine_rela
386 /* This code is used in dl-runtime.c to call the `fixup' function
387 and then redirect to the address it returns. It is called
388 from code built in the PLT by elf_machine_runtime_setup. */
389 #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
390 .section \".text\"
391 .align 2
392 .globl _dl_runtime_resolve
393 .type _dl_runtime_resolve,@function
394 _dl_runtime_resolve:
395 # We need to save the registers used to pass parameters.
396 # We build a stack frame to put them in.
397 stwu 1,-48(1)
398 mflr 0
399 stw 3,16(1)
400 stw 4,20(1)
401 stw 0,52(1)
402 stw 5,24(1)
403 # We also need to save some of the condition register fields.
404 mfcr 0
405 stw 6,28(1)
406 stw 7,32(1)
407 stw 8,36(1)
408 stw 9,40(1)
409 stw 10,44(1)
410 stw 0,12(1)
411 # The code that calls this has put parameters for `fixup' in r12 and r11.
412 mr 3,12
413 mr 4,11
414 bl fixup
415 # 'fixup' returns the address we want to branch to.
416 mtctr 3
417 # Put the registers back...
418 lwz 0,52(1)
419 lwz 10,44(1)
420 lwz 9,40(1)
421 mtlr 0
422 lwz 0,12(1)
423 lwz 8,36(1)
424 lwz 7,32(1)
425 lwz 6,28(1)
426 mtcrf 0xFF,0
427 lwz 5,24(1)
428 lwz 4,20(1)
429 lwz 3,16(1)
430 # ...unwind the stack frame, and jump to the PLT entry we updated.
431 addi 1,1,48
432 bctr
434 .size _dl_runtime_resolve,0b-_dl_runtime_resolve
435 # undo '.section text'.
436 .previous
439 /* Initial entry point code for the dynamic linker.
440 The C function `_dl_start' is the real entry point;
441 its return value is the user program's entry point. */
442 #define RTLD_START \
443 asm ("\
444 .text
445 .align 2
446 .globl _start
447 .type _start,@function
448 _start:
449 # We start with the following on the stack, from top:
450 # argc (4 bytes)
451 # arguments for program (terminated by NULL)
452 # environment variables (terminated by NULL)
453 # arguments for the program loader
454 # FIXME: perhaps this should do the same trick as elf/start.c?
456 # Call _dl_start with one parameter pointing at argc
457 mr 3,1
458 # (we have to frob the stack pointer a bit to allow room for
459 # _dl_start to save the link register)
460 li 4,0
461 addi 1,1,-16
462 stw 4,0(1)
463 bl _dl_start@local
465 # Now, we do our main work of calling initialisation procedures.
466 # The ELF ABI doesn't say anything about parameters for these,
467 # so we just pass argc, argv, and the environment.
468 # Changing these is strongly discouraged (not least because argc is
469 # passed by value!).
471 # put our GOT pointer in r31
472 bl _GLOBAL_OFFSET_TABLE_-4@local
473 mflr 31
474 # the address of _start in r30
475 mr 30,3
476 # &_dl_argc in 29, &_dl_argv in 27, and _dl_default_scope in 28
477 lwz 28,_dl_default_scope@got(31)
478 lwz 29,_dl_argc@got(31)
479 lwz 27,_dl_argv@got(31)
481 # call initfunc = _dl_init_next(_dl_default_scope[2])
482 lwz 3,8(28)
483 bl _dl_init_next@plt
484 # if initfunc is NULL, we exit the loop
485 mr. 0,3
486 beq 1f
487 # call initfunc(_dl_argc, _dl_argv, _dl_argv+_dl_argc+1)
488 mtlr 0
489 lwz 3,0(29)
490 lwz 4,0(27)
491 slwi 5,3,2
492 add 5,4,5
493 addi 5,5,4
494 blrl
495 # and loop.
496 b 0b
498 # Now, to conform to the ELF ABI, we have to:
499 # pass argv (actually _dl_argv) in r4
500 lwz 4,0(27)
501 # pass argc (actually _dl_argc) in r3
502 lwz 3,0(29)
503 # pass envp (actually _dl_argv+_dl_argc+1) in r5
504 slwi 5,3,2
505 add 5,4,5
506 addi 5,5,4
507 # pass the auxilary vector in r6. This is passed just after _envp.
508 addi 6,5,-4
509 2: lwzu 0,4(6)
510 cmpwi 1,0,0
511 bne 2b
512 addi 6,6,4
513 # pass a termination function pointer (in this case _dl_fini) in r7
514 lwz 7,_dl_fini@got(31)
515 # now, call the start function in r30...
516 mtctr 30
517 # pass the stack pointer in r1 (so far so good), pointing to a NULL value
518 # (this lets our startup code distinguish between a program linked statically,
519 # which linux will call with argc on top of the stack which will hopefully
520 # never be zero, and a dynamically linked program which will always have
521 # a NULL on the top of the stack).
522 # Take the opportunity to clear LR, so anyone who accidentally returns
523 # from _start gets SEGV.
524 li 0,0
525 stw 0,0(1)
526 mtlr 0
527 # and also clear _dl_starting_up
528 lwz 26,_dl_starting_up@got(31)
529 stw 0,0(26)
530 # go do it!
531 bctr
533 .size _start,0b-_start
534 # undo '.section text'.
535 .previous
538 #define ELF_PREFERRED_ADDRESS_DATA \
539 static ElfW(Addr) _dl_preferred_address = 0;
541 #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
542 ( { \
543 ElfW(Addr) prefd; \
544 if (mapstartpref != 0 && _dl_preferred_address == 0) \
545 _dl_preferred_address = mapstartpref; \
546 if (mapstartpref != 0) \
547 prefd = mapstartpref; \
548 else if (_dl_preferred_address < maplength + 0x50000) \
549 prefd = 0; \
550 else \
551 prefd = _dl_preferred_address = \
552 ((_dl_preferred_address - maplength - 0x10000) \
553 & ~(_dl_pagesize - 1)); \
554 prefd; \
557 #define ELF_FIXED_ADDRESS(loader, mapstart) \
558 ( { \
559 if (mapstart != 0 && _dl_preferred_address < mapstart) \
560 _dl_preferred_address = mapstart; \
563 #define ELF_FIXUP_RETURNS_ADDRESS 1