(__elf_machine_runtime_setup): DT_PLTGOT has already been relocated.
[kopensolaris-gnu/glibc.git] / sysdeps / powerpc / dl-machine.c
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.
4
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.
9
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.
14
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.  */
19
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/param.h>
23 #include <link.h>
24 #include <dl-machine.h>
25 #include <elf/ldsodefs.h>
26 #include <elf/dynamic-link.h>
27
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.
33 #endif
34
35
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 : \
44     0))
45 #define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries)
46
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)
61
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)
64
65
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")
71
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)
79
80
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.  */
89
90 ElfW(Addr)
91 __elf_preferred_address(struct link_map *loader, size_t maplength,
92                         ElfW(Addr) mapstartpref)
93 {
94   ElfW(Addr) low, high;
95   struct link_map *l;
96
97   /* If the object has a preference, load it there!  */
98   if (mapstartpref != 0)
99     return mapstartpref;
100
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).  */
105   low =  0x0003FFFF;
106   high = 0x70000000;
107   for (l = _dl_loaded; l; l = l->l_next)
108     {
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);
113
114       if (mapend >= high && high >= mapstart)
115         high = mapstart;
116       else if (mapend >= low && low >= mapstart)
117         low = mapend;
118       else if (high >= mapend && mapstart >= low)
119         {
120           if (high - mapend >= mapstart - low)
121             low = mapend;
122           else
123             high = mapstart;
124         }
125     }
126
127   high -= 0x10000; /* Allow some room between objects.  */
128   maplength = (maplength | (_dl_pagesize-1)) + 1;
129   if (high <= low || high - low < maplength )
130     return 0;
131   return high - maplength;  /* Both high and maplength are page-aligned.  */
132 }
133
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.  */
138
139 /* A PLT entry does one of three things:
140    (i)   Jumps to the actual routine. Such entries are set up above, in
141          elf_machine_rela.
142
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.
150
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.  */
157 int
158 __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
159 {
160   if (map->l_info[DT_JMPREL])
161     {
162       Elf32_Word i;
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);
173       Elf32_Word dlrr;
174
175       dlrr = (Elf32_Word)(char *)(profile
176                                   ? _dl_prof_resolve
177                                   : _dl_runtime_resolve);
178
179       if (lazy)
180         for (i = 0; i < num_plt_entries; i++)
181         {
182           Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
183
184           if (i >= PLT_DOUBLE_SIZE)
185             {
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)));
189             }
190           else
191             {
192               plt[offset  ] = OPCODE_LI (11, i * 4);
193               plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
194             }
195         }
196
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)
201         {
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
205                                            + 0x8000) >> 16));
206
207           /* Call _dl_runtime_resolve.  */
208           plt[4] = OPCODE_BA (dlrr);
209         }
210       else
211         {
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);
216
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
220                                            + 0x8000) >> 16));
221
222           /* Call _dl_runtime_resolve.  */
223           plt[7] = OPCODE_BCTR ();
224         }
225
226
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)
231                                 + 0x8000) >> 16));
232       plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
233         OPCODE_LWZ (11, (Elf32_Word) (char*) (plt + rel_offset_words), 11);
234
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 ();
238
239
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.
247
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.  */
251
252       size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
253       for (i = 0; i < size_modified; i+= 8)
254         PPC_DCBST (plt + i);
255       PPC_DCBST (plt + size_modified - 1);
256       PPC_SYNC;
257       PPC_ICBI (plt);
258       PPC_ICBI (plt + size_modified-1);
259       PPC_ISYNC;
260     }
261
262   return lazy;
263 }
264
265 void
266 __elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
267                         Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
268 {
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);
274   else
275     {
276       Elf32_Word *plt;
277       Elf32_Word index;
278
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)
282         {
283           /* Slots greater than or equal to 2^13 have 4 words available
284              instead of two.  */
285           /* FIXME: There are some possible race conditions in this code,
286              when called from 'fixup'.
287
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
292              (almost always).
293
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.
298
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).  */
304
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 ();
309         }
310       else
311         {
312           Elf32_Word num_plt_entries;
313
314           num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
315                              / sizeof(Elf32_Rela));
316
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
320                                          + 1
321                                          - PLT_LONGBRANCH_ENTRY_WORDS
322                                          + PLT_INITIAL_ENTRY_WORDS)));
323           reloc_addr += 1;  /* This is the modified address.  */
324         }
325     }
326   MODIFIED_CODE (reloc_addr);
327 }
328
329 void
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,
336                         int rinfo)
337 {
338   switch (rinfo)
339     {
340     case R_PPC_NONE:
341       return;
342
343     case R_PPC_ADDR32:
344     case R_PPC_UADDR32:
345     case R_PPC_GLOB_DAT:
346     case R_PPC_RELATIVE:
347       *reloc_addr = finaladdr;
348       return;
349
350     case R_PPC_ADDR24:
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);
355       break;
356
357     case R_PPC_ADDR16:
358     case R_PPC_UADDR16:
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;
363       break;
364
365     case R_PPC_ADDR16_LO:
366       *(Elf32_Half*) reloc_addr = finaladdr;
367       break;
368
369     case R_PPC_ADDR16_HI:
370       *(Elf32_Half*) reloc_addr = finaladdr >> 16;
371       break;
372
373     case R_PPC_ADDR16_HA:
374       *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
375       break;
376
377     case R_PPC_ADDR14:
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);
388       break;
389
390     case R_PPC_REL24:
391       {
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);
397       }
398       break;
399
400     case R_PPC_COPY:
401       if (sym == NULL)
402         /* This can happen in trace mode when an object could not be
403            found.  */
404         return;
405       if (sym->st_size > refsym->st_size
406           || (_dl_verbose && sym->st_size < refsym->st_size))
407         {
408           const char *strtab;
409
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);
415         }
416       memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
417                                                    refsym->st_size));
418       return;
419
420     case R_PPC_REL32:
421       *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
422       return;
423
424     case R_PPC_JMP_SLOT:
425       elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
426       return;
427
428     default:
429       _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
430                         ": Unknown relocation type\n", NULL);
431       return;
432     }
433
434   MODIFIED_CODE_NOQUEUE (reloc_addr);
435 }