Clear the exception flags, not the enable flags.
[kopensolaris-gnu/glibc.git] / sysdeps / hppa / dl-fptr.c
1 /* Make dynamic PLABELs for function pointers. HPPA version.
2    Copyright (C) 1999, 2000 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 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 extern int _dl_zerofd;
50 #define ANONFD _dl_zerofd
51 #endif
52
53 struct hppa_fptr __boot_ldso_fptr[HPPA_BOOT_FPTR_SIZE];
54 struct hppa_fptr *__fptr_root = NULL;
55 struct hppa_fptr *__fptr_next = __boot_ldso_fptr;
56 static struct hppa_fptr *__fptr_free = NULL;
57 int __fptr_count = HPPA_BOOT_FPTR_SIZE;
58
59 Elf32_Addr
60 __hppa_make_fptr (const struct link_map *sym_map, Elf32_Addr value,
61                   struct hppa_fptr **root, struct hppa_fptr *mem)
62 {
63   struct hppa_fptr **loc;
64   struct hppa_fptr *f;
65
66 #ifdef _LIBC_REENTRANT
67   /* Make sure we are alone. We don't need a lock during bootstrap. */
68   if (mem == NULL)
69     while (testandset (&__hppa_fptr_lock));
70 #endif
71
72   /* Search the sorted linked list for an existing entry for this
73      symbol.  */
74   loc = root;
75   f = *loc;
76   while (f != NULL && f->func <= value)
77     {
78       if (f->func == value)
79         goto found;
80       loc = &f->next;
81       f = *loc;
82     }
83
84   /* Not found.  Create a new one.  */
85   if (mem != NULL)
86     f = mem;
87   else if (__fptr_free != NULL)
88     {
89       f = __fptr_free;
90       __fptr_free = f->next;
91     }
92   else
93     {
94       if (__fptr_count == 0)
95         {
96 #ifndef MAP_ANON
97 # define MAP_ANON 0
98           if (_dl_zerofd == -1)
99             {
100               _dl_zerofd = _dl_sysdep_open_zero_fill ();
101               if (_dl_zerofd == -1)
102                 {
103                   __close (fd);
104                   _dl_signal_error (errno, NULL,
105                                     "cannot open zero fill device");
106                 }
107             }
108 #endif
109
110           __fptr_next = __mmap (0, _dl_pagesize, PROT_READ | PROT_WRITE,
111                                 MAP_ANON | MAP_PRIVATE, ANONFD, 0);
112           if (__fptr_next == MAP_FAILED)
113             _dl_signal_error(errno, NULL, "cannot map page for fptr");
114           __fptr_count = _dl_pagesize / sizeof (struct hppa_fptr);
115         }
116       f = __fptr_next++;
117       __fptr_count--;
118     }
119
120   f->func = value;
121   /* GOT has already been relocated in elf_get_dynamic_info - don't
122      try to relocate it again.  */
123   f->gp = sym_map->l_info[DT_PLTGOT]->d_un.d_ptr;
124   f->next = *loc;
125   *loc = f;
126
127 found:
128 #ifdef _LIBC_REENTRANT
129   /* Release the lock.  Again, remember, zero means the lock is taken!  */
130   if (mem == NULL)
131     __hppa_fptr_lock = 1;
132 #endif
133
134   /* Set bit 30 to indicate to $$dyncall that this is a PLABEL. */
135   return (Elf32_Addr) f | 2;
136 }
137
138 void
139 _dl_unmap (struct link_map *map)
140 {
141   struct hppa_fptr **floc;
142   struct hppa_fptr *f;
143   struct hppa_fptr **lloc;
144   struct hppa_fptr *l;
145
146   __munmap ((void *) map->l_map_start, map->l_map_end - map->l_map_start);
147
148 #ifdef _LIBC_REENTRANT
149   /* Make sure we are alone.  */
150   while (testandset (&__hppa_fptr_lock));
151 #endif
152
153   /* Search the sorted linked list for the first entry for this object.  */
154   floc = &__fptr_root;
155   f = *floc;
156   while (f != NULL && f->func < map->l_map_start)
157     {
158       floc = &f->next;
159       f = *floc;
160     }
161
162   /* We found one.  */
163   if (f != NULL && f->func < map->l_map_end)
164     {
165       /* Get the last entry.  */
166       lloc = floc;
167       l = f;
168       while (l && l->func < map->l_map_end)
169         {
170           lloc = &l->next;
171           l = *lloc;
172         }
173
174       /* Updated FPTR.  */
175       *floc = l;
176
177       /* Prepend them to the free list.  */
178       *lloc = __fptr_free;
179       __fptr_free = f;
180     }
181
182 #ifdef _LIBC_REENTRANT
183   /* Release the lock. */
184   __hppa_fptr_lock = 1;
185 #endif
186 }
187
188 Elf32_Addr
189 _dl_lookup_address (const void *address)
190 {
191   Elf32_Addr addr = (Elf32_Addr) address;
192   struct hppa_fptr *f;
193
194 #ifdef _LIBC_REENTRANT
195   /* Make sure we are alone.  */
196   while (testandset (&__hppa_fptr_lock));
197 #endif
198
199   for (f = __fptr_root; f != NULL; f = f->next)
200     if (f == address)
201       {
202         addr = f->func;
203         break;
204       }
205
206 #ifdef _LIBC_REENTRANT
207   /* Release the lock.   */
208   __hppa_fptr_lock = 1;
209 #endif
210
211   return addr;
212 }