7d45e74d65bebc1c7314ddab373b90c8e81c71b3
[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 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 *) ((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);
174       Elf32_Word dlrr;
175
176       dlrr = (Elf32_Word)(char *)(profile
177                                   ? _dl_prof_resolve
178                                   : _dl_runtime_resolve);
179
180       if (lazy)
181         for (i = 0; i < num_plt_entries; i++)
182         {
183           Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
184
185           if (i >= PLT_DOUBLE_SIZE)
186             {
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)));
190             }
191           else
192             {
193               plt[offset  ] = OPCODE_LI (11, i * 4);
194               plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
195             }
196         }
197
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)
202         {
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
206                                            + 0x8000) >> 16));
207
208           /* Call _dl_runtime_resolve.  */
209           plt[4] = OPCODE_BA (dlrr);
210         }
211       else
212         {
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);
217
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
221                                            + 0x8000) >> 16));
222
223           /* Call _dl_runtime_resolve.  */
224           plt[7] = OPCODE_BCTR ();
225         }
226
227
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)
232                                 + 0x8000) >> 16));
233       plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
234         OPCODE_LWZ (11, (Elf32_Word) (char*) (plt+rel_offset_words), 11);
235
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 ();
239
240
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.
248
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.  */
252
253       size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
254       for (i = 0; i < size_modified; i+=8)
255         PPC_DCBST (plt + i);
256       PPC_DCBST (plt + size_modified-1);
257       PPC_SYNC;
258       PPC_ICBI (plt);
259       PPC_ICBI (plt + size_modified-1);
260       PPC_ISYNC;
261     }
262
263   return lazy;
264 }
265
266 void
267 __elf_machine_fixup_plt(struct link_map *map, const Elf32_Rela *reloc,
268                         Elf32_Addr *reloc_addr, Elf32_Addr finaladdr)
269 {
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);
275   else
276     {
277       Elf32_Word *plt;
278       Elf32_Word index;
279
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)
284         {
285           /* Slots greater than or equal to 2^13 have 4 words available
286              instead of two.  */
287           /* FIXME: There are some possible race conditions in this code,
288              when called from 'fixup'.
289
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
294              (almost always).
295
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.
300
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).  */
306
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 ();
311         }
312       else
313         {
314           Elf32_Word num_plt_entries;
315
316           num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
317                              / sizeof(Elf32_Rela));
318
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
322                                          + 1
323                                          - PLT_LONGBRANCH_ENTRY_WORDS
324                                          + PLT_INITIAL_ENTRY_WORDS)));
325           reloc_addr += 1;  /* This is the modified address.  */
326         }
327     }
328   MODIFIED_CODE (reloc_addr);
329 }
330
331 void
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,
338                         int rinfo)
339 {
340   switch (rinfo)
341     {
342     case R_PPC_NONE:
343       return;
344
345     case R_PPC_ADDR32:
346     case R_PPC_UADDR32:
347     case R_PPC_GLOB_DAT:
348     case R_PPC_RELATIVE:
349       *reloc_addr = finaladdr;
350       return;
351
352     case R_PPC_ADDR24:
353       if (finaladdr > 0x01fffffc && finaladdr < 0xfe000000)
354         {
355           _dl_signal_error(0, map->l_name,
356                            "R_PPC_ADDR24 relocation out of range");
357         }
358       *reloc_addr = (*reloc_addr & 0xfc000003) | (finaladdr & 0x3fffffc);
359       break;
360
361     case R_PPC_ADDR16:
362     case R_PPC_UADDR16:
363       if (finaladdr > 0x7fff && finaladdr < 0x8000)
364         {
365           _dl_signal_error(0, map->l_name,
366                            "R_PPC_ADDR16 relocation out of range");
367         }
368       *(Elf32_Half*) reloc_addr = finaladdr;
369       break;
370
371     case R_PPC_ADDR16_LO:
372       *(Elf32_Half*) reloc_addr = finaladdr;
373       break;
374
375     case R_PPC_ADDR16_HI:
376       *(Elf32_Half*) reloc_addr = finaladdr >> 16;
377       break;
378
379     case R_PPC_ADDR16_HA:
380       *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
381       break;
382
383     case R_PPC_ADDR14:
384     case R_PPC_ADDR14_BRTAKEN:
385     case R_PPC_ADDR14_BRNTAKEN:
386       if (finaladdr > 0x7fff && finaladdr < 0x8000)
387         {
388           _dl_signal_error(0, map->l_name,
389                            "R_PPC_ADDR14 relocation out of range");
390         }
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);
396       break;
397
398     case R_PPC_REL24:
399       {
400         Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
401         if (delta << 6 >> 6 != delta)
402           {
403             _dl_signal_error(0, map->l_name,
404                              "R_PPC_REL24 relocation out of range");
405           }
406         *reloc_addr = (*reloc_addr & 0xfc000003) | (delta & 0x3fffffc);
407       }
408       break;
409
410     case R_PPC_COPY:
411       if (sym == NULL)
412         /* This can happen in trace mode when an object could not be
413            found.  */
414         return;
415       if (sym->st_size > refsym->st_size
416           || (_dl_verbose && sym->st_size < refsym->st_size))
417         {
418           const char *strtab;
419
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);
426         }
427       memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
428                                                    refsym->st_size));
429       return;
430
431     case R_PPC_REL32:
432       *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
433       return;
434
435     case R_PPC_JMP_SLOT:
436       elf_machine_fixup_plt(map, reloc, reloc_addr, finaladdr);
437       return;
438
439     default:
440       _dl_sysdep_error (_dl_argv[0] ?: "<program name unknown>",
441                         ": Unknown relocation type\n", NULL);
442       return;
443     }
444
445   MODIFIED_CODE_NOQUEUE (reloc_addr);
446 }