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"
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 : \
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. */
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)
83 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
88 /* Return the run-time load address of the shared object. */
89 static inline Elf32_Addr
90 elf_machine_load_address (void)
95 /* This is much harder than you'd expect. Possibly I'm missing something.
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
103 asm ("bcl 20,31,0f ;"
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
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'... */
129 /* ... and the address of the GOT. */
130 asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
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. */
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
)
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
;
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
;
183 loadbase
= (Elf32_Word
) (char *) (RESOLVE (&sym
, version
, flags
));
186 /* Weak symbol that wasn't actually defined anywhere. */
187 assert(loadbase
== 0);
188 finaladdr
= reloc
->r_addend
;
191 finaladdr
= (loadbase
+ (Elf32_Word
) (char *) sym
->st_value
+
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
);
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 ();
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
);
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
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. */
300 elf_machine_runtime_setup (struct link_map
*map
, int lazy
)
302 if (map
->l_info
[DT_JMPREL
])
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
;
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)));
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
);
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
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
355 plt
[7] = OPCODE_BCTR ();
357 plt
[PLT_LONGBRANCH_ENTRY_WORDS
] =
358 OPCODE_ADDIS (11, 11, (Elf32_Word
) (char*) (plt
+ rel_offset_words
)
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)
370 for (i
= 0; i
< size_modified
; i
+=8)
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 ("\
392 .globl _dl_runtime_resolve
393 .type _dl_runtime_resolve,@function
395 # We need to save the registers used to pass parameters.
396 # We build a stack frame to put them in.
403 # We also need to save some of the condition register fields.
411 # The code that calls this has put parameters for `fixup' in r12 and r11.
415 # 'fixup' returns the address we want to branch to.
417 # Put the registers back...
430 # ...unwind the stack frame, and jump to the PLT entry we updated.
434 .size _dl_runtime_resolve,0b-_dl_runtime_resolve
435 # undo '.section text'.
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. */
447 .type _start,@function
449 # We start with the following on the stack, from top:
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
458 # (we have to frob the stack pointer a bit to allow room for
459 # _dl_start to save the link register)
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
471 # put our GOT pointer in r31
472 bl _GLOBAL_OFFSET_TABLE_-4@local
474 # the address of _start in r30
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])
484 # if initfunc is NULL, we exit the loop
487 # call initfunc(_dl_argc, _dl_argv, _dl_argv+_dl_argc+1)
498 # Now, to conform to the ELF ABI, we have to:
499 # pass argv (actually _dl_argv) in r4
501 # pass argc (actually _dl_argc) in r3
503 # pass envp (actually _dl_argv+_dl_argc+1) in r5
507 # pass the auxilary vector in r6. This is passed just after _envp.
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...
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.
527 # and also clear _dl_starting_up
528 lwz 26,_dl_starting_up@got(31)
533 .size _start,0b-_start
534 # undo '.section text'.
538 #define ELF_PREFERRED_ADDRESS_DATA \
539 static ElfW(Addr) _dl_preferred_address = 0;
541 #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
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) \
551 prefd = _dl_preferred_address = \
552 ((_dl_preferred_address - maplength - 0x10000) \
553 & ~(_dl_pagesize - 1)); \
557 #define ELF_FIXED_ADDRESS(loader, mapstart) \
559 if (mapstart != 0 && _dl_preferred_address < mapstart) \
560 _dl_preferred_address = mapstart; \
563 #define ELF_FIXUP_RETURNS_ADDRESS 1