diff options
Diffstat (limited to 'sysdeps/ia64')
-rw-r--r-- | sysdeps/ia64/dl-fptr.c | 288 |
1 files changed, 0 insertions, 288 deletions
diff --git a/sysdeps/ia64/dl-fptr.c b/sysdeps/ia64/dl-fptr.c deleted file mode 100644 index 3c362b0f87..0000000000 --- a/sysdeps/ia64/dl-fptr.c +++ /dev/null @@ -1,288 +0,0 @@ -/* Manage function descriptors. IA-64 version. - Copyright (C) 1999,2000,2001,2002,2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library 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. - - The GNU C Library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include <ia64intrin.h> -#include <unistd.h> -#include <string.h> -#include <sys/param.h> -#include <sys/mman.h> -#include <link.h> -#include <ldsodefs.h> -#include <elf/dynamic-link.h> -#include <dl-machine.h> -#ifdef _LIBC_REENTRANT -# include <ia64intrin.h> -# include <signal.h> -# include <time.h> -#endif - -Elf64_Addr __ia64_boot_fptr_table[IA64_BOOT_FPTR_TABLE_LEN]; - -static struct local - { - struct ia64_fdesc_table *root; - struct ia64_fdesc *free_list; - unsigned int npages; /* # of pages to allocate */ -#ifdef _LIBC_REENTRANT - volatile int lock; - sigset_t full_sigset; -#endif - /* the next to members MUST be consecutive! */ - struct ia64_fdesc_table boot_table; - struct ia64_fdesc boot_fdescs[1024]; - } -local = - { - root: &local.boot_table, - npages: 2, - boot_table: - { - len: sizeof (local.boot_fdescs) / sizeof (local.boot_fdescs[0]), - first_unused: 0 - } - }; - -/* Locking is tricky: we may get a signal while holding the lock and - the signal handler may end up calling into the dynamic loader - again. Also, if a real-time process spins on the lock, a - non-realtime process may never get the chance to release it's lock, - unless the realtime process relinquishes the CPU from time to time. - Hence we (a) block signals before acquiring the lock and (b) do a - nanosleep() when we detect prolongued contention. */ -#ifdef _LIBC_REENTRANT -# define lock(l) \ -{ \ - sigset_t _saved_set; \ - int i = 10000; \ - if (!__sigismember (&(l)->full_sigset, SIGINT)) \ - __sigfillset (&(l)->full_sigset); \ - \ - while (__sync_lock_test_and_set (&(l)->lock, 1)) \ - { \ - struct timespec ts; \ - if (i > 0) \ - { \ - --i; \ - continue; \ - } \ - ts.tv_sec = 0; \ - ts.tv_nsec = 1*1000*1000; \ - __nanosleep (&ts, NULL); \ - } \ - __sigprocmask (SIG_BLOCK, &(l)->full_sigset, &_saved_set); -# define unlock(l) \ - __sigprocmask (SIG_SETMASK, &_saved_set, NULL); \ - __sync_lock_release (&(l)->lock); \ -} -#else -# define lock(l) -# define unlock(l) -#endif - -/* Create a new fdesc table and return a pointer to the first fdesc - entry. The fdesc lock must have been acquired already. */ - -static struct ia64_fdesc * -new_fdesc_table (struct local *l) -{ - size_t size = l->npages * GL(dl_pagesize); - struct ia64_fdesc_table *new_table; - struct ia64_fdesc *fdesc; - - l->npages += l->npages; - new_table = __mmap (0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - if (new_table == MAP_FAILED) - _dl_signal_error (errno, NULL, NULL, "cannot map pages for fdesc table"); - - new_table->len = (size - sizeof (*new_table)) / sizeof (struct ia64_fdesc); - fdesc = &new_table->fdesc[0]; - new_table->first_unused = 1; - new_table->next = l->root; - l->root = new_table; - return fdesc; -} - -static Elf64_Addr -make_fdesc (Elf64_Addr ip, Elf64_Addr gp) -{ - struct ia64_fdesc *fdesc = NULL; - struct ia64_fdesc_table *t; - unsigned int old; - struct local *l; - - asm ("movl %0 = @gprel (local);; add %0 = %0, gp" : "=&r"(l)); - - t = l->root; - while (1) - { - old = t->first_unused; - if (old >= t->len) - break; - else if (__sync_bool_compare_and_swap (&t->first_unused, old, old + 1)) - { - fdesc = &t->fdesc[old]; - goto install; - } - } - - lock (l); - { - if (l->free_list) - { - fdesc = l->free_list; /* get it from free-list */ - l->free_list = (struct ia64_fdesc *) fdesc->ip; - } - else - fdesc = new_fdesc_table (l); /* create new fdesc table */ - } - unlock (l); - - install: - fdesc->ip = ip; - fdesc->gp = gp; - - return (Elf64_Addr) fdesc; -} - -static inline Elf64_Addr * -make_fptr_table (struct link_map *map) -{ - const Elf64_Sym *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); - const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); - Elf64_Addr *fptr_table; - size_t size; - size_t len; - - /* XXX Apparently the only way to find out the size of the dynamic - symbol section is to assume that the string table follows right - afterwards... */ - len = ((strtab - (char *) symtab) / map->l_info[DT_SYMENT]->d_un.d_val); - size = ((len * sizeof (fptr_table[0]) + GL(dl_pagesize) - 1) - & -GL(dl_pagesize)); - /* XXX We don't support here in the moment systems without MAP_ANON. - There probably are none for IA-64. In case this is proven wrong - we will have to open /dev/null here and use the file descriptor - instead of the hard-coded -1. */ - fptr_table = __mmap (NULL, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - if (fptr_table == MAP_FAILED) - _dl_signal_error (errno, NULL, NULL, "cannot map pages for fptr table"); - - map->l_mach.fptr_table_len = len; - map->l_mach.fptr_table = fptr_table; - return fptr_table; -} - -Elf64_Addr -__ia64_make_fptr (struct link_map *map, const Elf64_Sym *sym, Elf64_Addr ip) -{ - Elf64_Addr *ftab = map->l_mach.fptr_table; - const Elf64_Sym *symtab; - Elf_Symndx symidx; - - if (__builtin_expect (!map->l_mach.fptr_table, 0)) - ftab = make_fptr_table (map); - - symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); - symidx = sym - symtab; - - if (symidx >= map->l_mach.fptr_table_len) - _dl_signal_error (0, NULL, NULL, - "internal error: symidx out of range of fptr table"); - - if (!ftab[symidx]) - { - /* GOT has already been relocated in elf_get_dynamic_info - - don't try to relocate it again. */ - ftab[symidx] = make_fdesc (ip, map->l_info[DT_PLTGOT]->d_un.d_ptr); -#if 0 - { - const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); - struct local *l; - - asm ("addl %0 = @gprel (local), gp" : "=r" (l)); - if (l->root != &l->boot_table || l->boot_table.first_unused > 20) - _dl_debug_printf ("created fdesc symbol `%s' at %lx\n", - strtab + sym->st_name, ftab[symidx]); - } -#endif - } - - return ftab[symidx]; -} - -void -_dl_unmap (struct link_map *map) -{ - Elf64_Addr *ftab = map->l_mach.fptr_table; - struct ia64_fdesc *head = NULL, *tail = NULL; - size_t i; - - __munmap ((void *) map->l_map_start, map->l_map_end - map->l_map_start); - - if (!ftab) - return; - - /* String together the fdesc structures that are being freed. */ - for (i = 0; i < map->l_mach.fptr_table_len; ++i) - { - if (ftab[i]) - { - *(struct ia64_fdesc **) ftab[i] = head; - head = (struct ia64_fdesc *) ftab[i]; - if (!tail) - tail = head; - } - } - - /* Prepend the new list to the free_list: */ - if (tail) - { - lock (&local); - { - *(struct ia64_fdesc **) tail = local.free_list; - local.free_list = head; - } - unlock (&local); - } - - __munmap (ftab, - map->l_mach.fptr_table_len * sizeof (map->l_mach.fptr_table[0])); - map->l_mach.fptr_table = NULL; -} - -Elf64_Addr -_dl_lookup_address (const void *address) -{ - Elf64_Addr addr = (Elf64_Addr) address; - struct ia64_fdesc_table *t; - unsigned long int i; - - for (t = local.root; t != NULL; t = t->next) - { - i = (struct ia64_fdesc *) addr - &t->fdesc[0]; - if (i < t->first_unused && addr == (Elf64_Addr) &t->fdesc[i]) - { - addr = t->fdesc[i].ip; - break; - } - } - return addr; -} |