OSDN Git Service

Minor change to better match recent changes to other arches
[uclinux-h8/uClibc.git] / ldso / ldso / frv / dl-sysdep.h
1      /* Copyright (C) 2003, 2004 Red Hat, Inc.
2         Contributed by Alexandre Oliva <aoliva@redhat.com>
3         Based on ../i386/dl-sysdep.h
4
5 This file is part of uClibc.
6
7 uClibc is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 uClibc is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with uClibc; see the file COPYING.LIB.  If not, write to
19 the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
20 USA.  */
21
22 /*
23  * Various assembly language/system dependent  hacks that are required
24  * so that we can minimize the amount of platform specific code.
25  */
26
27 /*
28  * Define this if the system uses RELOCA.
29  */
30 #undef ELF_USES_RELOCA
31
32 /*
33  * Initialization sequence for a GOT.  Copy the resolver function
34  * descriptor and the pointer to the elf_resolve/link_map data
35  * structure.  Initialize the got_value in the module while at that.
36  */
37 #define INIT_GOT(GOT_BASE,MODULE) \
38 {                               \
39   (MODULE)->loadaddr.got_value = (GOT_BASE); \
40   GOT_BASE[0] = ((unsigned long *)&_dl_linux_resolve)[0]; \
41   GOT_BASE[1] = ((unsigned long *)&_dl_linux_resolve)[1]; \
42   GOT_BASE[2] = (unsigned long) MODULE; \
43 }
44
45 /* Here we define the magic numbers that this dynamic loader should accept */
46 #define MAGIC1 EM_CYGNUS_FRV
47 #undef  MAGIC2
48
49 /* Used for error messages */
50 #define ELF_TARGET "FR-V"
51
52 struct elf_resolve;
53
54 struct funcdesc_value
55 {
56   void *entry_point;
57   void *got_value;
58 } __attribute__((__aligned__(8)));
59
60
61 extern int _dl_linux_resolve(void) __attribute__((__visibility__("hidden")));
62
63 #define do_rem(result, n, base)  result = (n % base)
64
65 /* 4096 bytes alignment */
66 #define PAGE_ALIGN 0xfffff000
67 #define ADDR_ALIGN 0xfff
68 #define OFFS_ALIGN 0x7ffff000
69
70 struct funcdesc_ht;
71
72 /* We must force strings used early in the bootstrap into the data
73    segment, such that they are referenced with GOTOFF instead of
74    GPREL, because GPREL needs the GOT to have already been
75    relocated.  */
76 #define SEND_EARLY_STDERR(S) \
77   do { static char __s[] = (S); SEND_STDERR (__s); } while (0)
78
79 #include <bits/elf-fdpic.h>
80 #ifdef __USE_GNU
81 # include <link.h>
82 #else
83 # define __USE_GNU
84 # include <link.h>
85 # undef __USE_GNU
86 #endif
87 #include <dl-syscall.h>
88 #include <dl-string.h>
89
90 /* These are declared in ldso.h, after it includes dl-elf.h that
91    includes ourselves.  */
92 extern void *_dl_malloc(int size);
93 extern void _dl_free(void *);
94 extern void _dl_dprintf(int, const char *, ...);
95
96
97 #ifndef _dl_assert
98 # define _dl_assert(expr)
99 #endif
100
101 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
102    load map.  */
103 inline static void
104 __dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
105                         struct elf32_fdpic_loadmap *map)
106 {
107   if (map->version != 0)
108     {
109       SEND_EARLY_STDERR ("Invalid loadmap version number\n");
110       _dl_exit(-1);
111     }
112   if (map->nsegs == 0)
113     {
114       SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
115       _dl_exit(-1);
116     }
117   loadaddr->got_value = got_value;
118   loadaddr->map = map;
119 }
120
121 /* Figure out how many LOAD segments there are in the given headers,
122    and allocate a block for the load map big enough for them.
123    got_value will be properly initialized later on, with INIT_GOT.  */
124 inline static int
125 __dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
126                     int pcnt)
127 {
128   int count = 0, i;
129   size_t size;
130
131   for (i = 0; i < pcnt; i++)
132     if (ppnt[i].p_type == PT_LOAD)
133       count++;
134
135   loadaddr->got_value = 0;
136
137   size = sizeof (struct elf32_fdpic_loadmap)
138     + sizeof (struct elf32_fdpic_loadseg) * count;
139   loadaddr->map = _dl_malloc (size);
140   if (! loadaddr->map)
141     _dl_exit (-1);
142
143   loadaddr->map->version = 0;
144   loadaddr->map->nsegs = 0;
145
146   return count;
147 }
148
149 /* Incrementally initialize a load map.  */
150 inline static void
151 __dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr,
152                         Elf32_Phdr *phdr, int maxsegs)
153 {
154   struct elf32_fdpic_loadseg *segdata;
155
156   if (loadaddr.map->nsegs == maxsegs)
157     _dl_exit (-1);
158
159   segdata = &loadaddr.map->segs[loadaddr.map->nsegs++];
160   segdata->addr = (Elf32_Addr) addr;
161   segdata->p_vaddr = phdr->p_vaddr;
162   segdata->p_memsz = phdr->p_memsz;
163
164 #if defined (__SUPPORT_LD_DEBUG__)
165   {
166     extern char *_dl_debug;
167     extern int _dl_debug_file;
168     if (_dl_debug)
169       _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n",
170                   loadaddr.map->nsegs-1,
171                   segdata->p_vaddr, segdata->addr, segdata->p_memsz);
172   }
173 #endif
174 }
175
176 inline static void __dl_loadaddr_unmap
177 (struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht);
178
179 /* Figure out whether the given address is in one of the mapped
180    segments.  */
181 inline static int
182 __dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr)
183 {
184   struct elf32_fdpic_loadmap *map = loadaddr.map;
185   int c;
186
187   for (c = 0; c < map->nsegs; c++)
188     if ((void*)map->segs[c].addr <= p
189         && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz)
190       return 1;
191
192   return 0;
193 }
194
195 inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
196
197 #define DL_LOADADDR_TYPE struct elf32_fdpic_loadaddr
198
199 #define DL_RELOC_ADDR(ADDR, LOADADDR) \
200   (__reloc_pointer ((void*)(ADDR), (LOADADDR).map))
201
202 #define DL_ADDR_TO_FUNC_PTR(ADDR, LOADADDR) \
203   ((void(*)(void)) _dl_funcdesc_for ((void*)(ADDR), (LOADADDR).got_value))
204
205 #define _dl_stabilize_funcdesc(val) \
206   ({ asm ("" : "+m" (*(val))); (val); })
207
208 #define DL_CALL_FUNC_AT_ADDR(ADDR, LOADADDR, SIGNATURE, ...) \
209   ({ struct funcdesc_value fd = { (void*)(ADDR), (LOADADDR).got_value }; \
210      void (*pf)(void) = (void*) _dl_stabilize_funcdesc (&fd); \
211      (* SIGNATURE pf)(__VA_ARGS__); })
212
213 #define DL_INIT_LOADADDR_BOOT(LOADADDR, BASEADDR) \
214   (__dl_init_loadaddr_map (&(LOADADDR), dl_boot_got_pointer, \
215                            dl_boot_ldsomap ?: dl_boot_progmap))
216
217 #define DL_INIT_LOADADDR_PROG(LOADADDR, BASEADDR) \
218   (__dl_init_loadaddr_map (&(LOADADDR), 0, dl_boot_progmap))
219
220 #define DL_INIT_LOADADDR_EXTRA_DECLS \
221   int dl_init_loadaddr_load_count;
222 #define DL_INIT_LOADADDR(LOADADDR, BASEADDR, PHDR, PHDRCNT) \
223   (dl_init_loadaddr_load_count = \
224      __dl_init_loadaddr (&(LOADADDR), (PHDR), (PHDRCNT)))
225 #define DL_INIT_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \
226   (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \
227                            dl_init_loadaddr_load_count))
228 #define DL_LOADADDR_UNMAP(LOADADDR, LEN) \
229   (__dl_loadaddr_unmap ((LOADADDR), (NULL)))
230 #define DL_LIB_UNMAP(LIB, LEN) \
231   (__dl_loadaddr_unmap ((LIB)->loadaddr, (LIB)->funcdesc_ht))
232 #define DL_LOADADDR_BASE(LOADADDR) \
233   ((LOADADDR).got_value)
234
235 #define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \
236   (! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr))
237
238 /* We only support loading FDPIC independently-relocatable shared
239    libraries.  It probably wouldn't be too hard to support loading
240    shared libraries that require relocation by the same amount, but we
241    don't know that they exist or would be useful, and the dynamic
242    loader code could leak the whole-library map unless we keeping a
243    bit more state for DL_LOADADDR_UNMAP and DL_LIB_UNMAP, so let's
244    keep things simple for now.  */
245 #define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \
246 do \
247 { \
248   if (((epnt)->e_flags & EF_FRV_FDPIC) && ! ((epnt)->e_flags & EF_FRV_PIC)) \
249     (piclib) = 2; \
250   else \
251     { \
252       _dl_internal_error_number = LD_ERROR_NOTDYN; \
253       _dl_dprintf(2, "%s: '%s' is not an FDPIC shared library" \
254                   "\n", (_dl_progname), (libname)); \
255       _dl_close(infile); \
256       return NULL; \
257     } \
258 } \
259 while (0)  
260
261 /* We want want to apply all relocations in the interpreter during
262    bootstrap.  Because of this, we have to skip the interpreter
263    relocations in _dl_parse_relocation_information(), see
264    elfinterp.c.  */
265 #define DL_SKIP_BOOTSTRAP_RELOC(SYMTAB, INDEX, STRTAB) 0
266
267 #ifdef __NR_pread
268 #define _DL_PREAD(FD, BUF, SIZE, OFFSET) \
269   (_dl_pread((FD), (BUF), (SIZE), (OFFSET)))
270 #endif
271
272 #include <dl-hash.h>
273
274 /* The hashcode handling code below is heavily inspired in libiberty's
275    hashtab code, but with most adaptation points and support for
276    deleting elements removed.
277
278    Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
279    Contributed by Vladimir Makarov (vmakarov@cygnus.com).  */
280
281 inline static unsigned long
282 higher_prime_number (unsigned long n)
283 {
284   /* These are primes that are near, but slightly smaller than, a
285      power of two.  */
286   static const unsigned long primes[] = {
287     (unsigned long) 7,
288     (unsigned long) 13,
289     (unsigned long) 31,
290     (unsigned long) 61,
291     (unsigned long) 127,
292     (unsigned long) 251,
293     (unsigned long) 509,
294     (unsigned long) 1021,
295     (unsigned long) 2039,
296     (unsigned long) 4093,
297     (unsigned long) 8191,
298     (unsigned long) 16381,
299     (unsigned long) 32749,
300     (unsigned long) 65521,
301     (unsigned long) 131071,
302     (unsigned long) 262139,
303     (unsigned long) 524287,
304     (unsigned long) 1048573,
305     (unsigned long) 2097143,
306     (unsigned long) 4194301,
307     (unsigned long) 8388593,
308     (unsigned long) 16777213,
309     (unsigned long) 33554393,
310     (unsigned long) 67108859,
311     (unsigned long) 134217689,
312     (unsigned long) 268435399,
313     (unsigned long) 536870909,
314     (unsigned long) 1073741789,
315     (unsigned long) 2147483647,
316                                         /* 4294967291L */
317     ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
318   };
319
320   const unsigned long *low = &primes[0];
321   const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
322
323   while (low != high)
324     {
325       const unsigned long *mid = low + (high - low) / 2;
326       if (n > *mid)
327         low = mid + 1;
328       else
329         high = mid;
330     }
331
332 #if 0
333   /* If we've run out of primes, abort.  */
334   if (n > *low)
335     {
336       fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
337       abort ();
338     }
339 #endif
340
341   return *low;
342 }
343
344 struct funcdesc_ht
345 {
346   /* Table itself.  */
347   struct funcdesc_value **entries;
348
349   /* Current size (in entries) of the hash table */
350   size_t size;
351
352   /* Current number of elements.  */
353   size_t n_elements;
354 };  
355
356 inline static int
357 hash_pointer (const void *p)
358 {
359   return (int) ((long)p >> 3);
360 }
361
362 inline static struct funcdesc_ht *
363 htab_create (void)
364 {
365   struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht));
366
367   if (! ht)
368     return NULL;
369   ht->size = 3;
370   ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size);
371   if (! ht->entries)
372     return NULL;
373   
374   ht->n_elements = 0;
375
376   _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size);
377   
378   return ht;
379 }
380
381 inline static void
382 htab_delete (struct funcdesc_ht *htab)
383 {
384   int i;
385
386   for (i = htab->size - 1; i >= 0; i--)
387     if (htab->entries[i])
388       _dl_free (htab->entries[i]);
389
390   _dl_free (htab->entries);
391   _dl_free (htab);
392 }
393
394 /* Similar to htab_find_slot, but without several unwanted side effects:
395     - Does not call htab->eq_f when it finds an existing entry.
396     - Does not change the count of elements/searches/collisions in the
397       hash table.
398    This function also assumes there are no deleted entries in the table.
399    HASH is the hash value for the element to be inserted.  */
400
401 inline static struct funcdesc_value **
402 find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash)
403 {
404   size_t size = htab->size;
405   unsigned int index = hash % size;
406   struct funcdesc_value **slot = htab->entries + index;
407   int hash2;
408
409   if (! *slot)
410     return slot;
411
412   hash2 = 1 + hash % (size - 2);
413   for (;;)
414     {
415       index += hash2;
416       if (index >= size)
417         index -= size;
418
419       slot = htab->entries + index;
420       if (! *slot)
421         return slot;
422     }
423 }
424
425 /* The following function changes size of memory allocated for the
426    entries and repeatedly inserts the table elements.  The occupancy
427    of the table after the call will be about 50%.  Naturally the hash
428    table must already exist.  Remember also that the place of the
429    table entries is changed.  If memory allocation failures are allowed,
430    this function will return zero, indicating that the table could not be
431    expanded.  If all goes well, it will return a non-zero value.  */
432
433 inline static int
434 htab_expand (struct funcdesc_ht *htab)
435 {
436   struct funcdesc_value **oentries;
437   struct funcdesc_value **olimit;
438   struct funcdesc_value **p;
439   struct funcdesc_value **nentries;
440   size_t nsize;
441
442   oentries = htab->entries;
443   olimit = oentries + htab->size;
444
445   /* Resize only when table after removal of unused elements is either
446      too full or too empty.  */
447   if (htab->n_elements * 2 > htab->size)
448     nsize = higher_prime_number (htab->n_elements * 2);
449   else
450     nsize = htab->size;
451
452   nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize);
453   _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize);
454   if (nentries == NULL)
455     return 0;
456   htab->entries = nentries;
457   htab->size = nsize;
458
459   p = oentries;
460   do
461     {
462       if (*p)
463         *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point))
464           = *p;
465
466       p++;
467     }
468   while (p < olimit);
469
470   _dl_free (oentries);
471   return 1;
472 }
473
474 /* This function searches for a hash table slot containing an entry
475    equal to the given element.  To delete an entry, call this with
476    INSERT = 0, then call htab_clear_slot on the slot returned (possibly
477    after doing some checks).  To insert an entry, call this with
478    INSERT = 1, then write the value you want into the returned slot.
479    When inserting an entry, NULL may be returned if memory allocation
480    fails.  */
481
482 inline static struct funcdesc_value **
483 htab_find_slot (struct funcdesc_ht *htab, void *ptr)
484 {
485   unsigned int index;
486   int hash, hash2;
487   size_t size;
488   struct funcdesc_value **entry;
489
490   if (htab->size * 3 <= htab->n_elements * 4
491       && htab_expand (htab) == 0)
492     return NULL;
493
494   hash = hash_pointer (ptr);
495
496   size = htab->size;
497   index = hash % size;
498
499   entry = &htab->entries[index];
500   if (!*entry)
501     goto empty_entry;
502   else if ((*entry)->entry_point == ptr)
503     return entry;
504       
505   hash2 = 1 + hash % (size - 2);
506   for (;;)
507     {
508       index += hash2;
509       if (index >= size)
510         index -= size;
511       
512       entry = &htab->entries[index];
513       if (!*entry)
514         goto empty_entry;
515       else if ((*entry)->entry_point == ptr)
516         return entry;
517     }
518
519  empty_entry:
520   htab->n_elements++;
521   return entry;
522 }
523
524 void *
525 _dl_funcdesc_for (void *entry_point, void *got_value)
526 {
527   struct elf_resolve *tpnt = ((void**)got_value)[2];
528   struct funcdesc_ht *ht = tpnt->funcdesc_ht;
529   struct funcdesc_value **entry;
530
531   _dl_assert (got_value == tpnt->loadaddr.got_value);
532
533   if (! ht)
534     {
535       ht = htab_create ();
536       if (! ht)
537         return (void*)-1;
538       tpnt->funcdesc_ht = ht;
539     }
540
541   entry = htab_find_slot (ht, entry_point);
542   if (*entry)
543     {
544       _dl_assert ((*entry)->entry_point == entry_point);
545       return _dl_stabilize_funcdesc (*entry);
546     }
547
548   *entry = _dl_malloc (sizeof (struct funcdesc_value));
549   (*entry)->entry_point = entry_point;
550   (*entry)->got_value = got_value;
551
552   return _dl_stabilize_funcdesc (*entry);
553 }
554
555 void
556 __dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
557                      struct funcdesc_ht *funcdesc_ht)
558 {
559   int i;
560
561   for (i = 0; i < loadaddr.map->nsegs; i++)
562     _dl_munmap ((void*)loadaddr.map->segs[i].addr,
563                 loadaddr.map->segs[i].p_memsz);
564
565   _dl_free (loadaddr.map);
566   if (funcdesc_ht)
567     htab_delete (funcdesc_ht);
568 }