diff options
author | Eric Andersen <andersen@codepoet.org> | 2004-08-26 23:39:02 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2004-08-26 23:39:02 +0000 |
commit | 6cd34f77ff5044e6aeb1cf01f02a8403351c4ad1 (patch) | |
tree | e5e7e8c0728a3fd3cd09cabd85ef736db3482bd7 | |
parent | 73fdcf0b9ce22a0fe993689c8f9e13d2c95a806c (diff) |
Partial patch from Alexandre Oliva to update the frv port
-rw-r--r-- | ldso/ldso/frv/dl-inlines.h | 471 | ||||
-rw-r--r-- | ldso/ldso/frv/dl-sysdep.h | 437 | ||||
-rw-r--r-- | ldso/ldso/frv/elfinterp.c | 16 |
3 files changed, 501 insertions, 423 deletions
diff --git a/ldso/ldso/frv/dl-inlines.h b/ldso/ldso/frv/dl-inlines.h new file mode 100644 index 000000000..f09c8b93a --- /dev/null +++ b/ldso/ldso/frv/dl-inlines.h @@ -0,0 +1,471 @@ + /* Copyright (C) 2003, 2004 Red Hat, Inc. + Contributed by Alexandre Oliva <aoliva@redhat.com> + +This file is part of uClibc. + +uClibc is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +uClibc is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with uClibc; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +USA. */ + + +#ifndef _dl_assert +# define _dl_assert(expr) +#endif + +/* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete + load map. */ +inline static void +__dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value, + struct elf32_fdpic_loadmap *map) +{ + if (map->version != 0) + { + SEND_EARLY_STDERR ("Invalid loadmap version number\n"); + _dl_exit(-1); + } + if (map->nsegs == 0) + { + SEND_EARLY_STDERR ("Invalid segment count in loadmap\n"); + _dl_exit(-1); + } + loadaddr->got_value = got_value; + loadaddr->map = map; +} + +/* Figure out how many LOAD segments there are in the given headers, + and allocate a block for the load map big enough for them. + got_value will be properly initialized later on, with INIT_GOT. */ +inline static int +__dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt, + int pcnt) +{ + int count = 0, i; + size_t size; + + for (i = 0; i < pcnt; i++) + if (ppnt[i].p_type == PT_LOAD) + count++; + + loadaddr->got_value = 0; + + size = sizeof (struct elf32_fdpic_loadmap) + + sizeof (struct elf32_fdpic_loadseg) * count; + loadaddr->map = _dl_malloc (size); + if (! loadaddr->map) + _dl_exit (-1); + + loadaddr->map->version = 0; + loadaddr->map->nsegs = 0; + + return count; +} + +/* Incrementally initialize a load map. */ +inline static void +__dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, + Elf32_Phdr *phdr, int maxsegs) +{ + struct elf32_fdpic_loadseg *segdata; + + if (loadaddr.map->nsegs == maxsegs) + _dl_exit (-1); + + segdata = &loadaddr.map->segs[loadaddr.map->nsegs++]; + segdata->addr = (Elf32_Addr) addr; + segdata->p_vaddr = phdr->p_vaddr; + segdata->p_memsz = phdr->p_memsz; + +#if defined (__SUPPORT_LD_DEBUG__) + { + extern char *_dl_debug; + extern int _dl_debug_file; + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, segdata->p_memsz); + } +#endif +} + +inline static void __dl_loadaddr_unmap +(struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht); + +/* Figure out whether the given address is in one of the mapped + segments. */ +inline static int +__dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr) +{ + struct elf32_fdpic_loadmap *map = loadaddr.map; + int c; + + for (c = 0; c < map->nsegs; c++) + if ((void*)map->segs[c].addr <= p + && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz) + return 1; + + return 0; +} + +inline static void * _dl_funcdesc_for (void *entry_point, void *got_value); + +/* The hashcode handling code below is heavily inspired in libiberty's + hashtab code, but with most adaptation points and support for + deleting elements removed. + + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). */ + +inline static unsigned long +higher_prime_number (unsigned long n) +{ + /* These are primes that are near, but slightly smaller than, a + power of two. */ + static const unsigned long primes[] = { + (unsigned long) 7, + (unsigned long) 13, + (unsigned long) 31, + (unsigned long) 61, + (unsigned long) 127, + (unsigned long) 251, + (unsigned long) 509, + (unsigned long) 1021, + (unsigned long) 2039, + (unsigned long) 4093, + (unsigned long) 8191, + (unsigned long) 16381, + (unsigned long) 32749, + (unsigned long) 65521, + (unsigned long) 131071, + (unsigned long) 262139, + (unsigned long) 524287, + (unsigned long) 1048573, + (unsigned long) 2097143, + (unsigned long) 4194301, + (unsigned long) 8388593, + (unsigned long) 16777213, + (unsigned long) 33554393, + (unsigned long) 67108859, + (unsigned long) 134217689, + (unsigned long) 268435399, + (unsigned long) 536870909, + (unsigned long) 1073741789, + (unsigned long) 2147483647, + /* 4294967291L */ + ((unsigned long) 2147483647) + ((unsigned long) 2147483644), + }; + + const unsigned long *low = &primes[0]; + const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])]; + + while (low != high) + { + const unsigned long *mid = low + (high - low) / 2; + if (n > *mid) + low = mid + 1; + else + high = mid; + } + +#if 0 + /* If we've run out of primes, abort. */ + if (n > *low) + { + fprintf (stderr, "Cannot find prime bigger than %lu\n", n); + abort (); + } +#endif + + return *low; +} + +struct funcdesc_ht +{ + /* Table itself. */ + struct funcdesc_value **entries; + + /* Current size (in entries) of the hash table */ + size_t size; + + /* Current number of elements. */ + size_t n_elements; +}; + +inline static int +hash_pointer (const void *p) +{ + return (int) ((long)p >> 3); +} + +inline static struct funcdesc_ht * +htab_create (void) +{ + struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht)); + + if (! ht) + return NULL; + ht->size = 3; + ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size); + if (! ht->entries) + return NULL; + + ht->n_elements = 0; + + _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size); + + return ht; +} + +/* This is only called from _dl_loadaddr_unmap, so it's safe to call + _dl_free(). See the discussion below. */ +inline static void +htab_delete (struct funcdesc_ht *htab) +{ + int i; + + for (i = htab->size - 1; i >= 0; i--) + if (htab->entries[i]) + _dl_free (htab->entries[i]); + + _dl_free (htab->entries); + _dl_free (htab); +} + +/* Similar to htab_find_slot, but without several unwanted side effects: + - Does not call htab->eq_f when it finds an existing entry. + - Does not change the count of elements/searches/collisions in the + hash table. + This function also assumes there are no deleted entries in the table. + HASH is the hash value for the element to be inserted. */ + +inline static struct funcdesc_value ** +find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash) +{ + size_t size = htab->size; + unsigned int index = hash % size; + struct funcdesc_value **slot = htab->entries + index; + int hash2; + + if (! *slot) + return slot; + + hash2 = 1 + hash % (size - 2); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + slot = htab->entries + index; + if (! *slot) + return slot; + } +} + +/* The following function changes size of memory allocated for the + entries and repeatedly inserts the table elements. The occupancy + of the table after the call will be about 50%. Naturally the hash + table must already exist. Remember also that the place of the + table entries is changed. If memory allocation failures are allowed, + this function will return zero, indicating that the table could not be + expanded. If all goes well, it will return a non-zero value. */ + +inline static int +htab_expand (struct funcdesc_ht *htab) +{ + struct funcdesc_value **oentries; + struct funcdesc_value **olimit; + struct funcdesc_value **p; + struct funcdesc_value **nentries; + size_t nsize; + + oentries = htab->entries; + olimit = oentries + htab->size; + + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + if (htab->n_elements * 2 > htab->size) + nsize = higher_prime_number (htab->n_elements * 2); + else + nsize = htab->size; + + nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize); + _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize); + if (nentries == NULL) + return 0; + htab->entries = nentries; + htab->size = nsize; + + p = oentries; + do + { + if (*p) + *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point)) + = *p; + + p++; + } + while (p < olimit); + +#if 0 /* We can't tell whether this was allocated by the _dl_malloc() + built into ld.so or malloc() in the main executable or libc, + and calling free() for something that wasn't malloc()ed could + do Very Bad Things (TM). Take the conservative approach + here, potentially wasting as much memory as actually used by + the hash table, even if multiple growths occur. That's not + so bad as to require some overengineered solution that would + enable us to keep track of how it was allocated. */ + _dl_free (oentries); +#endif + return 1; +} + +/* This function searches for a hash table slot containing an entry + equal to the given element. To delete an entry, call this with + INSERT = 0, then call htab_clear_slot on the slot returned (possibly + after doing some checks). To insert an entry, call this with + INSERT = 1, then write the value you want into the returned slot. + When inserting an entry, NULL may be returned if memory allocation + fails. */ + +inline static struct funcdesc_value ** +htab_find_slot (struct funcdesc_ht *htab, void *ptr, int insert) +{ + unsigned int index; + int hash, hash2; + size_t size; + struct funcdesc_value **entry; + + if (htab->size * 3 <= htab->n_elements * 4 + && htab_expand (htab) == 0) + return NULL; + + hash = hash_pointer (ptr); + + size = htab->size; + index = hash % size; + + entry = &htab->entries[index]; + if (!*entry) + goto empty_entry; + else if ((*entry)->entry_point == ptr) + return entry; + + hash2 = 1 + hash % (size - 2); + for (;;) + { + index += hash2; + if (index >= size) + index -= size; + + entry = &htab->entries[index]; + if (!*entry) + goto empty_entry; + else if ((*entry)->entry_point == ptr) + return entry; + } + + empty_entry: + if (!insert) + return NULL; + + htab->n_elements++; + return entry; +} + +void * +_dl_funcdesc_for (void *entry_point, void *got_value) +{ + struct elf_resolve *tpnt = ((void**)got_value)[2]; + struct funcdesc_ht *ht = tpnt->funcdesc_ht; + struct funcdesc_value **entry; + + _dl_assert (got_value == tpnt->loadaddr.got_value); + + if (! ht) + { + ht = htab_create (); + if (! ht) + return (void*)-1; + tpnt->funcdesc_ht = ht; + } + + entry = htab_find_slot (ht, entry_point, 1); + if (*entry) + { + _dl_assert ((*entry)->entry_point == entry_point); + return _dl_stabilize_funcdesc (*entry); + } + + *entry = _dl_malloc (sizeof (struct funcdesc_value)); + (*entry)->entry_point = entry_point; + (*entry)->got_value = got_value; + + return _dl_stabilize_funcdesc (*entry); +} + +inline static void * +_dl_lookup_address (void *address) +{ + struct elf_resolve *rpnt; + struct funcdesc_value *fd; + + /* Make sure we don't make assumptions about its alignment. */ + asm ("" : "+r" (address)); + + if ((Elf32_Addr)address & 7) + /* It's not a function descriptor. */ + return address; + + fd = (struct funcdesc_value *)address; + + for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) + { + if (! rpnt->funcdesc_ht) + continue; + + if (fd->got_value != rpnt->loadaddr.got_value) + continue; + + address = htab_find_slot (rpnt->funcdesc_ht, (void*)fd->entry_point, 0); + + if (address && *(struct funcdesc_value **)address == fd) + { + address = (*(struct funcdesc_value **)address)->entry_point; + break; + } + else + address = fd; + } + + return address; +} + +void +__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr, + struct funcdesc_ht *funcdesc_ht) +{ + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + _dl_munmap ((void*)loadaddr.map->segs[i].addr, + loadaddr.map->segs[i].p_memsz); + + /* _dl_unmap is only called for dlopen()ed libraries, for which + calling free() is safe, or before we've completed the initial + relocation, in which case calling free() is probably pointless, + but still safe. */ + _dl_free (loadaddr.map); + if (funcdesc_ht) + htab_delete (funcdesc_ht); +} diff --git a/ldso/ldso/frv/dl-sysdep.h b/ldso/ldso/frv/dl-sysdep.h index 46f8461f7..b121a934c 100644 --- a/ldso/ldso/frv/dl-sysdep.h +++ b/ldso/ldso/frv/dl-sysdep.h @@ -29,6 +29,9 @@ USA. */ */ #undef ELF_USES_RELOCA +/* JMPREL relocs are inside the DT_RELA table. */ +#define ELF_MACHINE_PLTREL_OVERLAP + #define DL_NO_COPY_RELOCS /* @@ -76,127 +79,10 @@ struct funcdesc_ht; segment, such that they are referenced with GOTOFF instead of GPREL, because GPREL needs the GOT to have already been relocated. */ +#undef SEND_EARLY_STDERR #define SEND_EARLY_STDERR(S) \ do { static char __s[] = (S); SEND_STDERR (__s); } while (0) -#include <bits/elf-fdpic.h> -#ifdef __USE_GNU -# include <link.h> -#else -# define __USE_GNU -# include <link.h> -# undef __USE_GNU -#endif -#include <dl-syscall.h> -#include <dl-string.h> - -/* These are declared in ldso.h, after it includes dl-elf.h that - includes ourselves. */ -extern void *_dl_malloc(int size); -extern void _dl_free(void *); -extern void _dl_dprintf(int, const char *, ...); - - -#ifndef _dl_assert -# define _dl_assert(expr) -#endif - -/* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete - load map. */ -inline static void -__dl_init_loadaddr_map (struct elf32_fdpic_loadaddr *loadaddr, void *got_value, - struct elf32_fdpic_loadmap *map) -{ - if (map->version != 0) - { - SEND_EARLY_STDERR ("Invalid loadmap version number\n"); - _dl_exit(-1); - } - if (map->nsegs == 0) - { - SEND_EARLY_STDERR ("Invalid segment count in loadmap\n"); - _dl_exit(-1); - } - loadaddr->got_value = got_value; - loadaddr->map = map; -} - -/* Figure out how many LOAD segments there are in the given headers, - and allocate a block for the load map big enough for them. - got_value will be properly initialized later on, with INIT_GOT. */ -inline static int -__dl_init_loadaddr (struct elf32_fdpic_loadaddr *loadaddr, Elf32_Phdr *ppnt, - int pcnt) -{ - int count = 0, i; - size_t size; - - for (i = 0; i < pcnt; i++) - if (ppnt[i].p_type == PT_LOAD) - count++; - - loadaddr->got_value = 0; - - size = sizeof (struct elf32_fdpic_loadmap) - + sizeof (struct elf32_fdpic_loadseg) * count; - loadaddr->map = _dl_malloc (size); - if (! loadaddr->map) - _dl_exit (-1); - - loadaddr->map->version = 0; - loadaddr->map->nsegs = 0; - - return count; -} - -/* Incrementally initialize a load map. */ -inline static void -__dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, - Elf32_Phdr *phdr, int maxsegs) -{ - struct elf32_fdpic_loadseg *segdata; - - if (loadaddr.map->nsegs == maxsegs) - _dl_exit (-1); - - segdata = &loadaddr.map->segs[loadaddr.map->nsegs++]; - segdata->addr = (Elf32_Addr) addr; - segdata->p_vaddr = phdr->p_vaddr; - segdata->p_memsz = phdr->p_memsz; - -#if defined (__SUPPORT_LD_DEBUG__) - { - extern char *_dl_debug; - extern int _dl_debug_file; - if (_dl_debug) - _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", - loadaddr.map->nsegs-1, - segdata->p_vaddr, segdata->addr, segdata->p_memsz); - } -#endif -} - -inline static void __dl_loadaddr_unmap -(struct elf32_fdpic_loadaddr loadaddr, struct funcdesc_ht *funcdesc_ht); - -/* Figure out whether the given address is in one of the mapped - segments. */ -inline static int -__dl_addr_in_loadaddr (void *p, struct elf32_fdpic_loadaddr loadaddr) -{ - struct elf32_fdpic_loadmap *map = loadaddr.map; - int c; - - for (c = 0; c < map->nsegs; c++) - if ((void*)map->segs[c].addr <= p - && (char*)p < (char*)map->segs[c].addr + map->segs[c].p_memsz) - return 1; - - return 0; -} - -inline static void * _dl_funcdesc_for (void *entry_point, void *got_value); - #define DL_LOADADDR_TYPE struct elf32_fdpic_loadaddr #define DL_RELOC_ADDR(ADDR, LOADADDR) \ @@ -235,6 +121,11 @@ inline static void * _dl_funcdesc_for (void *entry_point, void *got_value); #define DL_LOADADDR_BASE(LOADADDR) \ ((LOADADDR).got_value) +/* This is called from dladdr(), such that we map a function + descriptor's address to the function's entry point before trying to + find in which library it's defined. */ +#define DL_LOOKUP_ADDRESS(ADDRESS) (_dl_lookup_address (ADDRESS)) + #define DL_ADDR_IN_LOADADDR(ADDR, TPNT, TFROM) \ (! (TFROM) && __dl_addr_in_loadaddr ((void*)(ADDR), (TPNT)->loadaddr)) @@ -272,300 +163,20 @@ while (0) (_dl_pread((FD), (BUF), (SIZE), (OFFSET))) #endif -#include <dl-hash.h> +/* We want to return to dlsym() a function descriptor if the symbol + turns out to be a function. */ +#define DL_FIND_HASH_VALUE(TPNT, TYPE_CLASS, SYM) \ + (((TYPE_CLASS) & ELF_RTYPE_CLASS_DLSYM) \ + && ELF32_ST_TYPE((SYM)->st_info) == STT_FUNC \ + ? _dl_funcdesc_for (DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr), \ + (TPNT)->loadaddr.got_value) \ + : DL_RELOC_ADDR ((SYM)->st_value, (TPNT)->loadaddr)) -/* The hashcode handling code below is heavily inspired in libiberty's - hashtab code, but with most adaptation points and support for - deleting elements removed. - - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - Contributed by Vladimir Makarov (vmakarov@cygnus.com). */ - -inline static unsigned long -higher_prime_number (unsigned long n) -{ - /* These are primes that are near, but slightly smaller than, a - power of two. */ - static const unsigned long primes[] = { - (unsigned long) 7, - (unsigned long) 13, - (unsigned long) 31, - (unsigned long) 61, - (unsigned long) 127, - (unsigned long) 251, - (unsigned long) 509, - (unsigned long) 1021, - (unsigned long) 2039, - (unsigned long) 4093, - (unsigned long) 8191, - (unsigned long) 16381, - (unsigned long) 32749, - (unsigned long) 65521, - (unsigned long) 131071, - (unsigned long) 262139, - (unsigned long) 524287, - (unsigned long) 1048573, - (unsigned long) 2097143, - (unsigned long) 4194301, - (unsigned long) 8388593, - (unsigned long) 16777213, - (unsigned long) 33554393, - (unsigned long) 67108859, - (unsigned long) 134217689, - (unsigned long) 268435399, - (unsigned long) 536870909, - (unsigned long) 1073741789, - (unsigned long) 2147483647, - /* 4294967291L */ - ((unsigned long) 2147483647) + ((unsigned long) 2147483644), - }; - - const unsigned long *low = &primes[0]; - const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])]; - - while (low != high) - { - const unsigned long *mid = low + (high - low) / 2; - if (n > *mid) - low = mid + 1; - else - high = mid; - } - -#if 0 - /* If we've run out of primes, abort. */ - if (n > *low) - { - fprintf (stderr, "Cannot find prime bigger than %lu\n", n); - abort (); - } +/* Make sure dl_iterate_phdr is defined. */ +#ifdef __USE_GNU +# include <link.h> +#else +# define __USE_GNU +# include <link.h> +# undef __USE_GNU #endif - - return *low; -} - -struct funcdesc_ht -{ - /* Table itself. */ - struct funcdesc_value **entries; - - /* Current size (in entries) of the hash table */ - size_t size; - - /* Current number of elements. */ - size_t n_elements; -}; - -inline static int -hash_pointer (const void *p) -{ - return (int) ((long)p >> 3); -} - -inline static struct funcdesc_ht * -htab_create (void) -{ - struct funcdesc_ht *ht = _dl_malloc (sizeof (struct funcdesc_ht)); - - if (! ht) - return NULL; - ht->size = 3; - ht->entries = _dl_malloc (sizeof (struct funcdesc_ht_value *) * ht->size); - if (! ht->entries) - return NULL; - - ht->n_elements = 0; - - _dl_memset (ht->entries, 0, sizeof (struct funcdesc_ht_value *) * ht->size); - - return ht; -} - -inline static void -htab_delete (struct funcdesc_ht *htab) -{ - int i; - - for (i = htab->size - 1; i >= 0; i--) - if (htab->entries[i]) - _dl_free (htab->entries[i]); - - _dl_free (htab->entries); - _dl_free (htab); -} - -/* Similar to htab_find_slot, but without several unwanted side effects: - - Does not call htab->eq_f when it finds an existing entry. - - Does not change the count of elements/searches/collisions in the - hash table. - This function also assumes there are no deleted entries in the table. - HASH is the hash value for the element to be inserted. */ - -inline static struct funcdesc_value ** -find_empty_slot_for_expand (struct funcdesc_ht *htab, int hash) -{ - size_t size = htab->size; - unsigned int index = hash % size; - struct funcdesc_value **slot = htab->entries + index; - int hash2; - - if (! *slot) - return slot; - - hash2 = 1 + hash % (size - 2); - for (;;) - { - index += hash2; - if (index >= size) - index -= size; - - slot = htab->entries + index; - if (! *slot) - return slot; - } -} - -/* The following function changes size of memory allocated for the - entries and repeatedly inserts the table elements. The occupancy - of the table after the call will be about 50%. Naturally the hash - table must already exist. Remember also that the place of the - table entries is changed. If memory allocation failures are allowed, - this function will return zero, indicating that the table could not be - expanded. If all goes well, it will return a non-zero value. */ - -inline static int -htab_expand (struct funcdesc_ht *htab) -{ - struct funcdesc_value **oentries; - struct funcdesc_value **olimit; - struct funcdesc_value **p; - struct funcdesc_value **nentries; - size_t nsize; - - oentries = htab->entries; - olimit = oentries + htab->size; - - /* Resize only when table after removal of unused elements is either - too full or too empty. */ - if (htab->n_elements * 2 > htab->size) - nsize = higher_prime_number (htab->n_elements * 2); - else - nsize = htab->size; - - nentries = _dl_malloc (sizeof (struct funcdesc_value *) * nsize); - _dl_memset (nentries, 0, sizeof (struct funcdesc_value *) * nsize); - if (nentries == NULL) - return 0; - htab->entries = nentries; - htab->size = nsize; - - p = oentries; - do - { - if (*p) - *find_empty_slot_for_expand (htab, hash_pointer ((*p)->entry_point)) - = *p; - - p++; - } - while (p < olimit); - - _dl_free (oentries); - return 1; -} - -/* This function searches for a hash table slot containing an entry - equal to the given element. To delete an entry, call this with - INSERT = 0, then call htab_clear_slot on the slot returned (possibly - after doing some checks). To insert an entry, call this with - INSERT = 1, then write the value you want into the returned slot. - When inserting an entry, NULL may be returned if memory allocation - fails. */ - -inline static struct funcdesc_value ** -htab_find_slot (struct funcdesc_ht *htab, void *ptr) -{ - unsigned int index; - int hash, hash2; - size_t size; - struct funcdesc_value **entry; - - if (htab->size * 3 <= htab->n_elements * 4 - && htab_expand (htab) == 0) - return NULL; - - hash = hash_pointer (ptr); - - size = htab->size; - index = hash % size; - - entry = &htab->entries[index]; - if (!*entry) - goto empty_entry; - else if ((*entry)->entry_point == ptr) - return entry; - - hash2 = 1 + hash % (size - 2); - for (;;) - { - index += hash2; - if (index >= size) - index -= size; - - entry = &htab->entries[index]; - if (!*entry) - goto empty_entry; - else if ((*entry)->entry_point == ptr) - return entry; - } - - empty_entry: - htab->n_elements++; - return entry; -} - -void * -_dl_funcdesc_for (void *entry_point, void *got_value) -{ - struct elf_resolve *tpnt = ((void**)got_value)[2]; - struct funcdesc_ht *ht = tpnt->funcdesc_ht; - struct funcdesc_value **entry; - - _dl_assert (got_value == tpnt->loadaddr.got_value); - - if (! ht) - { - ht = htab_create (); - if (! ht) - return (void*)-1; - tpnt->funcdesc_ht = ht; - } - - entry = htab_find_slot (ht, entry_point); - if (*entry) - { - _dl_assert ((*entry)->entry_point == entry_point); - return _dl_stabilize_funcdesc (*entry); - } - - *entry = _dl_malloc (sizeof (struct funcdesc_value)); - (*entry)->entry_point = entry_point; - (*entry)->got_value = got_value; - - return _dl_stabilize_funcdesc (*entry); -} - -void -__dl_loadaddr_unmap (struct elf32_fdpic_loadaddr loadaddr, - struct funcdesc_ht *funcdesc_ht) -{ - int i; - - for (i = 0; i < loadaddr.map->nsegs; i++) - _dl_munmap ((void*)loadaddr.map->segs[i].addr, - loadaddr.map->segs[i].p_memsz); - - _dl_free (loadaddr.map); - if (funcdesc_ht) - htab_delete (funcdesc_ht); -} diff --git a/ldso/ldso/frv/elfinterp.c b/ldso/ldso/frv/elfinterp.c index dabd84a56..f69f70b7e 100644 --- a/ldso/ldso/frv/elfinterp.c +++ b/ldso/ldso/frv/elfinterp.c @@ -1,5 +1,5 @@ /* FR-V FDPIC ELF shared library loader suppport - Copyright (C) 2003 Red Hat, Inc. + Copyright (C) 2003, 2004 Red Hat, Inc. Contributed by Alexandre Oliva <aoliva@redhat.com> Lots of code copied from ../i386/elfinterp.c, so: Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, @@ -153,11 +153,10 @@ _dl_linux_resolver (struct elf_resolve *tpnt, int reloc_entry) DL_RELOC_ADDR (this_reloc->r_offset, tpnt->loadaddr); /* Get the address to be used to fill in the GOT entry. */ - new_addr = __dl_find_hash(symname, tpnt->symbol_scope, tpnt, resolver, - &new_tpnt); + new_addr = _dl_find_hash_mod(symname, tpnt->symbol_scope, 0, + &new_tpnt); if (!new_addr) { - new_addr = __dl_find_hash(symname, NULL, NULL, resolver, - &new_tpnt); + new_addr = _dl_find_hash_mod(symname, NULL, 0, &new_tpnt); if (!new_addr) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); @@ -279,10 +278,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, } else { symbol_addr = (unsigned long) - __dl_find_hash(symname, scope, - (reloc_type == R_FRV_FUNCDESC_VALUE - ? tpnt : NULL), symbolrel, - &symbol_tpnt); + _dl_find_hash_mod(symname, scope, 0, &symbol_tpnt); /* * We want to allow undefined references to weak symbols - this might @@ -338,7 +334,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, funcval.got_value = 0; asm ("std%I0\t%1, %M0" : "=m" (*(struct funcdesc_value *)reloc_addr) - : "r" (funcval)); + : "e" (funcval)); break; case R_FRV_FUNCDESC: if ((long)reloc_addr_packed & 3) |