1 /* Copyright (C) 2003, 2004 Red Hat, Inc.
2 * Contributed by Alexandre Oliva <aoliva@redhat.com>
4 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
8 # define _dl_assert(expr)
11 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete
14 __dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value,
15 struct elf32_fdpic_loadmap *map)
17 if (map->version != 0)
19 SEND_EARLY_STDERR ("Invalid loadmap version number\n");
24 SEND_EARLY_STDERR ("Invalid segment count in loadmap\n");
27 loadaddr->got_value = got_value;
31 /* Figure out how many LOAD segments there are in the given headers,
32 and allocate a block for the load map big enough for them.
33 got_value will be properly initialized later on, with INIT_GOT. */
35 __dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt,
41 for (i = 0; i < pcnt; i++)
42 if (ppnt[i].p_type == PT_LOAD)
45 loadaddr->got_value = 0;
47 size = sizeof (struct elf32_fdpic_loadmap)
48 + sizeof (struct elf32_fdpic_loadseg) * count;
49 loadaddr->map = _dl_malloc (size);
53 loadaddr->map->version = 0;
54 loadaddr->map->nsegs = 0;
59 /* Incrementally initialize a load map. */
61 __dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr,
62 Elf32_Phdr *phdr, int maxsegs)
64 struct elf32_fdpic_loadseg *segdata;
66 if (loadaddr.map->nsegs == maxsegs)
69 segdata = &loadaddr.map->segs[loadaddr.map->nsegs++];
70 segdata->addr = (Elf32_Addr) addr;
71 segdata->p_vaddr = phdr->p_vaddr;
72 segdata->p_memsz = phdr->p_memsz;
74 #if defined (__SUPPORT_LD_DEBUG__)
76 extern char *_dl_debug;
77 extern int _dl_debug_file;
79 _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n",
80 loadaddr.map->nsegs-1,
81 segdata->p_vaddr, segdata->addr, segdata->p_memsz);
86 inline static void __dl_loadaddr_unmap
87 (struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht);
89 /* Figure out whether the given address is in one of the mapped
92 __dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr)
94 struct elf32_fdpic_loadmap *map = loadaddr.map;
97 for (c = 0; c < map->nsegs; c++)
98 if ((void*)map->segs[c].addr <= p
99 && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz)
105 inline static void * _dl_funcdesc_for (void *entry_point, void *got_value);
107 /* The hashcode handling code below is heavily inspired in libiberty's
108 hashtab code, but with most adaptation points and support for
109 deleting elements removed.
111 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
112 Contributed by Vladimir Makarov (vmakarov@cygnus.com). */
114 inline static unsigned long
115 higher_prime_number (unsigned long n)
117 /* These are primes that are near, but slightly smaller than, a
119 static const unsigned long primes[] = {
127 (unsigned long) 1021,
128 (unsigned long) 2039,
129 (unsigned long) 4093,
130 (unsigned long) 8191,
131 (unsigned long) 16381,
132 (unsigned long) 32749,
133 (unsigned long) 65521,
134 (unsigned long) 131071,
135 (unsigned long) 262139,
136 (unsigned long) 524287,
137 (unsigned long) 1048573,
138 (unsigned long) 2097143,
139 (unsigned long) 4194301,
140 (unsigned long) 8388593,
141 (unsigned long) 16777213,
142 (unsigned long) 33554393,
143 (unsigned long) 67108859,
144 (unsigned long) 134217689,
145 (unsigned long) 268435399,
146 (unsigned long) 536870909,
147 (unsigned long) 1073741789,
148 (unsigned long) 2147483647,
150 ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
153 const unsigned long *low = &primes[0];
154 const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
158 const unsigned long *mid = low + (high - low) / 2;
166 /* If we've run out of primes, abort. */
169 fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
180 struct funcdesc_value **entries;
182 /* Current size (in entries) of the hash table */
185 /* Current number of elements. */
190 hash_pointer (const void *p)
192 return (int) ((long)p >> 3);
195 inline static struct funcdesc_ht *
198 struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht));
203 ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size);
209 _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size);
214 /* This is only called from _dl_loadaddr_unmap, so it's safe to call
215 _dl_free(). See the discussion below. */
217 htab_delete (struct funcdesc_ht *htab)
221 for (i = htab->size - 1; i >= 0; i--)
222 if (htab->entries[i])
223 _dl_free (htab->entries[i]);
225 _dl_free (htab->entries);
229 /* Similar to htab_find_slot, but without several unwanted side effects:
230 - Does not call htab->eq_f when it finds an existing entry.
231 - Does not change the count of elements/searches/collisions in the
233 This function also assumes there are no deleted entries in the table.
234 HASH is the hash value for the element to be inserted. */
236 inline static struct funcdesc_value **
237 find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash)
239 size_t size = htab->size;
240 unsigned int index = hash % size;
241 struct funcdesc_value **slot = htab->entries + index;
247 hash2 = 1 + hash % (size - 2);
254 slot = htab->entries + index;
260 /* The following function changes size of memory allocated for the
261 entries and repeatedly inserts the table elements. The occupancy
262 of the table after the call will be about 50%. Naturally the hash
263 table must already exist. Remember also that the place of the
264 table entries is changed. If memory allocation failures are allowed,
265 this function will return zero, indicating that the table could not be
266 expanded. If all goes well, it will return a non-zero value. */
269 htab_expand (struct funcdesc_ht *htab)
271 struct funcdesc_value **oentries;
272 struct funcdesc_value **olimit;
273 struct funcdesc_value **p;
274 struct funcdesc_value **nentries;
277 oentries = htab->entries;
278 olimit = oentries + htab->size;
280 /* Resize only when table after removal of unused elements is either
281 too full or too empty. */
282 if (htab->n_elements * 2 > htab->size)
283 nsize = higher_prime_number (htab->n_elements * 2);
287 nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize);
288 _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize);
289 if (nentries == NULL)
291 htab->entries = nentries;
298 *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point))
305 #if 0 /* We can't tell whether this was allocated by the _dl_malloc()
306 built into ld.so or malloc() in the main executable or libc,
307 and calling free() for something that wasn't malloc()ed could
308 do Very Bad Things (TM). Take the conservative approach
309 here, potentially wasting as much memory as actually used by
310 the hash table, even if multiple growths occur. That's not
311 so bad as to require some overengineered solution that would
312 enable us to keep track of how it was allocated. */
318 /* This function searches for a hash table slot containing an entry
319 equal to the given element. To delete an entry, call this with
320 INSERT = 0, then call htab_clear_slot on the slot returned (possibly
321 after doing some checks). To insert an entry, call this with
322 INSERT = 1, then write the value you want into the returned slot.
323 When inserting an entry, NULL may be returned if memory allocation
326 inline static struct funcdesc_value **
327 htab_find_slot (struct funcdesc_ht *htab, void *ptr, int insert)
332 struct funcdesc_value **entry;
334 if (htab->size * 3 <= htab->n_elements * 4
335 && htab_expand (htab) == 0)
338 hash = hash_pointer (ptr);
343 entry = &htab->entries[index];
346 else if ((*entry)->entry_point == ptr)
349 hash2 = 1 + hash % (size - 2);
356 entry = &htab->entries[index];
359 else if ((*entry)->entry_point == ptr)
372 _dl_funcdesc_for (void *entry_point, void *got_value)
374 struct elf_resolve *tpnt = ((void**)got_value)[2];
375 struct funcdesc_ht *ht = tpnt->funcdesc_ht;
376 struct funcdesc_value **entry;
378 _dl_assert (got_value == tpnt->loadaddr.got_value);
385 tpnt->funcdesc_ht = ht;
388 entry = htab_find_slot (ht, entry_point, 1);
391 _dl_assert ((*entry)->entry_point == entry_point);
392 return _dl_stabilize_funcdesc (*entry);
395 *entry = _dl_malloc (sizeof (struct funcdesc_value));
396 (*entry)->entry_point = entry_point;
397 (*entry)->got_value = got_value;
399 return _dl_stabilize_funcdesc (*entry);
402 inline static void const *
403 _dl_lookup_address (void const *address)
405 struct elf_resolve *rpnt;
406 struct funcdesc_value const *fd;
408 /* Make sure we don't make assumptions about its alignment. */
409 __asm__ ("" : "+r" (address));
411 if ((Elf32_Addr)address & 7)
412 /* It's not a function descriptor. */
415 fd = (struct funcdesc_value const *)address;
417 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next)
419 if (! rpnt->funcdesc_ht)
422 if (fd->got_value != rpnt->loadaddr.got_value)
425 address = htab_find_slot (rpnt->funcdesc_ht, (void*)fd->entry_point, 0);
427 if (address && *(struct funcdesc_value *const*)address == fd)
429 address = (*(struct funcdesc_value *const*)address)->entry_point;
440 __dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr,
441 struct funcdesc_ht *funcdesc_ht)
445 for (i = 0; i < loadaddr.map->nsegs; i++)
446 _dl_munmap ((void*)loadaddr.map->segs[i].addr,
447 loadaddr.map->segs[i].p_memsz);
449 /* _dl_unmap is only called for dlopen()ed libraries, for which
450 calling free() is safe, or before we've completed the initial
451 relocation, in which case calling free() is probably pointless,
453 _dl_free (loadaddr.map);
455 htab_delete (funcdesc_ht);