sqrt implementation.
[kopensolaris-gnu/glibc.git] / sysdeps / hppa / dl-fptr.c
1 /* Make dynamic PLABELs for function pointers. HPPA version.
2    Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/param.h>
23 #include <sys/mman.h>
24 #include <link.h>
25 #include <errno.h>
26 #include <ldsodefs.h>
27 #include <elf/dynamic-link.h>
28 #include <dl-machine.h>
29 #ifdef _LIBC_REENTRANT
30 # include <pt-machine.h>
31
32 /* Remember, we use 0 to mean that a lock is taken on PA-RISC. */
33 static int __hppa_fptr_lock = 1;
34 #endif
35
36 /* Because ld.so is now versioned, these functions can be in their own
37    file; no relocations need to be done to call them.  Of course, if
38    ld.so is not versioned...  */
39 #if 0
40 #ifndef DO_VERSIONING
41 # error "This will not work with versioning turned off, sorry."
42 #endif
43 #endif
44
45 #ifdef MAP_ANON
46 /* The fd is not examined when using MAP_ANON.  */
47 # define ANONFD -1
48 #else
49 # define ANONFD GL(dl_zerofd)
50 #endif
51
52 struct hppa_fptr __boot_ldso_fptr[HPPA_BOOT_FPTR_SIZE];
53 struct hppa_fptr *__fptr_root = NULL;
54 struct hppa_fptr *__fptr_next = __boot_ldso_fptr;
55 static struct hppa_fptr *__fptr_free = NULL;
56 int __fptr_count = HPPA_BOOT_FPTR_SIZE;
57
58 Elf32_Addr
59 __hppa_make_fptr (const struct link_map *sym_map, Elf32_Addr value,
60                   struct hppa_fptr **root, struct hppa_fptr *mem)
61 {
62   struct hppa_fptr **loc;
63   struct hppa_fptr *f;
64
65 #ifdef _LIBC_REENTRANT
66   /* Make sure we are alone. We don't need a lock during bootstrap. */
67   if (mem == NULL)
68     while (testandset (&__hppa_fptr_lock));
69 #endif
70
71   /* Search the sorted linked list for an existing entry for this
72      symbol.  */
73   loc = root;
74   f = *loc;
75   while (f != NULL && f->func <= value)
76     {
77       if (f->func == value)
78         goto found;
79       loc = &f->next;
80       f = *loc;
81     }
82
83   /* Not found.  Create a new one.  */
84   if (mem != NULL)
85     f = mem;
86   else if (__fptr_free != NULL)
87     {
88       f = __fptr_free;
89       __fptr_free = f->next;
90     }
91   else
92     {
93       if (__fptr_count == 0)
94         {
95 #ifndef MAP_ANON
96 # define MAP_ANON 0
97           if (GL(dl_zerofd) == -1)
98             {
99               GL(dl_zerofd) = _dl_sysdep_open_zero_fill ();
100               if (GL(dl_zerofd) == -1)
101                 {
102                   __close (fd);
103                   _dl_signal_error (errno, NULL, NULL,
104                                     "cannot open zero fill device");
105                 }
106             }
107 #endif
108
109           __fptr_next = __mmap (0, GL(dl_pagesize), PROT_READ | PROT_WRITE,
110                                 MAP_ANON | MAP_PRIVATE, ANONFD, 0);
111           if (__fptr_next == MAP_FAILED)
112             _dl_signal_error(errno, NULL, NULL, "cannot map page for fptr");
113           __fptr_count = GL(dl_pagesize) / sizeof (struct hppa_fptr);
114         }
115       f = __fptr_next++;
116       __fptr_count--;
117     }
118
119   f->func = value;
120   /* GOT has already been relocated in elf_get_dynamic_info - don't
121      try to relocate it again.  */
122   f->gp = sym_map->l_info[DT_PLTGOT]->d_un.d_ptr;
123   f->next = *loc;
124   *loc = f;
125
126 found:
127 #ifdef _LIBC_REENTRANT
128   /* Release the lock.  Again, remember, zero means the lock is taken!  */
129   if (mem == NULL)
130     __hppa_fptr_lock = 1;
131 #endif
132
133   /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */
134   return (Elf32_Addr) f | 2;
135 }
136
137 void
138 _dl_unmap (struct link_map *map)
139 {
140   struct hppa_fptr **floc;
141   struct hppa_fptr *f;
142   struct hppa_fptr **lloc;
143   struct hppa_fptr *l;
144
145   __munmap ((void *) map->l_map_start, map->l_map_end - map->l_map_start);
146
147 #ifdef _LIBC_REENTRANT
148   /* Make sure we are alone.  */
149   while (testandset (&__hppa_fptr_lock));
150 #endif
151
152   /* Search the sorted linked list for the first entry for this object.  */
153   floc = &__fptr_root;
154   f = *floc;
155   while (f != NULL && f->func < map->l_map_start)
156     {
157       floc = &f->next;
158       f = *floc;
159     }
160
161   /* We found one.  */
162   if (f != NULL && f->func < map->l_map_end)
163     {
164       /* Get the last entry.  */
165       lloc = floc;
166       l = f;
167       while (l && l->func < map->l_map_end)
168         {
169           lloc = &l->next;
170           l = *lloc;
171         }
172
173       /* Updated FPTR.  */
174       *floc = l;
175
176       /* Prepend them to the free list.  */
177       *lloc = __fptr_free;
178       __fptr_free = f;
179     }
180
181 #ifdef _LIBC_REENTRANT
182   /* Release the lock. */
183   __hppa_fptr_lock = 1;
184 #endif
185 }
186
187 Elf32_Addr
188 _dl_lookup_address (const void *address)
189 {
190   Elf32_Addr addr = (Elf32_Addr) address;
191   struct hppa_fptr *f;
192
193 #ifdef _LIBC_REENTRANT
194   /* Make sure we are alone.  */
195   while (testandset (&__hppa_fptr_lock));
196 #endif
197
198   for (f = __fptr_root; f != NULL; f = f->next)
199     if (f == address)
200       {
201         addr = f->func;
202         break;
203       }
204
205 #ifdef _LIBC_REENTRANT
206   /* Release the lock.   */
207   __hppa_fptr_lock = 1;
208 #endif
209
210   return addr;
211 }