1 /* Machine-dependent ELF dynamic relocation functions. PowerPC version.
2 Copyright (C) 1995, 1996, 1997, 1998 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. */
22 #include <sys/param.h>
24 #include <dl-machine.h>
25 #include <elf/ldsodefs.h>
26 #include <elf/dynamic-link.h>
28 /* Because ld.so is now versioned, these functions can be in their own file;
29 no relocations need to be done to call them.
30 Of course, if ld.so is not versioned... */
31 #if !(DO_VERSIONING - 0)
32 #error This will not work with versioning turned off, sorry.
36 /* stuff for the PLT */
37 #define PLT_INITIAL_ENTRY_WORDS 18
38 #define PLT_LONGBRANCH_ENTRY_WORDS 10
39 #define PLT_DOUBLE_SIZE (1<<13)
40 #define PLT_ENTRY_START_WORDS(entry_number) \
41 (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2 + \
42 ((entry_number) > PLT_DOUBLE_SIZE ? \
43 ((entry_number) - PLT_DOUBLE_SIZE)*2 : \
45 #define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
47 #define OPCODE_ADDI(rd,ra,simm) \
48 (0x38000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
49 #define OPCODE_ADDIS(rd,ra,simm) \
50 (0x3c000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff)
51 #define OPCODE_ADD(rd,ra,rb) \
52 (0x7c000214 | (rd) << 21 | (ra) << 16 | (rb) << 11)
53 #define OPCODE_B(target) (0x48000000 | (target) & 0x03fffffc)
54 #define OPCODE_BA(target) (0x48000002 | (target) & 0x03fffffc)
55 #define OPCODE_BCTR() 0x4e800420
56 #define OPCODE_LWZ(rd,d,ra) \
57 (0x80000000 | (rd) << 21 | (ra) << 16 | (d) & 0xffff)
58 #define OPCODE_MTCTR(rd) (0x7C0903A6 | (rd) << 21)
59 #define OPCODE_RLWINM(ra,rs,sh,mb,me) \
60 (0x54000000 | (rs) << 21 | (ra) << 16 | (sh) << 11 | (mb) << 6 | (me) << 1)
62 #define OPCODE_LI(rd,simm) OPCODE_ADDI(rd,0,simm)
63 #define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh)
66 #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where))
67 #define PPC_SYNC asm volatile ("sync")
68 #define PPC_ISYNC asm volatile ("sync; isync")
69 #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where))
70 #define PPC_DIE asm volatile ("tweq 0,0")
72 /* Use this when you've modified some code, but it won't be in the
73 instruction fetch queue (or when it doesn't matter if it is). */
74 #define MODIFIED_CODE_NOQUEUE(where) \
75 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0)
76 /* Use this when it might be in the instruction queue. */
77 #define MODIFIED_CODE(where) \
78 do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0)
81 /* The idea here is that to conform to the ABI, we are supposed to try
82 to load dynamic objects between 0x10000 (we actually use 0x40000 as
83 the lower bound, to increase the chance of a memory reference from
84 a null pointer giving a segfault) and the program's load address;
85 this may allow us to use a branch instruction in the PLT rather
86 than a computed jump. The address is only used as a preference for
87 mmap, so if we get it wrong the worst that happens is that it gets
88 mapped somewhere else. */
91 __elf_preferred_address(struct link_map *loader, size_t maplength,
92 ElfW(Addr) mapstartpref)
97 /* If the object has a preference, load it there! */
98 if (mapstartpref != 0)
101 /* Otherwise, quickly look for a suitable gap between 0x3FFFF and
102 0x70000000. 0x3FFFF is so that references off NULL pointers will
103 cause a segfault, 0x70000000 is just paranoia (it should always
104 be superceded by the program's load address). */
107 for (l = _dl_loaded; l; l = l->l_next)
109 ElfW(Addr) mapstart, mapend;
110 mapstart = l->l_map_start & ~(_dl_pagesize - 1);
111 mapend = l->l_map_end | (_dl_pagesize - 1);
112 assert (mapend > mapstart);
114 if (mapend >= high && high >= mapstart)
116 else if (mapend >= low && low >= mapstart)
118 else if (high >= mapend && mapstart >= low)
120 if (high - mapend >= mapstart - low)
127 high -= 0x10000; /* Allow some room between objects. */
128 maplength = (maplength | (_dl_pagesize-1)) + 1;
129 if (high <= low || high - low < maplength )
131 return high - maplength; /* Both high and maplength are page-aligned. */
134 /* Set up the loaded object described by L so its unrelocated PLT
135 entries will jump to the on-demand fixup code in dl-runtime.c.
136 Also install a small trampoline to be used by entries that have
137 been relocated to an address too far away for a single branch. */
139 /* A PLT entry does one of three things:
140 (i) Jumps to the actual routine. Such entries are set up above, in
143 (ii) Jumps to the actual routine via glue at the start of the PLT.
144 We do this by putting the address of the routine in space
145 allocated at the end of the PLT, and when the PLT entry is
146 called we load the offset of that word (from the start of the
147 space) into r11, then call the glue, which loads the word and
148 branches to that address. These entries are set up in
149 elf_machine_rela, but the glue is set up here.
151 (iii) Loads the index of this PLT entry (we count the double-size
152 entries as one entry for this purpose) into r11, then
153 branches to code at the start of the PLT. This code then
154 calls `fixup', in dl-runtime.c, via the glue in the macro
155 ELF_MACHINE_RUNTIME_TRAMPOLINE, which resets the PLT entry to
156 be one of the above two types. These entries are set up here. */
158 __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
160 if (map->l_info[DT_JMPREL])
163 /* Fill in the PLT. Its initial contents are directed to a
164 function earlier in the PLT which arranges for the dynamic
165 linker to be called back. */
166 Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr
167 + map->l_info[DT_PLTGOT]->d_un.d_val);
168 Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
169 / sizeof (Elf32_Rela));
170 Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
171 Elf32_Word size_modified;
172 extern void _dl_runtime_resolve (void);
173 extern void _dl_prof_resolve (void);
176 dlrr = (Elf32_Word)(char *)(profile
178 : _dl_runtime_resolve);
181 for (i = 0; i < num_plt_entries; i++)
183 Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
185 if (i >= PLT_DOUBLE_SIZE)
187 plt[offset ] = OPCODE_LI (11, i * 4);
188 plt[offset+1] = OPCODE_ADDIS (11, 11, (i * 4 + 0x8000) >> 16);
189 plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
193 plt[offset ] = OPCODE_LI (11, i * 4);
194 plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
198 /* Multiply index of entry by 3 (in r11). */
199 plt[0] = OPCODE_SLWI (12, 11, 1);
200 plt[1] = OPCODE_ADD (11, 12, 11);
201 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
203 /* Load address of link map in r12. */
204 plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
205 plt[3] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
208 /* Call _dl_runtime_resolve. */
209 plt[4] = OPCODE_BA (dlrr);
213 /* Get address of _dl_runtime_resolve in CTR. */
214 plt[2] = OPCODE_LI (12, dlrr);
215 plt[3] = OPCODE_ADDIS (12, 12, (dlrr + 0x8000) >> 16);
216 plt[4] = OPCODE_MTCTR (12);
218 /* Load address of link map in r12. */
219 plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
220 plt[6] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
223 /* Call _dl_runtime_resolve. */
224 plt[7] = OPCODE_BCTR ();
228 /* Convert the index in r11 into an actual address, and get the
229 word at that address. */
230 plt[PLT_LONGBRANCH_ENTRY_WORDS] =
231 OPCODE_ADDIS (11, 11, (((Elf32_Word) (char*) (plt + rel_offset_words)
233 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
234 OPCODE_LWZ (11, (Elf32_Word) (char*) (plt+rel_offset_words), 11);
236 /* Call the procedure at that address. */
237 plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11);
238 plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR ();
241 /* Now, we've modified code (quite a lot of code, possibly). We
242 need to write the changes from the data cache to a
243 second-level unified cache, then make sure that stale data in
244 the instruction cache is removed. (In a multiprocessor
245 system, the effect is more complex.)
247 Assumes the cache line size is at least 32 bytes, or at least
248 that dcbst and icbi apply to 32-byte lines. At present, all
249 PowerPC processors have line sizes of exactly 32 bytes. */
251 size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
252 for (i = 0; i < size_modified; i+=8)
255 for (i = 0; i < size_modified; i+=8)
264 __elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
265 Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
267 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
268 if (delta << 6 >> 6 == delta)
269 *reloc_addr = OPCODE_B (delta);
270 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
271 *reloc_addr = OPCODE_BA (finaladdr);
277 plt = (Elf32_Word *)((char *)map->l_addr
278 + map->l_info[DT_PLTGOT]->d_un.d_val);
279 index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
280 if (index >= PLT_DOUBLE_SIZE)
282 /* Slots greater than or equal to 2^13 have 4 words available
284 /* FIXME: There are some possible race conditions in this code,
285 when called from 'fixup'.
287 1) Suppose that a lazy PLT entry is executing, a context switch
288 between threads (or a signal) occurs, and the new thread or
289 signal handler calls the same lazy PLT entry. Then the PLT entry
290 would be changed while it's being run, which will cause a segfault
293 2) Suppose the reverse: that a lazy PLT entry is being updated,
294 a context switch occurs, and the new code calls the lazy PLT
295 entry that is being updated. Then the half-fixed PLT entry will
296 be executed, which will also almost always cause a segfault.
298 These problems don't happen with the 2-word entries, because
299 only one of the two instructions are changed when a lazy entry
300 is retargeted at the actual PLT entry; the li instruction stays
301 the same (we have to update it anyway, because we might not be
302 updating a lazy PLT entry). */
304 reloc_addr[0] = OPCODE_LI (11, finaladdr);
305 reloc_addr[1] = OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16);
306 reloc_addr[2] = OPCODE_MTCTR (11);
307 reloc_addr[3] = OPCODE_BCTR ();
311 Elf32_Word num_plt_entries;
313 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
314 / sizeof(Elf32_Rela));
316 plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
317 reloc_addr[0] = OPCODE_LI (11, index*4);
318 reloc_addr[1] = OPCODE_B (-(4*(index*2
320 - PLT_LONGBRANCH_ENTRY_WORDS
321 + PLT_INITIAL_ENTRY_WORDS)));
324 MODIFIED_CODE (reloc_addr);
328 __process_machine_rela (struct link_map *map,
329 const Elf32_Rela *reloc,
330 const Elf32_Sym *sym,
331 const Elf32_Sym *refsym,
332 Elf32_Addr *const reloc_addr,
333 Elf32_Addr const finaladdr,
345 *reloc_addr = finaladdr;
349 if (finaladdr > 0x01fffffc && finaladdr < 0xfe000000)
351 _dl_signal_error(0, map->l_name,
352 "R_PPC_ADDR24 relocation out of range");
354 *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
359 if (finaladdr > 0x7fff && finaladdr < 0x8000)
361 _dl_signal_error(0, map->l_name,
362 "R_PPC_ADDR16 relocation out of range");
364 *(Elf32_Half*) reloc_addr = finaladdr;
367 case R_PPC_ADDR16_LO:
368 *(Elf32_Half*) reloc_addr = finaladdr;
371 case R_PPC_ADDR16_HI:
372 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
375 case R_PPC_ADDR16_HA:
376 *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
380 case R_PPC_ADDR14_BRTAKEN:
381 case R_PPC_ADDR14_BRNTAKEN:
382 if (finaladdr > 0x7fff && finaladdr < 0x8000)
384 _dl_signal_error(0, map->l_name,
385 "R_PPC_ADDR14 relocation out of range");
387 *reloc_addr = *reloc_addr & 0xffff0003 | finaladdr & 0xfffc;
388 if (rinfo != R_PPC_ADDR14)
389 *reloc_addr = (*reloc_addr & 0xffdfffff
390 | (rinfo == R_PPC_ADDR14_BRTAKEN
391 ^ finaladdr >> 31) << 21);
396 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
397 if (delta << 6 >> 6 != delta)
399 _dl_signal_error(0, map->l_name,
400 "R_PPC_REL24 relocation out of range");
402 *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
408 /* This can happen in trace mode when an object could not be
411 if (sym->st_size > refsym->st_size
412 || (_dl_verbose && sym->st_size < refsym->st_size))
416 strtab = ((void *) map->l_addr
417 + map->l_info[DT_STRTAB]->d_un.d_ptr);
418 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
419 ": Symbol `", strtab + refsym->st_name,
420 "' has different size in shared object, "
421 "consider re-linking\n", NULL);
423 memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
428 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
432 elf_machine_fixup_plt(map, reloc, reloc_addr, finaladdr);
436 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
437 ": Unknown relocation type\n", NULL);
441 MODIFIED_CODE_NOQUEUE (reloc_addr);