PATCH: Add generic function descripto support
H . J . Lu
hjl@lucon.org
Fri Sep 28 08:04:00 GMT 2001
On Thu, Sep 27, 2001 at 10:45:25AM -0700, David Mosberger wrote:
>
> HJ> BTW, I think glibc should have a generic implementation for
> HJ> function descriptors so that ia64, hppa, ... can share the code.
>
> That sounds like a good idea.
>
Here is a patch. Someone should try to convert hppa. It shouldn't be
too hard.
H.J.
---
2001-09-28 H.J. Lu <hjl@gnu.org>
* sysdeps/generic/dl-fptr.c (lock): Block signals before
acquiring lock.
(unlock): Unblock signals after releasing lock.
* sysdeps/ia64/dl-lookupcfg.h (_dl_symbol_address): Remove
`const'.
* sysdeps/ia64/dl-machine.h: Include <dl-fptr.h>.
(IA64_BOOT_FPTR_TABLE_LEN): Removed.
(ia64_fdesc): Likewise.
(ia64_fdesc_table): Likewise.
(__ia64_make_fptr): Likewise.
(__ia64_init_bootstrap_fdesc_table): Replace __ia64_boot_fptr_table
with _dl_boot_fptr_table.
(elf_machine_runtime_setup): Replace `struct ia64_fdesc' with
`struct fdesc'.
(elf_machine_rela): Replace __ia64_make_fptr with _dl_make_fptr.
* sysdeps/generic/dl-fptr.h: New.
* sysdeps/ia64/dl-fptr.h: New.
* sysdeps/generic/dl-symaddr.c: New.
* sysdeps/ia64/dl-symaddr.c: Removed.
* sysdeps/ia64/dl-fptr.c: Moved to ...
* sysdeps/generic/dl-fptr.c: Here.
--- libc/sysdeps/generic/dl-fptr.c.fptr Thu Sep 27 19:39:58 2001
+++ libc/sysdeps/generic/dl-fptr.c Fri Sep 28 06:45:10 2001
@@ -0,0 +1,299 @@
+/* Manage function descriptors. Generic version.
+ Copyright (C) 1999, 2000, 2001 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 <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-fptr.h>
+#ifdef _LIBC_REENTRANT
+# include <pt-machine.h>
+# include <signal.h>
+# include <time.h>
+#else
+# include <atomicity.h>
+#endif
+
+#ifndef ELF_MACHINE_BOOT_FPTR_TABLE_LEN
+/* ELF_MACHINE_BOOT_FPTR_TABLE_LEN should be greater than the number of
+ dynamic symbols in ld.so. */
+#define ELF_MACHINE_BOOT_FPTR_TABLE_LEN 256
+#endif
+
+#ifndef ELF_MACHINE_LOAD_ADDRESS
+# error "ELF_MACHINE_LOAD_ADDRESS is not defined."
+#endif
+
+ElfW(Addr) _dl_boot_fptr_table [ELF_MACHINE_BOOT_FPTR_TABLE_LEN];
+
+static struct local
+ {
+ struct fdesc_table *root;
+ struct 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 fdesc_table boot_table;
+ struct 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); \
+ __sigprocmask (SIG_BLOCK, &(l)->full_sigset, &_saved_set); \
+ \
+ while (testandset ((int *) &(l)->lock)) \
+ { \
+ struct timespec ts; \
+ if (i > 0) \
+ { \
+ --i; \
+ continue; \
+ } \
+ ts.tv_sec = 0; \
+ ts.tv_nsec = 1*1000*1000; \
+ __nanosleep (&ts, NULL); \
+ }
+# define unlock(l) \
+ (l)->lock = 0; \
+ __sigprocmask (SIG_SETMASK, &_saved_set, NULL); \
+}
+#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 fdesc *
+new_fdesc_table (struct local *l)
+{
+ size_t size = l->npages * _dl_pagesize;
+ struct fdesc_table *new_table;
+ struct 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 fdesc);
+ fdesc = &new_table->fdesc[0];
+ new_table->first_unused = 1;
+ new_table->next = l->root;
+ l->root = new_table;
+ return fdesc;
+}
+
+static ElfW(Addr)
+make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp)
+{
+ struct fdesc *fdesc = NULL;
+ struct fdesc_table *t;
+ unsigned int old;
+ struct local *l;
+
+ ELF_MACHINE_LOAD_ADDRESS (l, local);
+
+ t = l->root;
+ while (1)
+ {
+ old = t->first_unused;
+ if (old >= t->len)
+ break;
+ else if (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 fdesc *) fdesc->ip;
+ }
+ else
+ fdesc = new_fdesc_table (l); /* create new fdesc table */
+ }
+ unlock (l);
+
+ install:
+ fdesc->ip = ip;
+ fdesc->gp = gp;
+
+ return (ElfW(Addr)) fdesc;
+}
+
+static inline ElfW(Addr) *
+make_fptr_table (struct link_map *map)
+{
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ ElfW(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]) + _dl_pagesize - 1) & -_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;
+}
+
+ElfW(Addr)
+_dl_make_fptr (struct link_map *map, const ElfW(Sym) *sym,
+ ElfW(Addr) ip)
+{
+ ElfW(Addr) *ftab = map->l_mach.fptr_table;
+ const ElfW(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;
+
+ ELF_MACHINE_LOAD_ADDRESS (l, local);
+ 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)
+{
+ ElfW(Addr) *ftab = map->l_mach.fptr_table;
+ struct 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 fdesc **) ftab[i] = head;
+ head = (struct fdesc *) ftab[i];
+ if (!tail)
+ tail = head;
+ }
+ }
+
+ /* Prepend the new list to the free_list: */
+ if (tail)
+ {
+ lock (&local);
+ {
+ *(struct 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;
+}
+
+ElfW(Addr)
+_dl_lookup_address (const void *address)
+{
+ ElfW(Addr) addr = (ElfW(Addr)) address;
+ struct fdesc_table *t;
+ unsigned long int i;
+
+ for (t = local.root; t != NULL; t = t->next)
+ {
+ i = (struct fdesc *) addr - &t->fdesc[0];
+ if (i < t->first_unused && addr == (ElfW(Addr)) &t->fdesc[i])
+ {
+ addr = t->fdesc[i].ip;
+ break;
+ }
+ }
+ return addr;
+}
--- libc/sysdeps/generic/dl-fptr.h.fptr Thu Sep 27 19:40:05 2001
+++ libc/sysdeps/generic/dl-fptr.h Thu Sep 27 19:40:56 2001
@@ -0,0 +1,44 @@
+/* Function descriptors. Generic version.
+ Copyright (C) 1995, 1996, 1997, 2000, 2001 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. */
+
+#ifndef dl_fptr_h
+#define dl_fptr_h 1
+
+/* An FDESC is a function descriptor. */
+
+struct fdesc
+ {
+ ElfW(Addr) ip; /* code entry point */
+ ElfW(Addr) gp; /* global pointer */
+ };
+
+struct fdesc_table
+ {
+ struct fdesc_table *next;
+ unsigned int len; /* # of entries in fdesc table */
+ volatile unsigned int first_unused; /* index of first available entry */
+ struct fdesc fdesc[0];
+ };
+
+extern ElfW(Addr) _dl_boot_fptr_table [];
+
+extern ElfW(Addr) _dl_make_fptr (struct link_map *, const ElfW(Sym) *,
+ ElfW(Addr));
+
+#endif /* !dl_fptr_h */
--- libc/sysdeps/generic/dl-symaddr.c.fptr Thu Sep 27 16:48:17 2001
+++ libc/sysdeps/generic/dl-symaddr.c Thu Sep 27 19:38:18 2001
@@ -0,0 +1,33 @@
+/* Get the symbol address. Generic version.
+ Copyright (C) 1999, 2000, 2001 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 <ldsodefs.h>
+#include <dl-fptr.h>
+
+void *
+_dl_symbol_address (struct link_map *map, const ElfW(Sym) *ref)
+{
+ Elf64_Addr value = (map ? map->l_addr : 0) + ref->st_value;
+
+ /* Return the pointer to function descriptor. */
+ if (ELFW(ST_TYPE) (ref->st_info) == STT_FUNC)
+ return (void *) _dl_make_fptr (map, ref, value);
+ else
+ return (void *) value;
+}
--- libc/sysdeps/ia64/dl-fptr.c.fptr Sat Sep 8 10:16:44 2001
+++ libc/sysdeps/ia64/dl-fptr.c Fri Sep 28 06:57:55 2001
@@ -1,287 +0,0 @@
-/* Manage function descriptors. IA-64 version.
- Copyright (C) 1999, 2000, 2001 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 <pt-machine.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 (testandset ((int *) &(l)->lock)) \
- { \
- 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); \
- (l)->lock = 0; \
-}
-#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 * _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 ("addl %0 = @gprel (local), 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]) + _dl_pagesize - 1) & -_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;
-}
--- libc/sysdeps/ia64/dl-fptr.h.fptr Thu Sep 27 17:03:56 2001
+++ libc/sysdeps/ia64/dl-fptr.h Thu Sep 27 19:39:14 2001
@@ -0,0 +1,36 @@
+/* Function descriptors. IA64 version.
+ Copyright (C) 1995, 1996, 1997, 2000, 2001 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. */
+
+#ifndef dl_ia64_fptr_h
+#define dl_ia64_fptr_h 1
+
+#include <ia64intrin.h>
+#include <sysdeps/generic/dl-fptr.h>
+
+#define compare_and_swap(ptr,old,new) \
+ __sync_bool_compare_and_swap ((ptr), (old), (new))
+
+/* There are currently 123 dynamic symbols in ld.so.
+ ELF_MACHINE_BOOT_FPTR_TABLE_LEN needs to be at least that big. */
+#define ELF_MACHINE_BOOT_FPTR_TABLE_LEN 200
+
+#define ELF_MACHINE_LOAD_ADDRESS(var,symbol) \
+ asm ("addl %0 = @gprel (" #symbol "), gp" : "=r" (var));
+
+#endif /* !dl_ia64_fptr_h */
--- libc/sysdeps/ia64/dl-lookupcfg.h.fptr Thu Sep 27 17:21:37 2001
+++ libc/sysdeps/ia64/dl-lookupcfg.h Thu Sep 27 17:20:54 2001
@@ -26,7 +26,7 @@
/* Forward declaration. */
struct link_map;
-extern void *_dl_symbol_address (const struct link_map *map,
+extern void *_dl_symbol_address (struct link_map *map,
const Elf64_Sym *ref);
#define DL_SYMBOL_ADDRESS(map, ref) _dl_symbol_address(map, ref)
--- libc/sysdeps/ia64/dl-machine.h.fptr Thu Aug 30 16:09:10 2001
+++ libc/sysdeps/ia64/dl-machine.h Thu Sep 27 17:06:35 2001
@@ -26,44 +26,21 @@
#include <string.h>
#include <link.h>
#include <errno.h>
-
+#include <dl-fptr.h>
/* Translate a processor specific dynamic tag to the index
in l_info array. */
#define DT_IA_64(x) (DT_IA_64_##x - DT_LOPROC + DT_NUM)
-/* There are currently 123 dynamic symbols in ld.so.
- IA64_BOOT_FPTR_TABLE_LEN needs to be at least that big. */
-#define IA64_BOOT_FPTR_TABLE_LEN 200
-
-/* An FDESC is a function descriptor. */
-
-struct ia64_fdesc
- {
- Elf64_Addr ip; /* code entry point */
- Elf64_Addr gp; /* global pointer */
- };
-
-struct ia64_fdesc_table
- {
- struct ia64_fdesc_table *next;
- unsigned int len; /* # of entries in fdesc table */
- volatile unsigned int first_unused; /* index of first available entry */
- struct ia64_fdesc fdesc[0];
- };
-
-extern Elf64_Addr __ia64_make_fptr (struct link_map *, const Elf64_Sym *,
- Elf64_Addr);
-
static inline void
__ia64_init_bootstrap_fdesc_table (struct link_map *map)
{
Elf64_Addr *boot_table;
/* careful: this will be called before got has been relocated... */
- asm ("addl %0 = @gprel (__ia64_boot_fptr_table), gp" : "=r"(boot_table));
+ asm ("addl %0 = @gprel (_dl_boot_fptr_table), gp" : "=r"(boot_table));
- map->l_mach.fptr_table_len = IA64_BOOT_FPTR_TABLE_LEN;
+ map->l_mach.fptr_table_len = ELF_MACHINE_BOOT_FPTR_TABLE_LEN;
map->l_mach.fptr_table = boot_table;
}
@@ -142,7 +119,7 @@ elf_machine_runtime_setup (struct link_m
/* This function will be called to perform the relocation. */
if (!profile)
- doit = (Elf64_Addr) ((struct ia64_fdesc *) &_dl_runtime_resolve)->ip;
+ doit = (Elf64_Addr) ((struct fdesc *) &_dl_runtime_resolve)->ip;
else
{
if (_dl_name_match_p (_dl_profile, l))
@@ -151,7 +128,7 @@ elf_machine_runtime_setup (struct link_m
want profiling and the timers are started. */
_dl_profile_map = l;
}
- doit = (Elf64_Addr) ((struct ia64_fdesc *) &_dl_runtime_profile)->ip;
+ doit = (Elf64_Addr) ((struct fdesc *) &_dl_runtime_profile)->ip;
}
reserve[1] = doit;
@@ -555,7 +532,7 @@ elf_machine_rela (struct link_map *map,
return;
}
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_FPTR64LSB))
- value = __ia64_make_fptr (sym_map, sym, value);
+ value = _dl_make_fptr (sym_map, sym, value);
else if (R_IA64_TYPE (r_type) == R_IA64_TYPE (R_IA64_PCREL64LSB))
value -= (Elf64_Addr) reloc_addr & -16;
else
--- libc/sysdeps/ia64/dl-symaddr.c.fptr Wed Jul 25 17:22:42 2001
+++ libc/sysdeps/ia64/dl-symaddr.c Fri Sep 28 06:57:55 2001
@@ -1,33 +0,0 @@
-/* Get the symbol address. IA-64 version.
- Copyright (C) 1999, 2000, 2001 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 <ldsodefs.h>
-#include <dl-machine.h>
-
-void *
-_dl_symbol_address (const struct link_map *map, const Elf64_Sym *ref)
-{
- Elf64_Addr value = (map ? map->l_addr : 0) + ref->st_value;
-
- /* On ia64, we have to return the pointer to function descriptor. */
- if (ELFW(ST_TYPE) (ref->st_info) == STT_FUNC)
- return (void *) __ia64_make_fptr (map, ref, value);
- else
- return (void *) value;
-}
More information about the Libc-alpha
mailing list