* sysdeps/unix/readdir.c: Make sure we don't modify errno when we reached EOF.
[glibc.git] / sysdeps / ia64 / dl-fptr.c
blob85fefa3ea89e25dc1d25b8e60a27a7c8a6b97eeb
1 /* Unmap a loaded object. IA-64 version.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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. */
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/param.h>
23 #include <sys/mman.h>
24 #include <link.h>
25 #include <ldsodefs.h>
26 #include <elf/dynamic-link.h>
27 #include <dl-machine.h>
28 #ifdef _LIBC_REENTRANT
29 # include <pt-machine.h>
31 static int __ia64_fptr_lock = 0;
32 #endif
34 /* Because ld.so is now versioned, these functions can be in their own
35 file; no relocations need to be done to call them. Of course, if
36 ld.so is not versioned... */
37 #if 0
38 #ifndef DO_VERSIONING
39 # error "This will not work with versioning turned off, sorry."
40 #endif
41 #endif
43 #ifdef MAP_ANON
44 /* The fd is not examined when using MAP_ANON. */
45 #define ANONFD -1
46 #else
47 extern int _dl_zerofd;
48 #define ANONFD _dl_zerofd
49 #endif
52 /* ld.so currently has 14 FPTR relocs, we take 256 and use them for
53 the relocs for the dynamic app itself. */
54 struct ia64_fptr __boot_ldso_fptr[IA64_BOOT_FPTR_SIZE];
55 struct ia64_fptr *__fptr_root = NULL;
56 struct ia64_fptr *__fptr_next = __boot_ldso_fptr;
57 static struct ia64_fptr *__fptr_free = NULL;
58 int __fptr_count = IA64_BOOT_FPTR_SIZE;
60 Elf64_Addr
61 __ia64_make_fptr (const struct link_map *sym_map, Elf64_Addr value,
62 struct ia64_fptr **root, struct ia64_fptr *mem)
64 struct ia64_fptr **loc;
65 struct ia64_fptr *f;
67 #ifdef _LIBC_REENTRANT
68 /* Make sure we are alone. We don't need a lock during bootstrap. */
69 if (mem == NULL)
70 while (testandset (&__ia64_fptr_lock));
71 #endif
73 /* Search the sorted linked list for an existing entry for this
74 symbol. */
75 loc = root;
76 f = *loc;
77 while (f != NULL && f->func <= value)
79 if (f->func == value)
80 goto found;
81 loc = &f->next;
82 f = *loc;
85 /* Not found. Create a new one. */
86 if (mem != NULL)
87 f = mem;
88 else if (__fptr_free != NULL)
90 f = __fptr_free;
91 __fptr_free = f->next;
93 else
95 if (__fptr_count == 0)
97 #ifndef MAP_ANON
98 # define MAP_ANON 0
99 if (_dl_zerofd == -1)
101 _dl_zerofd = _dl_sysdep_open_zero_fill ();
102 if (_dl_zerofd == -1)
104 __close (fd);
105 _dl_signal_error (errno, NULL,
106 "cannot open zero fill device");
109 #endif
111 __fptr_next = __mmap (0, _dl_pagesize, PROT_READ | PROT_WRITE,
112 MAP_ANON | MAP_PRIVATE, ANONFD, 0);
113 if (__fptr_next == MAP_FAILED)
114 _dl_signal_error(errno, NULL, "cannot map page for fptr");
115 __fptr_count = _dl_pagesize / sizeof (struct ia64_fptr);
117 f = __fptr_next++;
118 __fptr_count--;
121 f->func = value;
122 /* GOT has already been relocated in elf_get_dynamic_info - don't
123 try to relocate it again. */
124 f->gp = sym_map->l_info[DT_PLTGOT]->d_un.d_ptr;
125 f->next = *loc;
126 *loc = f;
128 found:
129 #ifdef _LIBC_REENTRANT
130 /* Release the lock. */
131 if (mem == NULL)
132 __ia64_fptr_lock = 0;
133 #endif
135 return (Elf64_Addr) f;
138 void
139 _dl_unmap (struct link_map *map)
141 struct ia64_fptr **floc;
142 struct ia64_fptr *f;
143 struct ia64_fptr **lloc;
144 struct ia64_fptr *l;
146 __munmap ((void *) map->l_map_start, map->l_map_end - map->l_map_start);
148 #ifdef _LIBC_REENTRANT
149 /* Make sure we are alone. */
150 while (testandset (&__ia64_fptr_lock));
151 #endif
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)
158 floc = &f->next;
159 f = *floc;
162 /* We found one. */
163 if (f != NULL && f->func < map->l_map_end)
165 /* Get the last entry. */
166 lloc = floc;
167 l = f;
168 while (l && l->func < map->l_map_end)
170 lloc = &l->next;
171 l = *lloc;
174 /* Updated FPTR. */
175 *floc = l;
177 /* Prepend them to the free list. */
178 *lloc = __fptr_free;
179 __fptr_free = f;
182 #ifdef _LIBC_REENTRANT
183 /* Release the lock. */
184 __ia64_fptr_lock = 0;
185 #endif
188 Elf64_Addr
189 _dl_lookup_address (const void *address)
191 Elf64_Addr addr = (Elf64_Addr) address;
192 struct ia64_fptr *f;
194 #ifdef _LIBC_REENTRANT
195 /* Make sure we are alone. */
196 while (testandset (&__ia64_fptr_lock));
197 #endif
199 for (f = __fptr_root; f != NULL; f = f->next)
200 if (f == address)
202 addr = f->func;
203 break;
206 #ifdef _LIBC_REENTRANT
207 /* Release the lock. */
208 __ia64_fptr_lock = 0;
209 #endif
211 return addr;