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 ("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 *) ((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.) Most of the PLT shouldn't
246 be in the instruction cache, but there may be a little overlap
247 at the start and the end.
249 Assumes the cache line size is at least 32 bytes, or at least
250 that dcbst and icbi apply to 32-byte lines. At present, all
251 PowerPC processors have line sizes of exactly 32 bytes. */
253 size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
254 for (i = 0; i < size_modified; i+=8)
256 PPC_DCBST (plt + size_modified-1);
259 PPC_ICBI (plt + size_modified-1);
267 __elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
268 Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
270 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
271 if (delta << 6 >> 6 == delta)
272 *reloc_addr = OPCODE_B (delta);
273 else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
274 *reloc_addr = OPCODE_BA (finaladdr);
280 plt = (Elf32_Word *)((char *)map->l_addr
281 + map->l_info[DT_PLTGOT]->d_un.d_val);
282 index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
283 if (index >= PLT_DOUBLE_SIZE)
285 /* Slots greater than or equal to 2^13 have 4 words available
287 /* FIXME: There are some possible race conditions in this code,
288 when called from 'fixup'.
290 1) Suppose that a lazy PLT entry is executing, a context switch
291 between threads (or a signal) occurs, and the new thread or
292 signal handler calls the same lazy PLT entry. Then the PLT entry
293 would be changed while it's being run, which will cause a segfault
296 2) Suppose the reverse: that a lazy PLT entry is being updated,
297 a context switch occurs, and the new code calls the lazy PLT
298 entry that is being updated. Then the half-fixed PLT entry will
299 be executed, which will also almost always cause a segfault.
301 These problems don't happen with the 2-word entries, because
302 only one of the two instructions are changed when a lazy entry
303 is retargeted at the actual PLT entry; the li instruction stays
304 the same (we have to update it anyway, because we might not be
305 updating a lazy PLT entry). */
307 reloc_addr[0] = OPCODE_LI (11, finaladdr);
308 reloc_addr[1] = OPCODE_ADDIS (11, 11, (finaladdr + 0x8000) >> 16);
309 reloc_addr[2] = OPCODE_MTCTR (11);
310 reloc_addr[3] = OPCODE_BCTR ();
314 Elf32_Word num_plt_entries;
316 num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
317 / sizeof(Elf32_Rela));
319 plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
320 reloc_addr[0] = OPCODE_LI (11, index*4);
321 reloc_addr[1] = OPCODE_B (-(4*(index*2
323 - PLT_LONGBRANCH_ENTRY_WORDS
324 + PLT_INITIAL_ENTRY_WORDS)));
325 reloc_addr += 1; /* This is the modified address. */
328 MODIFIED_CODE (reloc_addr);
332 __process_machine_rela (struct link_map *map,
333 const Elf32_Rela *reloc,
334 const Elf32_Sym *sym,
335 const Elf32_Sym *refsym,
336 Elf32_Addr *const reloc_addr,
337 Elf32_Addr const finaladdr,
349 *reloc_addr = finaladdr;
353 if (finaladdr > 0x01fffffc && finaladdr < 0xfe000000)
355 _dl_signal_error(0, map->l_name,
356 "R_PPC_ADDR24 relocation out of range");
358 *reloc_addr = (*reloc_addr & 0xfc000003) | (finaladdr & 0x3fffffc);
363 if (finaladdr > 0x7fff && finaladdr < 0x8000)
365 _dl_signal_error(0, map->l_name,
366 "R_PPC_ADDR16 relocation out of range");
368 *(Elf32_Half*) reloc_addr = finaladdr;
371 case R_PPC_ADDR16_LO:
372 *(Elf32_Half*) reloc_addr = finaladdr;
375 case R_PPC_ADDR16_HI:
376 *(Elf32_Half*) reloc_addr = finaladdr >> 16;
379 case R_PPC_ADDR16_HA:
380 *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
384 case R_PPC_ADDR14_BRTAKEN:
385 case R_PPC_ADDR14_BRNTAKEN:
386 if (finaladdr > 0x7fff && finaladdr < 0x8000)
388 _dl_signal_error(0, map->l_name,
389 "R_PPC_ADDR14 relocation out of range");
391 *reloc_addr = (*reloc_addr & 0xffff0003) | (finaladdr & 0xfffc);
392 if (rinfo != R_PPC_ADDR14)
393 *reloc_addr = ((*reloc_addr & 0xffdfffff)
394 | ((rinfo == R_PPC_ADDR14_BRTAKEN)
395 ^ (finaladdr >> 31)) << 21);
400 Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
401 if (delta << 6 >> 6 != delta)
403 _dl_signal_error(0, map->l_name,
404 "R_PPC_REL24 relocation out of range");
406 *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
412 /* This can happen in trace mode when an object could not be
415 if (sym->st_size > refsym->st_size
416 || (_dl_verbose && sym->st_size < refsym->st_size))
420 strtab = ((void *) map->l_addr
421 + map->l_info[DT_STRTAB]->d_un.d_ptr);
422 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
423 ": Symbol `", strtab + refsym->st_name,
424 "' has different size in shared object, "
425 "consider re-linking\n", NULL);
427 memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
432 *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
436 elf_machine_fixup_plt(map, reloc, reloc_addr, finaladdr);
440 _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
441 ": Unknown relocation type\n", NULL);
445 MODIFIED_CODE_NOQUEUE (reloc_addr);