(ELF_MACHINE_START_ADDRESS): Define.
[kopensolaris-gnu/glibc.git] / sysdeps / hppa / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  PA-RISC version.
2    Copyright (C) 1995,1996,1997,1999,2000,2001 Free Software Foundation, Inc.
3    Contributed by David Huggins-Daines <dhd@debian.org>
4    This file is part of the GNU C Library.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If
18    not, write to the Free Software Foundation, Inc.,
19    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #ifndef dl_machine_h
22 #define dl_machine_h 1
23
24 #define ELF_MACHINE_NAME "hppa"
25
26 #include <sys/param.h>
27 #include <string.h>
28 #include <link.h>
29 #include <assert.h>
30
31 /* These must match the definition of the stub in bfd/elf32-hppa.c. */
32 #define SIZEOF_PLT_STUB (4*4)
33 #define GOT_FROM_PLT_STUB (4*4)
34
35 /* A PLABEL is a function descriptor.  Properly they consist of just
36    FUNC and GP.  But we want to traverse a binary tree too.  See
37    dl-fptr.c for the code (it may be made common between HPPA and
38    IA-64 in the future).
39
40    We call these 'fptr' to make it easier to steal code from IA-64. */
41
42 /* ld.so currently has 12 PLABEL32 relocs.  We'll keep this constant
43    large for now in case we require more, as the rest of these will be
44    used by the dynamic program itself (libc.so has quite a few
45    PLABEL32 relocs in it). */
46 #define HPPA_BOOT_FPTR_SIZE     256
47
48 struct hppa_fptr
49 {
50   Elf32_Addr func;
51   Elf32_Addr gp;
52   struct hppa_fptr *next;
53 };
54
55 extern struct hppa_fptr __boot_ldso_fptr[];
56 extern struct hppa_fptr *__fptr_root;
57 extern int __fptr_count;
58
59 extern Elf32_Addr __hppa_make_fptr (const struct link_map *, Elf32_Addr,
60                                     struct hppa_fptr **, struct hppa_fptr *);
61
62 /* Return nonzero iff ELF header is compatible with the running host.  */
63 static inline int
64 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
65 {
66   return ehdr->e_machine == EM_PARISC;
67 }
68
69
70 /* Return the link-time address of _DYNAMIC.  */
71 static inline Elf32_Addr
72 elf_machine_dynamic (void)
73 {
74   Elf32_Addr dynamic;
75
76 #if 0
77   /* Use this method if GOT address not yet set up.  */
78   asm ("\
79         b,l     1f,%0
80         depi    0,31,2,%0
81 1:      addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8),%0
82         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%%r1),%0"
83       : "=r" (dynamic) : : "r1");
84 #else
85   /* This works because we already have our GOT address available.  */
86   dynamic = (Elf32_Addr) &_DYNAMIC;
87 #endif
88
89   return dynamic;
90 }
91
92 /* Return the run-time load address of the shared object.  */
93 static inline Elf32_Addr
94 elf_machine_load_address (void)
95 {
96   Elf32_Addr dynamic, dynamic_linkaddress;
97
98   asm ("\
99         b,l     1f,%0
100         depi    0,31,2,%0
101 1:      addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%0
102         ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%%r1),%1
103         addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%0
104         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%%r1),%0"
105    : "=r" (dynamic_linkaddress), "=r" (dynamic) : : "r1");
106
107   return dynamic - dynamic_linkaddress;
108 }
109
110 /* Fixup a PLT entry to bounce directly to the function at VALUE.  */
111 static inline Elf32_Addr
112 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
113                        const Elf32_Rela *reloc,
114                        Elf32_Addr *reloc_addr, Elf32_Addr value)
115 {
116   /* l is the link_map for the caller, t is the link_map for the object
117    * being called */
118   reloc_addr[1] = D_PTR (t, l_info[DT_PLTGOT]);
119   reloc_addr[0] = value;
120   /* Return the PLT slot rather than the function value so that the
121      trampoline can load the new LTP. */
122   return (Elf32_Addr) reloc_addr;
123 }
124
125 /* Return the final value of a plt relocation.  */
126 static inline Elf32_Addr
127 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
128                        Elf32_Addr value)
129 {
130   /* We are rela only */
131   return value + reloc->r_addend;
132 }
133
134 /* Set up the loaded object described by L so its unrelocated PLT
135    entries will jump to the on-demand fixup code in dl-runtime.c.  */
136
137 static inline int
138 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
139 {
140   extern void _dl_runtime_resolve (void);
141   extern void _dl_runtime_profile (void);
142   Elf32_Addr jmprel = D_PTR(l, l_info[DT_JMPREL]);
143
144   if (lazy && jmprel)
145     {
146       Elf32_Addr *got = NULL;
147       Elf32_Addr l_addr;
148       Elf32_Addr end_jmprel;
149       Elf32_Addr iplt;
150
151       /* Relocate all the PLT slots.  */
152       l_addr = l->l_addr;
153       end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
154       for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
155         {
156           const Elf32_Rela *reloc;
157           Elf32_Word r_type;
158           Elf32_Word r_sym;
159           struct hppa_fptr *fptr;
160
161           reloc = (const Elf32_Rela *) iplt;
162           r_type = ELF32_R_TYPE (reloc->r_info);
163           r_sym = ELF32_R_SYM (reloc->r_info);
164
165           if (__builtin_expect (r_type == R_PARISC_IPLT, 1))
166             {
167               fptr = (struct hppa_fptr *) (reloc->r_offset + l_addr);
168               if (r_sym != 0)
169                 {
170                   /* Relocate the pointer to the stub.  */
171                   fptr->func += l_addr;
172                   /* Instead of the LTP value, we put the reloc offset
173                      here.  The trampoline code will load the proper
174                      LTP and pass the reloc offset to the fixup
175                      function.  */
176                   fptr->gp = iplt - jmprel;
177                   if (!got)
178                     {
179                       static union {
180                         unsigned char c[8];
181                         Elf32_Addr i[2];
182                       } sig = {{0x00,0xc0,0xff,0xee, 0xde,0xad,0xbe,0xef}};
183
184                       /* Find our .got section.  It's right after the
185                          stub.  */
186                       got = (Elf32_Addr *) (fptr->func + GOT_FROM_PLT_STUB);
187
188                       /* Sanity check to see if the address we are
189                          going to check below is within a reasonable
190                          approximation of the bounds of the PLT (or,
191                          at least, is at an address that won't fault
192                          on read).  Then check for the magic signature
193                          above. */
194                       if (fptr->func < (Elf32_Addr) fptr + sizeof(*fptr))
195                           return 0;
196                       if (fptr->func >
197                           ((Elf32_Addr) fptr
198                            + SIZEOF_PLT_STUB
199                            + ((l->l_info[DT_PLTRELSZ]->d_un.d_val / sizeof (Elf32_Rela))
200                               * 8)))
201                         return 0;
202                       if (got[-2] != sig.i[0] || got[-1] != sig.i[1])
203                         return 0; /* No lazy linking for you! */
204                     }
205                 }
206               else
207                 {
208                   /* Relocate this *ABS* entry.  */
209                   fptr->func = reloc->r_addend + l_addr;
210                   fptr->gp = D_PTR (l, l_info[DT_PLTGOT]);
211                 }
212             }
213           else if (__builtin_expect (r_type != R_PARISC_NONE, 0))
214             _dl_reloc_bad_type (l, r_type, 1);
215         }
216
217       if (got)
218         {
219           register Elf32_Addr ltp __asm__ ("%r19");
220           /* Identify this shared object. */
221           got[1] = (Elf32_Addr) l;
222
223           /* This function will be called to perform the relocation. */
224           if (__builtin_expect (!profile, 1))
225             got[-2] =
226               (Elf32_Addr) ((struct hppa_fptr *)
227                             ((unsigned long) &_dl_runtime_resolve & ~3))->func;
228           else
229             {
230               if (_dl_name_match_p (_dl_profile, l))
231                 {
232                   /* This is the object we are looking for.  Say that
233                      we really want profiling and the timers are
234                      started.  */
235                   _dl_profile_map = l;
236                 }
237               got[-2] =
238                 (Elf32_Addr) ((struct hppa_fptr *)
239                               ((unsigned long) &_dl_runtime_profile & ~3))->func;
240             }
241           got[-1] = ltp;
242         }
243     }
244   return lazy;
245 }
246
247 /* Initial entry point code for the dynamic linker.
248    The C function `_dl_start' is the real entry point;
249    its return value is the user program's entry point.  */
250
251 #define RTLD_START asm ("\
252         .text
253         .globl _start
254         .type _start,@function
255 _start:
256         /* The kernel does not give us an initial stack frame. */
257         ldo     64(%sp),%sp
258         /* Save the relevant arguments (yes, those are the correct
259            registers, the kernel is weird) in their stack slots. */
260         stw     %r25,-40(%sp) /* argc */
261         stw     %r24,-44(%sp) /* argv */
262
263         /* We need the LTP, and we need it now. */
264         /* $PIC_pcrel$0 points 8 bytes past the current instruction,
265            just like a branch reloc.  This sequence gets us the runtime
266            address of _DYNAMIC. */
267         bl      0f,%r19
268         depi    0,31,2,%r19     /* clear priviledge bits */
269 0:      addil   L'_DYNAMIC - ($PIC_pcrel$0 - 8),%r19
270         ldo     R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%r26
271
272         /* Also get the link time address from the first entry of the GOT.  */
273         addil   L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16),%r19
274         ldw     R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r20
275
276         sub     %r26,%r20,%r20  /* Calculate load offset */
277
278         /* Rummage through the dynamic entries, looking for DT_PLTGOT.  */
279         ldw,ma  8(%r26),%r19
280 1:      cmpib,=,n 3,%r19,2f     /* tag == DT_PLTGOT? */
281         cmpib,<>,n 0,%r19,1b
282         ldw,ma  8(%r26),%r19
283
284         /* Uh oh!  We didn't find one.  Abort. */
285         iitlbp  %r0,(%r0)
286
287 2:      ldw     -4(%r26),%r19   /* Found it, load value. */
288         add     %r19,%r20,%r19  /* And add the load offset. */
289
290         /* Our initial stack layout is rather different from everyone
291            else's due to the unique PA-RISC ABI.  As far as I know it
292            looks like this:
293
294            -----------------------------------  (this frame created above)
295            |         32 bytes of magic       |
296            |---------------------------------|
297            | 32 bytes argument/sp save area  |
298            |---------------------------------|  ((current->mm->env_end) + 63 & ~63)
299            |         N bytes of slack        |
300            |---------------------------------|
301            |      envvar and arg strings     |
302            |---------------------------------|
303            |        ELF auxiliary info       |
304            |         (up to 28 words)        |
305            |---------------------------------|
306            |  Environment variable pointers  |
307            |         upwards to NULL         |
308            |---------------------------------|
309            |        Argument pointers        |
310            |         upwards to NULL         |
311            |---------------------------------|
312            |          argc (1 word)          |
313            -----------------------------------
314
315           So, obviously, we can't just pass %sp to _dl_start.  That's
316           okay, argv-4 will do just fine.
317
318           The pleasant part of this is that if we need to skip
319           arguments we can just decrement argc and move argv, because
320           the stack pointer is utterly unrelated to the location of
321           the environment and argument vectors. */
322
323         /* This is always within range so we'll be okay. */
324         bl      _dl_start,%rp
325         ldo     -4(%r24),%r26
326
327         /* FALLTHRU */
328         .globl _dl_start_user
329         .type _dl_start_user,@function
330 _dl_start_user:
331         /* Save the entry point in %r3. */
332         copy    %ret0,%r3
333
334         /* Remember the lowest stack address. */
335         addil   LT'__libc_stack_end,%r19
336         ldw     RT'__libc_stack_end(%r1),%r20
337         stw     %sp,0(%r20)
338
339         /* See if we were called as a command with the executable file
340            name as an extra leading argument. */
341         addil   LT'_dl_skip_args,%r19
342         ldw     RT'_dl_skip_args(%r1),%r20
343         ldw     0(%r20),%r20
344
345         ldw     -40(%sp),%r25   /* argc */
346         comib,= 0,%r20,.Lnofix  /* FIXME: will be mispredicted */
347         ldw     -44(%sp),%r24   /* argv (delay slot) */
348
349         sub     %r25,%r20,%r25
350         stw     %r25,-40(%sp)
351         sh2add  %r20,%r24,%r24
352         stw     %r24,-44(%sp)
353
354 .Lnofix:
355         /* Call _dl_init(_dl_loaded, argc, argv, envp). */
356         addil   LT'_dl_loaded,%r19
357         ldw     RT'_dl_loaded(%r1),%r26
358         ldw     0(%r26),%r26
359         /* envp = argv + argc + 1 */
360         sh2add  %r25,%r24,%r23
361         bl      _dl_init,%r2
362         ldo     4(%r23),%r23    /* delay slot */
363
364         /* Reload argc, argv  to the registers start.S expects them in (feh) */
365         ldw     -40(%sp),%r25
366         ldw     -44(%sp),%r24
367
368         /* _dl_fini does have a PLT slot now.  I don't know how to get
369            to it though, so this hack will remain. */
370         .section .data
371 __dl_fini_plabel:
372         .word   _dl_fini
373         .word   0xdeadbeef
374         .previous
375
376         addil   LT'__dl_fini_plabel,%r19
377         ldw     RT'__dl_fini_plabel(%r1),%r23
378         stw     %r19,4(%r23)
379         bv      %r0(%r3)
380         depi    2,31,2,%r23     /* delay slot */");
381
382 /* This code gets called via the .plt stub, and is used in
383    dl-runtime.c to call the `fixup' function and then redirect to the
384    address it returns.
385    Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp.  */
386 #define TRAMPOLINE_TEMPLATE(tramp_name, fixup_name) \
387   extern void tramp_name (void);                    \
388   asm ( "\
389         /* Trampoline for " #tramp_name " */
390         .globl " #tramp_name "
391         .type " #tramp_name ",@function
392 " #tramp_name ":
393         /* Save return pointer */
394         stw     %r2,-20(%sp)
395         /* Save argument registers in the call stack frame. */
396         stw     %r26,-36(%sp)
397         stw     %r25,-40(%sp)
398         stw     %r24,-44(%sp)
399         stw     %r23,-48(%sp)
400         /* Build a call frame. */
401         stwm    %sp,64(%sp)
402
403         /* Set up args to fixup func.  */
404         ldw     8+4(%r20),%r26  /* got[1] == struct link_map *  */
405         copy    %r19,%r25       /* reloc offset  */
406
407         /* Call the real address resolver. */
408         bl      " #fixup_name ",%r2
409         copy    %r21,%r19       /* delay slot, set fixup func ltp */
410
411         ldwm    -64(%sp),%sp
412         /* Arguments. */
413         ldw     -36(%sp),%r26
414         ldw     -40(%sp),%r25
415         ldw     -44(%sp),%r24
416         ldw     -48(%sp),%r23
417         /* Return pointer. */
418         ldw     -20(%sp),%r2
419         /* Call the real function. */
420         ldw     0(%r28),%r22
421         bv      %r0(%r22)
422         ldw     4(%r28),%r19
423 ");
424
425 #ifndef PROF
426 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
427   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
428   TRAMPOLINE_TEMPLATE (_dl_runtime_profile, profile_fixup);
429 #else
430 #define ELF_MACHINE_RUNTIME_TRAMPOLINE                  \
431   TRAMPOLINE_TEMPLATE (_dl_runtime_resolve, fixup);     \
432   strong_alias (_dl_runtime_resolve, _dl_runtime_profile);
433 #endif
434
435
436 /* Nonzero iff TYPE describes a relocation that should
437    skip the executable when looking up the symbol value.  */
438 #define elf_machine_lookup_noexec_p(type) ((type) == R_PARISC_COPY)
439
440 /* Nonzero iff TYPE describes relocation of a PLT entry, so
441    PLT entries should not be allowed to define the value.  */
442 #define elf_machine_lookup_noplt_p(type) ((type) == R_PARISC_IPLT \
443                                           || (type) == R_PARISC_EPLT)
444
445 /* Used by ld.so for ... something ... */
446 #define ELF_MACHINE_JMP_SLOT R_PARISC_IPLT
447
448 /* We only use RELA. */
449 #define ELF_MACHINE_NO_REL 1
450
451 /* Return the address of the entry point. */
452 #define ELF_MACHINE_START_ADDRESS(map, start) \
453   DL_FUNCTION_ADDRESS (map, start)
454
455 #endif /* !dl_machine_h */
456
457 /* These are only actually used where RESOLVE_MAP is defined, anyway. */
458 #ifdef RESOLVE_MAP
459
460 static inline void
461 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
462                   const Elf32_Sym *sym, const struct r_found_version *version,
463                   Elf32_Addr *const reloc_addr)
464 {
465   const Elf32_Sym *const refsym = sym;
466   unsigned long const r_type = ELF32_R_TYPE (reloc->r_info);
467   struct link_map *sym_map;
468   Elf32_Addr value;
469
470 #ifndef RTLD_BOOTSTRAP
471   /* This is defined in rtld.c, but nowhere in the static libc.a; make the
472      reference weak so static programs can still link.  This declaration
473      cannot be done when compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP)
474      because rtld.c contains the common defn for _dl_rtld_map, which is
475      incompatible with a weak decl in the same file.  */
476   weak_extern (_dl_rtld_map);
477 #endif
478
479   /* RESOLVE_MAP will return a null value for undefined syms, and
480      non-null for all other syms.  In particular, relocs with no
481      symbol (symbol index of zero), also called *ABS* relocs, will be
482      resolved to MAP.  (The first entry in a symbol table is all
483      zeros, and an all zero Elf32_Sym has a binding of STB_LOCAL.)
484      See RESOLVE_MAP definition in elf/dl-reloc.c  */
485 #ifdef RTLD_BOOTSTRAP
486   /* RESOLVE_MAP in rtld.c doesn't have the local sym test.  */
487   sym_map = (ELF32_ST_BIND (sym->st_info) != STB_LOCAL
488              ? RESOLVE_MAP (&sym, version, r_type) : map);
489 #else
490   sym_map = RESOLVE_MAP (&sym, version, r_type);
491 #endif
492   if (sym_map)
493     {
494       value = sym ? sym_map->l_addr + sym->st_value : 0;
495       value += reloc->r_addend;
496     }
497   else
498     value = 0;
499
500   switch (r_type)
501     {
502     case R_PARISC_DIR32:
503 #ifndef RTLD_BOOTSTRAP
504       /* All hell breaks loose if we try to relocate these twice,
505          because any initialized variables in ld.so that refer to
506          other ones will have their values reset.  In particular,
507          __fptr_next will be reset, sometimes causing endless loops in
508          __hppa_make_fptr().  So don't do that. */
509       if (map == &_dl_rtld_map)
510         return;
511 #endif
512       /* Otherwise, nothing more to do here. */
513       break;
514
515     case R_PARISC_PLABEL32:
516       /* Easy rule: If there is a symbol and it is global, then we
517          need to make a dynamic function descriptor.  Otherwise we
518          have the address of a PLT slot for a local symbol which we
519          know to be unique. */
520       if (sym == NULL
521           || sym_map == NULL
522           || ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
523         break;
524
525       /* Okay, we need to make ourselves a PLABEL then.  See the IA64
526          code for an explanation of how this works.  */
527 #ifndef RTLD_BOOTSTRAP
528       value = __hppa_make_fptr (sym_map, value, &__fptr_root, NULL);
529 #else
530       {
531         struct hppa_fptr *p_boot_ldso_fptr;
532         struct hppa_fptr **p_fptr_root;
533         int *p_fptr_count;
534         unsigned long dot;
535
536         /* Go from the top of __boot_ldso_fptr.  As on IA64, we
537            probably haven't relocated the necessary values by this
538            point so we have to find them ourselves. */
539
540         asm ("bl        0f,%0
541               depi      0,31,2,%0
542 0:            addil     L'__boot_ldso_fptr - ($PIC_pcrel$0 - 8),%0
543               ldo       R'__boot_ldso_fptr - ($PIC_pcrel$0 - 12)(%%r1),%1
544               addil     L'__fptr_root - ($PIC_pcrel$0 - 16),%0
545               ldo       R'__fptr_root - ($PIC_pcrel$0 - 20)(%%r1),%2
546               addil     L'__fptr_count - ($PIC_pcrel$0 - 24),%0
547               ldo       R'__fptr_count - ($PIC_pcrel$0 - 28)(%%r1),%3"
548              :
549              "=r" (dot),
550              "=r" (p_boot_ldso_fptr),
551              "=r" (p_fptr_root),
552              "=r" (p_fptr_count));
553
554         value = __hppa_make_fptr (sym_map, value, p_fptr_root,
555                                   &p_boot_ldso_fptr[--*p_fptr_count]);
556       }
557 #endif
558       break;
559
560     case R_PARISC_IPLT:
561       if (__builtin_expect (sym_map != NULL, 1))
562         elf_machine_fixup_plt (NULL, sym_map, reloc, reloc_addr, value);
563       else
564         {
565           /* If we get here, it's a (weak) undefined sym.  */
566           elf_machine_fixup_plt (NULL, map, reloc, reloc_addr, value);
567         }
568       return;
569
570     case R_PARISC_COPY:
571       if (__builtin_expect (sym == NULL, 0))
572         /* This can happen in trace mode if an object could not be
573            found.  */
574         break;
575       if (__builtin_expect (sym->st_size > refsym->st_size, 0)
576           || (__builtin_expect (sym->st_size < refsym->st_size, 0)
577               && __builtin_expect (_dl_verbose, 0)))
578         {
579           const char *strtab;
580
581           strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
582           _dl_error_printf ("\
583 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
584                             _dl_argv[0] ?: "<program name unknown>",
585                             strtab + refsym->st_name);
586         }
587       memcpy (reloc_addr, (void *) value,
588               MIN (sym->st_size, refsym->st_size));
589       return;
590
591     case R_PARISC_NONE: /* Alright, Wilbur. */
592       return;
593
594     default:
595       _dl_reloc_bad_type (map, r_type, 0);
596     }
597
598   *reloc_addr = value;
599 }
600
601 static inline void
602 elf_machine_lazy_rel (struct link_map *map,
603                       Elf32_Addr l_addr, const Elf32_Rela *reloc)
604 {
605   /* We don't have anything to do here.  elf_machine_runtime_setup has
606      done all the relocs already.  */
607 }
608
609 #endif /* RESOLVE_MAP */