1 /* Copyright (C) 2003, 2004 Red Hat, Inc.
2 Contributed by Alexandre Oliva <aoliva@redhat.com>
3 Based on ../i386/dl-sysdep.h
5 This file is part of uClibc.
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.
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.
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,
23 * Various assembly language/system dependent hacks that are required
24 * so that we can minimize the amount of platform specific code.
28 * Define this if the system uses RELOCA.
30 #undef ELF_USES_RELOCA
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.
37 #define INIT_GOT(GOT_BASE,MODULE) \
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; \
45 /* Here we define the magic numbers that this dynamic loader should accept */
46 #define MAGIC1 EM_CYGNUS_FRV
49 /* Used for error messages */
50 #define ELF_TARGET "FR-V"
58 } __attribute__((__aligned__(8)));
61 extern int _dl_linux_resolve(void) __attribute__((__visibility__("hidden")));
63 #define do_rem(result, n, base) result = (n % base)
65 /* 4096 bytes alignment */
66 #define PAGE_ALIGN 0xfffff000
67 #define ADDR_ALIGN 0xfff
68 #define OFFS_ALIGN 0x7ffff000
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
76 #define SEND_EARLY_STDERR(S) \
77 do { static char __s[] = (S); SEND_STDERR (__s); } while (0)
79 #include <bits/elf-fdpic.h>
87 #include <dl-syscall.h>
88 #include <dl-string.h>
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 *, ...);
98 # define _dl_assert(expr)
101 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
104 __dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
105 struct elf32_fdpic_loadmap *map)
107 if (map->version != 0)
109 SEND_EARLY_STDERR ("Invalid loadmap version number\n");
114 SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
117 loadaddr->got_value = got_value;
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. */
125 __dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
131 for (i = 0; i < pcnt; i++)
132 if (ppnt[i].p_type == PT_LOAD)
135 loadaddr->got_value = 0;
137 size = sizeof (struct elf32_fdpic_loadmap)
138 + sizeof (struct elf32_fdpic_loadseg) * count;
139 loadaddr->map = _dl_malloc (size);
143 loadaddr->map->version = 0;
144 loadaddr->map->nsegs = 0;
149 /* Incrementally initialize a load map. */
151 __dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr,
152 Elf32_Phdr *phdr, int maxsegs)
154 struct elf32_fdpic_loadseg *segdata;
156 if (loadaddr.map->nsegs == maxsegs)
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;
164 #if defined (__SUPPORT_LD_DEBUG__)
166 extern char *_dl_debug;
167 extern int _dl_debug_file;
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);
176 inline static void __dl_loadaddr_unmap
177 (struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht);
179 /* Figure out whether the given address is in one of the mapped
182 __dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr)
184 struct elf32_fdpic_loadmap *map = loadaddr.map;
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)
195 inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
197 #define DL_LOADADDR_TYPE struct elf32_fdpic_loadaddr
199 #define DL_RELOC_ADDR(ADDR, LOADADDR) \
200 (__reloc_pointer ((void*)(ADDR), (LOADADDR).map))
202 #define DL_ADDR_TO_FUNC_PTR(ADDR, LOADADDR) \
203 ((void(*)(void)) _dl_funcdesc_for ((void*)(ADDR), (LOADADDR).got_value))
205 #define _dl_stabilize_funcdesc(val) \
206 ({ asm ("" : "+m" (*(val))); (val); })
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__); })
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))
217 #define DL_INIT_LOADADDR_PROG(LOADADDR, BASEADDR) \
218 (__dl_init_loadaddr_map (&(LOADADDR), 0, dl_boot_progmap))
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)
235 #define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \
236 (! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr))
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) \
248 if (((epnt)->e_flags & EF_FRV_FDPIC) && ! ((epnt)->e_flags & EF_FRV_PIC)) \
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)); \
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
265 #define DL_SKIP_BOOTSTRAP_RELOC(SYMTAB, INDEX, STRTAB) 0
268 #define _DL_PREAD(FD, BUF, SIZE, OFFSET) \
269 (_dl_pread((FD), (BUF), (SIZE), (OFFSET)))
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.
278 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
279 Contributed by Vladimir Makarov (vmakarov@cygnus.com). */
281 inline static unsigned long
282 higher_prime_number (unsigned long n)
284 /* These are primes that are near, but slightly smaller than, a
286 static const unsigned long primes[] = {
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,
317 ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
320 const unsigned long *low = &primes[0];
321 const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
325 const unsigned long *mid = low + (high - low) / 2;
333 /* If we've run out of primes, abort. */
336 fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
347 struct funcdesc_value **entries;
349 /* Current size (in entries) of the hash table */
352 /* Current number of elements. */
357 hash_pointer (const void *p)
359 return (int) ((long)p >> 3);
362 inline static struct funcdesc_ht *
365 struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht));
370 ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size);
376 _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size);
382 htab_delete (struct funcdesc_ht *htab)
386 for (i = htab->size - 1; i >= 0; i--)
387 if (htab->entries[i])
388 _dl_free (htab->entries[i]);
390 _dl_free (htab->entries);
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
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. */
401 inline static struct funcdesc_value **
402 find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash)
404 size_t size = htab->size;
405 unsigned int index = hash % size;
406 struct funcdesc_value **slot = htab->entries + index;
412 hash2 = 1 + hash % (size - 2);
419 slot = htab->entries + index;
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. */
434 htab_expand (struct funcdesc_ht *htab)
436 struct funcdesc_value **oentries;
437 struct funcdesc_value **olimit;
438 struct funcdesc_value **p;
439 struct funcdesc_value **nentries;
442 oentries = htab->entries;
443 olimit = oentries + htab->size;
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);
452 nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize);
453 _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize);
454 if (nentries == NULL)
456 htab->entries = nentries;
463 *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point))
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
482 inline static struct funcdesc_value **
483 htab_find_slot (struct funcdesc_ht *htab, void *ptr)
488 struct funcdesc_value **entry;
490 if (htab->size * 3 <= htab->n_elements * 4
491 && htab_expand (htab) == 0)
494 hash = hash_pointer (ptr);
499 entry = &htab->entries[index];
502 else if ((*entry)->entry_point == ptr)
505 hash2 = 1 + hash % (size - 2);
512 entry = &htab->entries[index];
515 else if ((*entry)->entry_point == ptr)
525 _dl_funcdesc_for (void *entry_point, void *got_value)
527 struct elf_resolve *tpnt = ((void**)got_value)[2];
528 struct funcdesc_ht *ht = tpnt->funcdesc_ht;
529 struct funcdesc_value **entry;
531 _dl_assert (got_value == tpnt->loadaddr.got_value);
538 tpnt->funcdesc_ht = ht;
541 entry = htab_find_slot (ht, entry_point);
544 _dl_assert ((*entry)->entry_point == entry_point);
545 return _dl_stabilize_funcdesc (*entry);
548 *entry = _dl_malloc (sizeof (struct funcdesc_value));
549 (*entry)->entry_point = entry_point;
550 (*entry)->got_value = got_value;
552 return _dl_stabilize_funcdesc (*entry);
556 __dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
557 struct funcdesc_ht *funcdesc_ht)
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);
565 _dl_free (loadaddr.map);
567 htab_delete (funcdesc_ht);