1 /* Machine-dependent ELF dynamic relocation functions. PowerPC version.
2 Copyright (C) 1995, 1996, 1997, 1998, 1999 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 ("dcbst 0,%0" : : "r"(where) : "memory")
67 #define PPC_SYNC asm ("sync" : : : "memory")
68 #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory")
69 #define PPC_ICBI(where) asm ("icbi 0,%0" : : "r"(where) : "memory")
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 *) map->l_info[DT_PLTGOT]->d_un.d_val;
167 Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
168 / sizeof (Elf32_Rela));
169 Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
170 Elf32_Word size_modified;
171 extern void _dl_runtime_resolve (void);
172 extern void _dl_prof_resolve (void);
175 dlrr = (Elf32_Word)(char *)(profile
177 : _dl_runtime_resolve);
180 for (i = 0; i < num_plt_entries; i++)
182 Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
184 if (i >= PLT_DOUBLE_SIZE)
186 plt[offset ] = OPCODE_LI (11, i * 4);
187 plt[offset+1] = OPCODE_ADDIS (11, 11, (i * 4 + 0x8000) >> 16);
188 plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
192 plt[offset ] = OPCODE_LI (11, i * 4);
193 plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
197 /* Multiply index of entry by 3 (in r11). */
198 plt[0] = OPCODE_SLWI (12, 11, 1);
199 plt[1] = OPCODE_ADD (11, 12, 11);
200 if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
202 /* Load address of link map in r12. */
203 plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
204 plt[3] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
207 /* Call _dl_runtime_resolve. */
208 plt[4] = OPCODE_BA (dlrr);
212 /* Get address of _dl_runtime_resolve in CTR. */
213 plt[2] = OPCODE_LI (12, dlrr);
214 plt[3] = OPCODE_ADDIS (12, 12, (dlrr + 0x8000) >> 16);
215 plt[4] = OPCODE_MTCTR (12);
217 /* Load address of link map in r12. */
218 plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
219 plt[6] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
222 /* Call _dl_runtime_resolve. */
223 plt[7] = OPCODE_BCTR ();
227 /* Convert the index in r11 into an actual address, and get the
228 word at that address. */
229 plt[PLT_LONGBRANCH_ENTRY_WORDS] =
230 OPCODE_ADDIS (11, 11, (((Elf32_Word) (char*) (plt + rel_offset_words)
232 plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
233 OPCODE_LWZ (11, (Elf32_Word) (char*) (plt + rel_offset_words), 11);
235 /* Call the procedure at that address. */
236 plt[PLT_LONGBRANCH_ENTRY_WORDS + 2] = OPCODE_MTCTR (11);
237 plt[PLT_LONGBRANCH_ENTRY_WORDS + 3] = OPCODE_BCTR ();
240 /* Now, we've modified code (quite a lot of code, possibly). We
241 need to write the changes from the data cache to a
242 second-level unified cache, then make sure that stale data in
243 the instruction cache is removed. (In a multiprocessor
244 system, the effect is more complex.) Most of the PLT shouldn't
245 be in the instruction cache, but there may be a little overlap
246 at the start and the end.
248 Assumes the cache line size is at least 32 bytes, or at least
249 that dcbst and icbi apply to 32-byte lines. At present, all
250 PowerPC processors have line sizes of exactly 32 bytes. */
252 size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
253 for (i = 0; i < size_modified; i+= 8)
255 PPC_DCBST (plt + size_modified - 1);
258 PPC_ICBI (plt + size_modified-1);
266 __elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
267 Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
269 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
270 if (delta << 6 >> 6 == delta)
271 *reloc_addr = OPCODE_B (delta);
272 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
273 *reloc_addr = OPCODE_BA (finaladdr);
279 plt = (Elf32_Word *) map->l_info[DT_PLTGOT]->d_un.d_val;
280 index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
281 if (index >= PLT_DOUBLE_SIZE)
283 /* Slots greater than or equal to 2^13 have 4 words available
285 /* FIXME: There are some possible race conditions in this code,
286 when called from 'fixup'.
288 1) Suppose that a lazy PLT entry is executing, a context switch
289 between threads (or a signal) occurs, and the new thread or
290 signal handler calls the same lazy PLT entry. Then the PLT entry
291 would be changed while it's being run, which will cause a segfault
294 2) Suppose the reverse: that a lazy PLT entry is being updated,
295 a context switch occurs, and the new code calls the lazy PLT
296 entry that is being updated. Then the half-fixed PLT entry will
297 be executed, which will also almost always cause a segfault.
299 These problems don't happen with the 2-word entries, because
300 only one of the two instructions are changed when a lazy entry
301 is retargeted at the actual PLT entry; the li instruction stays
302 the same (we have to update it anyway, because we might not be
303 updating a lazy PLT entry). */
305 reloc_addr[0] = OPCODE_LI (11, finaladdr);
306 reloc_addr[1] = OPCODE_ADDIS (11, 11, (finaladdr + 0x8000) >> 16);
307 reloc_addr[2] = OPCODE_MTCTR (11);
308 reloc_addr[3] = OPCODE_BCTR ();
312 Elf32_Word num_plt_entries;
314 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
315 / sizeof(Elf32_Rela));
317 plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
318 reloc_addr[0] = OPCODE_LI (11, index*4);
319 reloc_addr[1] = OPCODE_B (-(4*(index*2
321 - PLT_LONGBRANCH_ENTRY_WORDS
322 + PLT_INITIAL_ENTRY_WORDS)));
323 reloc_addr += 1; /* This is the modified address. */
326 MODIFIED_CODE (reloc_addr);
330 __process_machine_rela (struct link_map *map,
331 const Elf32_Rela *reloc,
332 const Elf32_Sym *sym,
333 const Elf32_Sym *refsym,
334 Elf32_Addr *const reloc_addr,
335 Elf32_Addr const finaladdr,
347 *reloc_addr = finaladdr;
351 if (finaladdr > 0x01fffffc && finaladdr < 0xfe000000)
352 _dl_signal_error (0, map->l_name,
353 "R_PPC_ADDR24 relocation out of range");
354 *reloc_addr = (*reloc_addr & 0xfc000003) | (finaladdr & 0x3fffffc);
359 if (finaladdr > 0x7fff && finaladdr < 0x8000)
360 _dl_signal_error (0, map->l_name,
361 "R_PPC_ADDR16 relocation out of range");
362 *(Elf32_Half*) reloc_addr = finaladdr;
365 case R_PPC_ADDR16_LO:
366 *(Elf32_Half*) reloc_addr = finaladdr;
369 case R_PPC_ADDR16_HI:
370 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
373 case R_PPC_ADDR16_HA:
374 *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
378 case R_PPC_ADDR14_BRTAKEN:
379 case R_PPC_ADDR14_BRNTAKEN:
380 if (finaladdr > 0x7fff && finaladdr < 0x8000)
381 _dl_signal_error (0, map->l_name,
382 "R_PPC_ADDR14 relocation out of range");
383 *reloc_addr = (*reloc_addr & 0xffff0003) | (finaladdr & 0xfffc);
384 if (rinfo != R_PPC_ADDR14)
385 *reloc_addr = ((*reloc_addr & 0xffdfffff)
386 | ((rinfo == R_PPC_ADDR14_BRTAKEN)
387 ^ (finaladdr >> 31)) << 21);
392 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
393 if (delta << 6 >> 6 != delta)
394 _dl_signal_error (0, map->l_name,
395 "R_PPC_REL24 relocation out of range");
396 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
402 /* This can happen in trace mode when an object could not be
405 if (sym->st_size > refsym->st_size
406 || (_dl_verbose && sym->st_size < refsym->st_size))
410 strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
411 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
412 ": Symbol `", strtab + refsym->st_name,
413 "' has different size in shared object, "
414 "consider re-linking\n", NULL);
416 memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
421 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
425 elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
429 _dl_reloc_bad_type (map, rinfo, 0);
433 MODIFIED_CODE_NOQUEUE (reloc_addr);