Remove conditional code which now is unnecessary.
[kopensolaris-gnu/glibc.git] / sysdeps / i386 / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  i386 version.
2    Copyright (C) 1995-2005, 2006 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 #ifndef dl_machine_h
21 #define dl_machine_h
22
23 #define ELF_MACHINE_NAME "i386"
24
25 #include <sys/param.h>
26 #include <sysdep.h>
27 #include <tls.h>
28
29 /* Return nonzero iff ELF header is compatible with the running host.  */
30 static inline int __attribute__ ((unused))
31 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
32 {
33   return ehdr->e_machine == EM_386;
34 }
35
36
37 #ifdef PI_STATIC_AND_HIDDEN
38
39 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
40    first element of the GOT, a special entry that is never relocated.  */
41 static inline Elf32_Addr __attribute__ ((unused, const))
42 elf_machine_dynamic (void)
43 {
44   /* This produces a GOTOFF reloc that resolves to zero at link time, so in
45      fact just loads from the GOT register directly.  By doing it without
46      an asm we can let the compiler choose any register.  */
47   extern const Elf32_Addr _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
48   return _GLOBAL_OFFSET_TABLE_[0];
49 }
50
51 /* Return the run-time load address of the shared object.  */
52 static inline Elf32_Addr __attribute__ ((unused))
53 elf_machine_load_address (void)
54 {
55   /* Compute the difference between the runtime address of _DYNAMIC as seen
56      by a GOTOFF reference, and the link-time address found in the special
57      unrelocated first GOT entry.  */
58   extern Elf32_Dyn bygotoff[] asm ("_DYNAMIC") attribute_hidden;
59   return (Elf32_Addr) &bygotoff - elf_machine_dynamic ();
60 }
61
62 #else  /* Without .hidden support, we can't compile the code above.  */
63
64 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
65    first element of the GOT.  This must be inlined in a function which
66    uses global data.  */
67 static inline Elf32_Addr __attribute__ ((unused))
68 elf_machine_dynamic (void)
69 {
70   register Elf32_Addr *got asm ("%ebx");
71   return *got;
72 }
73
74
75 /* Return the run-time load address of the shared object.  */
76 static inline Elf32_Addr __attribute__ ((unused))
77 elf_machine_load_address (void)
78 {
79   /* It doesn't matter what variable this is, the reference never makes
80      it to assembly.  We need a dummy reference to some global variable
81      via the GOT to make sure the compiler initialized %ebx in time.  */
82   extern int _dl_argc;
83   Elf32_Addr addr;
84   asm ("leal _dl_start@GOTOFF(%%ebx), %0\n"
85        "subl _dl_start@GOT(%%ebx), %0"
86        : "=r" (addr) : "m" (_dl_argc) : "cc");
87   return addr;
88 }
89
90 #endif
91
92
93 /* Set up the loaded object described by L so its unrelocated PLT
94    entries will jump to the on-demand fixup code in dl-runtime.c.  */
95
96 static inline int __attribute__ ((unused, always_inline))
97 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
98 {
99   Elf32_Addr *got;
100   extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
101   extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
102
103   if (l->l_info[DT_JMPREL] && lazy)
104     {
105       /* The GOT entries for functions in the PLT have not yet been filled
106          in.  Their initial contents will arrange when called to push an
107          offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
108          and then jump to _GLOBAL_OFFSET_TABLE[2].  */
109       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
110       /* If a library is prelinked but we have to relocate anyway,
111          we have to be able to undo the prelinking of .got.plt.
112          The prelinker saved us here address of .plt + 0x16.  */
113       if (got[1])
114         {
115           l->l_mach.plt = got[1] + l->l_addr;
116           l->l_mach.gotplt = (Elf32_Addr) &got[3];
117         }
118       got[1] = (Elf32_Addr) l;  /* Identify this shared object.  */
119
120       /* The got[2] entry contains the address of a function which gets
121          called to get the address of a so far unresolved function and
122          jump to it.  The profiling extension of the dynamic linker allows
123          to intercept the calls to collect information.  In this case we
124          don't store the address in the GOT so that all future calls also
125          end in this function.  */
126       if (__builtin_expect (profile, 0))
127         {
128           got[2] = (Elf32_Addr) &_dl_runtime_profile;
129
130           if (GLRO(dl_profile) != NULL
131               && _dl_name_match_p (GLRO(dl_profile), l))
132             /* This is the object we are looking for.  Say that we really
133                want profiling and the timers are started.  */
134             GL(dl_profile_map) = l;
135         }
136       else
137         /* This function will get called to fix up the GOT entry indicated by
138            the offset on the stack, and then jump to the resolved address.  */
139         got[2] = (Elf32_Addr) &_dl_runtime_resolve;
140     }
141
142   return lazy;
143 }
144
145 #ifdef IN_DL_RUNTIME
146
147 # if !defined PROF && !__BOUNDED_POINTERS__
148 /* We add a declaration of this function here so that in dl-runtime.c
149    the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
150    in registers.
151
152    We cannot use this scheme for profiling because the _mcount call
153    destroys the passed register information.  */
154 /* GKM FIXME: Fix trampoline to pass bounds so we can do
155    without the `__unbounded' qualifier.  */
156 #define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused))
157
158 extern ElfW(Addr) _dl_fixup (struct link_map *__unbounded l,
159                              ElfW(Word) reloc_offset)
160      ARCH_FIXUP_ATTRIBUTE;
161 extern ElfW(Addr) _dl_profile_fixup (struct link_map *l,
162                                      ElfW(Word) reloc_offset,
163                                      ElfW(Addr) retaddr, void *regs,
164                                      long int *framesizep)
165      ARCH_FIXUP_ATTRIBUTE;
166 # endif
167
168 #endif
169
170 /* Mask identifying addresses reserved for the user program,
171    where the dynamic linker should not map anything.  */
172 #define ELF_MACHINE_USER_ADDRESS_MASK   0xf8000000UL
173
174 /* Initial entry point code for the dynamic linker.
175    The C function `_dl_start' is the real entry point;
176    its return value is the user program's entry point.  */
177
178 #define RTLD_START asm ("\n\
179         .text\n\
180         .align 16\n\
181 0:      movl (%esp), %ebx\n\
182         ret\n\
183         .align 16\n\
184 .globl _start\n\
185 .globl _dl_start_user\n\
186 _start:\n\
187         # Note that _dl_start gets the parameter in %eax.\n\
188         movl %esp, %eax\n\
189         call _dl_start\n\
190 _dl_start_user:\n\
191         # Save the user entry point address in %edi.\n\
192         movl %eax, %edi\n\
193         # Point %ebx at the GOT.\n\
194         call 0b\n\
195         addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\
196         # See if we were run as a command with the executable file\n\
197         # name as an extra leading argument.\n\
198         movl _dl_skip_args@GOTOFF(%ebx), %eax\n\
199         # Pop the original argument count.\n\
200         popl %edx\n\
201         # Adjust the stack pointer to skip _dl_skip_args words.\n\
202         leal (%esp,%eax,4), %esp\n\
203         # Subtract _dl_skip_args from argc.\n\
204         subl %eax, %edx\n\
205         # Push argc back on the stack.\n\
206         push %edx\n\
207         # The special initializer gets called with the stack just\n\
208         # as the application's entry point will see it; it can\n\
209         # switch stacks if it moves these contents over.\n\
210 " RTLD_START_SPECIAL_INIT "\n\
211         # Load the parameters again.\n\
212         # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\
213         movl _rtld_local@GOTOFF(%ebx), %eax\n\
214         leal 8(%esp,%edx,4), %esi\n\
215         leal 4(%esp), %ecx\n\
216         movl %esp, %ebp\n\
217         # Make sure _dl_init is run with 16 byte aligned stack.\n\
218         andl $-16, %esp\n\
219         pushl %eax\n\
220         pushl %eax\n\
221         pushl %ebp\n\
222         pushl %esi\n\
223         # Clear %ebp, so that even constructors have terminated backchain.\n\
224         xorl %ebp, %ebp\n\
225         # Call the function to run the initializers.\n\
226         call _dl_init_internal@PLT\n\
227         # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
228         leal _dl_fini@GOTOFF(%ebx), %edx\n\
229         # Restore %esp _start expects.\n\
230         movl (%esp), %esp\n\
231         # Jump to the user's entry point.\n\
232         jmp *%edi\n\
233         .previous\n\
234 ");
235
236 #ifndef RTLD_START_SPECIAL_INIT
237 # define RTLD_START_SPECIAL_INIT /* nothing */
238 #endif
239
240 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
241    TLS variable, so undefined references should not be allowed to
242    define the value.
243    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
244    of the main executable's symbols, as for a COPY reloc.  */
245 #if !defined RTLD_BOOTSTRAP || USE___THREAD
246 # define elf_machine_type_class(type) \
247   ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32                 \
248      || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32           \
249      || (type) == R_386_TLS_TPOFF)                                            \
250     * ELF_RTYPE_CLASS_PLT)                                                    \
251    | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
252 #else
253 # define elf_machine_type_class(type) \
254   ((((type) == R_386_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)                         \
255    | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY))
256 #endif
257
258 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
259 #define ELF_MACHINE_JMP_SLOT    R_386_JMP_SLOT
260
261 /* The i386 never uses Elf32_Rela relocations for the dynamic linker.
262    Prelinked libraries may use Elf32_Rela though.  */
263 #define ELF_MACHINE_PLT_REL 1
264
265 /* We define an initialization functions.  This is called very early in
266    _dl_sysdep_start.  */
267 #define DL_PLATFORM_INIT dl_platform_init ()
268
269 static inline void __attribute__ ((unused))
270 dl_platform_init (void)
271 {
272   if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
273     /* Avoid an empty string which would disturb us.  */
274     GLRO(dl_platform) = NULL;
275 }
276
277 static inline Elf32_Addr
278 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
279                        const Elf32_Rel *reloc,
280                        Elf32_Addr *reloc_addr, Elf32_Addr value)
281 {
282   return *reloc_addr = value;
283 }
284
285 /* Return the final value of a plt relocation.  */
286 static inline Elf32_Addr
287 elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
288                        Elf32_Addr value)
289 {
290   return value;
291 }
292
293
294 /* Names of the architecture-specific auditing callback functions.  */
295 #define ARCH_LA_PLTENTER i86_gnu_pltenter
296 #define ARCH_LA_PLTEXIT i86_gnu_pltexit
297
298 #endif /* !dl_machine_h */
299
300 /* The i386 never uses Elf32_Rela relocations for the dynamic linker.
301    Prelinked libraries may use Elf32_Rela though.  */
302 #define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
303
304 #ifdef RESOLVE_MAP
305
306 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
307    MAP is the object containing the reloc.  */
308
309 auto inline void
310 __attribute ((always_inline))
311 elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
312                  const Elf32_Sym *sym, const struct r_found_version *version,
313                  void *const reloc_addr_arg)
314 {
315   Elf32_Addr *const reloc_addr = reloc_addr_arg;
316   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
317
318 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
319   if (__builtin_expect (r_type == R_386_RELATIVE, 0))
320     {
321 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
322       /* This is defined in rtld.c, but nowhere in the static libc.a;
323          make the reference weak so static programs can still link.
324          This declaration cannot be done when compiling rtld.c
325          (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
326          common defn for _dl_rtld_map, which is incompatible with a
327          weak decl in the same file.  */
328 #  ifndef SHARED
329       weak_extern (_dl_rtld_map);
330 #  endif
331       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
332 # endif
333         *reloc_addr += map->l_addr;
334     }
335 # ifndef RTLD_BOOTSTRAP
336   else if (__builtin_expect (r_type == R_386_NONE, 0))
337     return;
338 # endif
339   else
340 #endif  /* !RTLD_BOOTSTRAP and have no -z combreloc */
341     {
342       const Elf32_Sym *const refsym = sym;
343       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
344       Elf32_Addr value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
345
346       switch (r_type)
347         {
348         case R_386_GLOB_DAT:
349         case R_386_JMP_SLOT:
350           *reloc_addr = value;
351           break;
352
353 #if !defined RTLD_BOOTSTRAP || USE___THREAD
354         case R_386_TLS_DTPMOD32:
355 # ifdef RTLD_BOOTSTRAP
356           /* During startup the dynamic linker is always the module
357              with index 1.
358              XXX If this relocation is necessary move before RESOLVE
359              call.  */
360           *reloc_addr = 1;
361 # else
362           /* Get the information from the link map returned by the
363              resolv function.  */
364           if (sym_map != NULL)
365             *reloc_addr = sym_map->l_tls_modid;
366 # endif
367           break;
368         case R_386_TLS_DTPOFF32:
369 # ifndef RTLD_BOOTSTRAP
370           /* During relocation all TLS symbols are defined and used.
371              Therefore the offset is already correct.  */
372           if (sym != NULL)
373             *reloc_addr = sym->st_value;
374 # endif
375           break;
376         case R_386_TLS_TPOFF32:
377           /* The offset is positive, backward from the thread pointer.  */
378 # ifdef RTLD_BOOTSTRAP
379           *reloc_addr += map->l_tls_offset - sym->st_value;
380 # else
381           /* We know the offset of object the symbol is contained in.
382              It is a positive value which will be subtracted from the
383              thread pointer.  To get the variable position in the TLS
384              block we subtract the offset from that of the TLS block.  */
385           if (sym != NULL)
386             {
387               CHECK_STATIC_TLS (map, sym_map);
388               *reloc_addr += sym_map->l_tls_offset - sym->st_value;
389             }
390 # endif
391           break;
392         case R_386_TLS_TPOFF:
393           /* The offset is negative, forward from the thread pointer.  */
394 # ifdef RTLD_BOOTSTRAP
395           *reloc_addr += sym->st_value - map->l_tls_offset;
396 # else
397           /* We know the offset of object the symbol is contained in.
398              It is a negative value which will be added to the
399              thread pointer.  */
400           if (sym != NULL)
401             {
402               CHECK_STATIC_TLS (map, sym_map);
403               *reloc_addr += sym->st_value - sym_map->l_tls_offset;
404             }
405 # endif
406           break;
407 #endif  /* use TLS */
408
409 #ifndef RTLD_BOOTSTRAP
410         case R_386_32:
411           *reloc_addr += value;
412           break;
413         case R_386_PC32:
414           *reloc_addr += (value - (Elf32_Addr) reloc_addr);
415           break;
416         case R_386_COPY:
417           if (sym == NULL)
418             /* This can happen in trace mode if an object could not be
419                found.  */
420             break;
421           if (__builtin_expect (sym->st_size > refsym->st_size, 0)
422               || (__builtin_expect (sym->st_size < refsym->st_size, 0)
423                   && GLRO(dl_verbose)))
424             {
425               const char *strtab;
426
427               strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
428               _dl_error_printf ("\
429 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
430                                 rtld_progname ?: "<program name unknown>",
431                                 strtab + refsym->st_name);
432             }
433           memcpy (reloc_addr_arg, (void *) value,
434                   MIN (sym->st_size, refsym->st_size));
435           break;
436         default:
437           _dl_reloc_bad_type (map, r_type, 0);
438           break;
439 #endif  /* !RTLD_BOOTSTRAP */
440         }
441     }
442 }
443
444 #ifndef RTLD_BOOTSTRAP
445 auto inline void
446 __attribute__ ((always_inline))
447 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
448                   const Elf32_Sym *sym, const struct r_found_version *version,
449                   void *const reloc_addr_arg)
450 {
451   Elf32_Addr *const reloc_addr = reloc_addr_arg;
452   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
453
454   if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
455     *reloc_addr = map->l_addr + reloc->r_addend;
456   else if (r_type != R_386_NONE)
457     {
458 # ifndef RESOLVE_CONFLICT_FIND_MAP
459       const Elf32_Sym *const refsym = sym;
460 # endif
461       struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
462       Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
463
464       switch (ELF32_R_TYPE (reloc->r_info))
465         {
466         case R_386_GLOB_DAT:
467         case R_386_JMP_SLOT:
468         case R_386_32:
469           *reloc_addr = value + reloc->r_addend;
470           break;
471 # ifndef RESOLVE_CONFLICT_FIND_MAP
472           /* Not needed for dl-conflict.c.  */
473         case R_386_PC32:
474           *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
475           break;
476
477         case R_386_TLS_DTPMOD32:
478           /* Get the information from the link map returned by the
479              resolv function.  */
480           if (sym_map != NULL)
481             *reloc_addr = sym_map->l_tls_modid;
482           break;
483         case R_386_TLS_DTPOFF32:
484           /* During relocation all TLS symbols are defined and used.
485              Therefore the offset is already correct.  */
486           *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
487           break;
488         case R_386_TLS_TPOFF32:
489           /* The offset is positive, backward from the thread pointer.  */
490           /* We know the offset of object the symbol is contained in.
491              It is a positive value which will be subtracted from the
492              thread pointer.  To get the variable position in the TLS
493              block we subtract the offset from that of the TLS block.  */
494           if (sym != NULL)
495             {
496               CHECK_STATIC_TLS (map, sym_map);
497               *reloc_addr = sym_map->l_tls_offset - sym->st_value
498                             + reloc->r_addend;
499             }
500           break;
501         case R_386_TLS_TPOFF:
502           /* The offset is negative, forward from the thread pointer.  */
503           /* We know the offset of object the symbol is contained in.
504              It is a negative value which will be added to the
505              thread pointer.  */
506           if (sym != NULL)
507             {
508               CHECK_STATIC_TLS (map, sym_map);
509               *reloc_addr = sym->st_value - sym_map->l_tls_offset
510                             + reloc->r_addend;
511             }
512           break;
513         case R_386_COPY:
514           if (sym == NULL)
515             /* This can happen in trace mode if an object could not be
516                found.  */
517             break;
518           if (__builtin_expect (sym->st_size > refsym->st_size, 0)
519               || (__builtin_expect (sym->st_size < refsym->st_size, 0)
520                   && GLRO(dl_verbose)))
521             {
522               const char *strtab;
523
524               strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
525               _dl_error_printf ("\
526 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
527                                 rtld_progname ?: "<program name unknown>",
528                                 strtab + refsym->st_name);
529             }
530           memcpy (reloc_addr_arg, (void *) value,
531                   MIN (sym->st_size, refsym->st_size));
532           break;
533 # endif /* !RESOLVE_CONFLICT_FIND_MAP */
534         default:
535           /* We add these checks in the version to relocate ld.so only
536              if we are still debugging.  */
537           _dl_reloc_bad_type (map, r_type, 0);
538           break;
539         }
540     }
541 }
542 #endif  /* !RTLD_BOOTSTRAP */
543
544 auto inline void
545 __attribute ((always_inline))
546 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
547                           void *const reloc_addr_arg)
548 {
549   Elf32_Addr *const reloc_addr = reloc_addr_arg;
550   assert (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE);
551   *reloc_addr += l_addr;
552 }
553
554 #ifndef RTLD_BOOTSTRAP
555 auto inline void
556 __attribute__ ((always_inline))
557 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
558                            void *const reloc_addr_arg)
559 {
560   Elf32_Addr *const reloc_addr = reloc_addr_arg;
561   *reloc_addr = l_addr + reloc->r_addend;
562 }
563 #endif  /* !RTLD_BOOTSTRAP */
564
565 auto inline void
566 __attribute__ ((always_inline))
567 elf_machine_lazy_rel (struct link_map *map,
568                       Elf32_Addr l_addr, const Elf32_Rel *reloc)
569 {
570   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
571   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
572   /* Check for unexpected PLT reloc type.  */
573   if (__builtin_expect (r_type == R_386_JMP_SLOT, 1))
574     {
575       if (__builtin_expect (map->l_mach.plt, 0) == 0)
576         *reloc_addr += l_addr;
577       else
578         *reloc_addr = (map->l_mach.plt
579                        + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 4);
580     }
581   else
582     _dl_reloc_bad_type (map, r_type, 1);
583 }
584
585 #ifndef RTLD_BOOTSTRAP
586
587 auto inline void
588 __attribute__ ((always_inline))
589 elf_machine_lazy_rela (struct link_map *map,
590                        Elf32_Addr l_addr, const Elf32_Rela *reloc)
591 {
592 }
593
594 #endif  /* !RTLD_BOOTSTRAP */
595
596 #endif /* RESOLVE_MAP */