b85b4f117f23dd680bcdede292d5623ddec7cfb5
[platform/upstream/glibc.git] / sysdeps / arm / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions.  ARM version.
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005
3         Free Software Foundation, Inc.
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 Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the 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    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #ifndef dl_machine_h
22 #define dl_machine_h
23
24 #define ELF_MACHINE_NAME "ARM"
25
26 #include <sys/param.h>
27
28 #define VALID_ELF_ABIVERSION(ver)       (ver == 0)
29 #define VALID_ELF_OSABI(osabi) \
30   (osabi == ELFOSABI_SYSV || osabi == ELFOSABI_ARM)
31 #define VALID_ELF_HEADER(hdr,exp,size) \
32   memcmp (hdr,exp,size-2) == 0 \
33   && VALID_ELF_OSABI (hdr[EI_OSABI]) \
34   && VALID_ELF_ABIVERSION (hdr[EI_ABIVERSION])
35
36 #define CLEAR_CACHE(BEG,END)                                            \
37 {                                                                       \
38   register unsigned long _beg __asm ("a1") = (unsigned long)(BEG);      \
39   register unsigned long _end __asm ("a2") = (unsigned long)(END);      \
40   register unsigned long _flg __asm ("a3") = 0;                         \
41   __asm __volatile ("swi 0x9f0002               @ sys_cacheflush"       \
42                     : /* no outputs */                                  \
43                     : /* no inputs */                                   \
44                     : "a1");                                            \
45 }
46
47 /* Return nonzero iff ELF header is compatible with the running host.  */
48 static inline int __attribute__ ((unused))
49 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
50 {
51   return ehdr->e_machine == EM_ARM;
52 }
53
54
55 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
56    first element of the GOT.  This must be inlined in a function which
57    uses global data.  */
58 static inline Elf32_Addr __attribute__ ((unused))
59 elf_machine_dynamic (void)
60 {
61   register Elf32_Addr *got asm ("r10");
62   return *got;
63 }
64
65
66 /* Return the run-time load address of the shared object.  */
67 static inline Elf32_Addr __attribute__ ((unused))
68 elf_machine_load_address (void)
69 {
70   extern void __dl_start asm ("_dl_start");
71   Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
72   Elf32_Addr pcrel_addr;
73   asm ("adr %0, _dl_start" : "=r" (pcrel_addr));
74   return pcrel_addr - got_addr;
75 }
76
77
78 /* Set up the loaded object described by L so its unrelocated PLT
79    entries will jump to the on-demand fixup code in dl-runtime.c.  */
80
81 static inline int __attribute__ ((unused))
82 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
83 {
84   Elf32_Addr *got;
85   extern void _dl_runtime_resolve (Elf32_Word);
86   extern void _dl_runtime_profile (Elf32_Word);
87
88   if (l->l_info[DT_JMPREL] && lazy)
89     {
90       /* patb: this is different than i386 */
91       /* The GOT entries for functions in the PLT have not yet been filled
92          in.  Their initial contents will arrange when called to push an
93          index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
94          and then jump to _GLOBAL_OFFSET_TABLE[2].  */
95       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
96       /* If a library is prelinked but we have to relocate anyway,
97          we have to be able to undo the prelinking of .got.plt.
98          The prelinker saved us here address of .plt.  */
99       if (got[1])
100         l->l_mach.plt = got[1] + l->l_addr;
101       got[1] = (Elf32_Addr) l;  /* Identify this shared object.  */
102
103       /* The got[2] entry contains the address of a function which gets
104          called to get the address of a so far unresolved function and
105          jump to it.  The profiling extension of the dynamic linker allows
106          to intercept the calls to collect information.  In this case we
107          don't store the address in the GOT so that all future calls also
108          end in this function.  */
109       if (profile)
110         {
111           got[2] = (Elf32_Addr) &_dl_runtime_profile;
112
113           if (_dl_name_match_p (GLRO(dl_profile), l))
114             /* Say that we really want profiling and the timers are
115                started.  */
116             GL(dl_profile_map) = l;
117         }
118       else
119         /* This function will get called to fix up the GOT entry indicated by
120            the offset on the stack, and then jump to the resolved address.  */
121         got[2] = (Elf32_Addr) &_dl_runtime_resolve;
122     }
123   return lazy;
124 }
125
126 #if defined(__USE_BX__)
127 #define BX(x) "bx\t" #x
128 #else
129 #define BX(x) "mov\tpc, " #x
130 #endif
131
132 #ifndef PROF
133 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
134         .text\n\
135         .globl _dl_runtime_resolve\n\
136         .type _dl_runtime_resolve, #function\n\
137         .align 2\n\
138 _dl_runtime_resolve:\n\
139         @ we get called with\n\
140         @       stack[0] contains the return address from this call\n\
141         @       ip contains &GOT[n+3] (pointer to function)\n\
142         @       lr points to &GOT[2]\n\
143 \n\
144         @ stack arguments\n\
145         stmdb   sp!,{r0-r3}\n\
146 \n\
147         @ get pointer to linker struct\n\
148         ldr     r0, [lr, #-4]\n\
149 \n\
150         @ prepare to call fixup()\n\
151         @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each\n\
152         sub     r1, ip, lr\n\
153         sub     r1, r1, #4\n\
154         add     r1, r1, r1\n\
155 \n\
156         @ call fixup routine\n\
157         bl      fixup\n\
158 \n\
159         @ save the return\n\
160         mov     ip, r0\n\
161 \n\
162         @ get arguments and return address back\n\
163         ldmia   sp!, {r0-r3,lr}\n\
164 \n\
165         @ jump to the newly found address\n\
166         " BX(ip) "\n\
167 \n\
168         .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
169 \n\
170         .globl _dl_runtime_profile\n\
171         .type _dl_runtime_profile, #function\n\
172         .align 2\n\
173 _dl_runtime_profile:\n\
174         @ stack arguments\n\
175         stmdb   sp!, {r0-r3}\n\
176 \n\
177         @ get pointer to linker struct\n\
178         ldr     r0, [lr, #-4]\n\
179 \n\
180         @ prepare to call fixup()\n\
181         @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each\n\
182         sub     r1, ip, lr\n\
183         sub     r1, r1, #4\n\
184         add     r1, r1, r1\n\
185 \n\
186         @ call profiling fixup routine\n\
187         bl      profile_fixup\n\
188 \n\
189         @ save the return\n\
190         mov     ip, r0\n\
191 \n\
192         @ get arguments and return address back\n\
193         ldmia   sp!, {r0-r3,lr}\n\
194 \n\
195         @ jump to the newly found address\n\
196         " BX(ip) "\n\
197 \n\
198         .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
199         .previous\n\
200 ");
201 #else // PROF
202 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
203         .text\n\
204         .globl _dl_runtime_resolve\n\
205         .globl _dl_runtime_profile\n\
206         .type _dl_runtime_resolve, #function\n\
207         .type _dl_runtime_profile, #function\n\
208         .align 2\n\
209 _dl_runtime_resolve:\n\
210 _dl_runtime_profile:\n\
211         @ we get called with\n\
212         @       stack[0] contains the return address from this call\n\
213         @       ip contains &GOT[n+3] (pointer to function)\n\
214         @       lr points to &GOT[2]\n\
215 \n\
216         @ stack arguments\n\
217         stmdb   sp!, {r0-r3}\n\
218 \n\
219         @ get pointer to linker struct\n\
220         ldr     r0, [lr, #-4]\n\
221 \n\
222         @ prepare to call fixup()\n\
223         @ change &GOT[n+3] into 8*n        NOTE: reloc are 8 bytes each\n\
224         sub     r1, ip, lr\n\
225         sub     r1, r1, #4\n\
226         add     r1, r1, r1\n\
227 \n\
228         @ call profiling fixup routine\n\
229         bl      fixup\n\
230 \n\
231         @ save the return\n\
232         mov     ip, r0\n\
233 \n\
234         @ get arguments and return address back\n\
235         ldmia   sp!, {r0-r3,lr}\n\
236 \n\
237         @ jump to the newly found address\n\
238         " BX(ip) "\n\
239 \n\
240         .size _dl_runtime_profile, .-_dl_runtime_profile\n\
241         .previous\n\
242 ");
243 #endif //PROF
244
245 /* Mask identifying addresses reserved for the user program,
246    where the dynamic linker should not map anything.  */
247 #define ELF_MACHINE_USER_ADDRESS_MASK   0xf8000000UL
248
249 /* Initial entry point code for the dynamic linker.
250    The C function `_dl_start' is the real entry point;
251    its return value is the user program's entry point.  */
252
253 #define RTLD_START asm ("\
254 .text\n\
255 .globl _start\n\
256 .globl _dl_start_user\n\
257 _start:\n\
258         @ we are PIC code, so get global offset table\n\
259         ldr     sl, .L_GET_GOT\n\
260         @ See if we were run as a command with the executable file\n\
261         @ name as an extra leading argument.\n\
262         ldr     r4, .L_SKIP_ARGS\n\
263         @ at start time, all the args are on the stack\n\
264         mov     r0, sp\n\
265         bl      _dl_start\n\
266         @ returns user entry point in r0\n\
267 _dl_start_user:\n\
268         add     sl, pc, sl\n\
269 .L_GOT_GOT:\n\
270         ldr     r4, [sl, r4]\n\
271         @ get the original arg count\n\
272         ldr     r1, [sp]\n\
273         @ save the entry point in another register\n\
274         mov     r6, r0\n\
275         @ adjust the stack pointer to skip the extra args\n\
276         add     sp, sp, r4, lsl #2\n\
277         @ subtract _dl_skip_args from original arg count\n\
278         sub     r1, r1, r4\n\
279         @ get the argv address\n\
280         add     r2, sp, #4\n\
281         @ store the new argc in the new stack location\n\
282         str     r1, [sp]\n\
283         @ compute envp\n\
284         add     r3, r2, r1, lsl #2\n\
285         add     r3, r3, #4\n\
286 \n\
287         @ now we call _dl_init\n\
288         ldr     r0, .L_LOADED\n\
289         ldr     r0, [sl, r0]\n\
290         @ call _dl_init\n\
291         bl      _dl_init_internal(PLT)\n\
292         @ load the finalizer function\n\
293         ldr     r0, .L_FINI_PROC\n\
294         add     r0, sl, r0\n\
295         @ jump to the user_s entry point\n\
296         " BX(r6) "\n\
297 .L_GET_GOT:\n\
298         .word   _GLOBAL_OFFSET_TABLE_ - .L_GOT_GOT - 4\n\
299 .L_SKIP_ARGS:\n\
300         .word   _dl_skip_args(GOTOFF)\n\
301 .L_FINI_PROC:\n\
302         .word   _dl_fini(GOTOFF)\n\
303 .L_LOADED:\n\
304         .word   _rtld_local(GOTOFF)\n\
305 .previous\n\
306 ");
307
308 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
309    PLT entries should not be allowed to define the value.
310    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
311    of the main executable's symbols, as for a COPY reloc.  */
312 #define elf_machine_type_class(type) \
313   ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)  \
314    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
315
316 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
317 #define ELF_MACHINE_JMP_SLOT    R_ARM_JUMP_SLOT
318
319 /* ARM never uses Elf32_Rela relocations for the dynamic linker.
320    Prelinked libraries may use Elf32_Rela though.  */
321 #define ELF_MACHINE_PLT_REL 1
322
323 /* We define an initialization functions.  This is called very early in
324    _dl_sysdep_start.  */
325 #define DL_PLATFORM_INIT dl_platform_init ()
326
327 static inline void __attribute__ ((unused))
328 dl_platform_init (void)
329 {
330   if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
331     /* Avoid an empty string which would disturb us.  */
332     GLRO(dl_platform) = NULL;
333 }
334
335 static inline Elf32_Addr
336 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
337                        const Elf32_Rel *reloc,
338                        Elf32_Addr *reloc_addr, Elf32_Addr value)
339 {
340   return *reloc_addr = value;
341 }
342
343 /* Return the final value of a plt relocation.  */
344 static inline Elf32_Addr
345 elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
346                        Elf32_Addr value)
347 {
348   return value;
349 }
350
351 #endif /* !dl_machine_h */
352
353
354 /* ARM never uses Elf32_Rela relocations for the dynamic linker.
355    Prelinked libraries may use Elf32_Rela though.  */
356 #define ELF_MACHINE_NO_RELA defined RTLD_BOOTSTRAP
357
358 #ifdef RESOLVE
359
360 /* Deal with an out-of-range PC24 reloc.  */
361 static Elf32_Addr
362 fix_bad_pc24 (Elf32_Addr *const reloc_addr, Elf32_Addr value)
363 {
364   static void *fix_page;
365   static unsigned int fix_offset;
366   static size_t pagesize;
367   Elf32_Word *fix_address;
368
369   if (! fix_page)
370     {
371       if (! pagesize)
372         pagesize = getpagesize ();
373       fix_page = mmap (NULL, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC,
374                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
375       if (! fix_page)
376         assert (! "could not map page for fixup");
377       fix_offset = 0;
378     }
379
380   fix_address = (Elf32_Word *)(fix_page + fix_offset);
381   fix_address[0] = 0xe51ff004;  /* ldr pc, [pc, #-4] */
382   fix_address[1] = value;
383
384   fix_offset += 8;
385   if (fix_offset >= pagesize)
386     fix_page = NULL;
387
388   return (Elf32_Addr)fix_address;
389 }
390
391 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
392    MAP is the object containing the reloc.  */
393
394 static inline void
395 elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
396                  const Elf32_Sym *sym, const struct r_found_version *version,
397                  void *const reloc_addr_arg)
398 {
399   Elf32_Addr *const reloc_addr = reloc_addr_arg;
400   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
401
402 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
403   if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
404     {
405 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
406       /* This is defined in rtld.c, but nowhere in the static libc.a;
407          make the reference weak so static programs can still link.
408          This declaration cannot be done when compiling rtld.c
409          (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
410          common defn for _dl_rtld_map, which is incompatible with a
411          weak decl in the same file.  */
412 #  ifndef SHARED
413       weak_extern (_dl_rtld_map);
414 #  endif
415       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
416 # endif
417         *reloc_addr += map->l_addr;
418     }
419 # ifndef RTLD_BOOTSTRAP
420   else if (__builtin_expect (r_type == R_ARM_NONE, 0))
421     return;
422 # endif
423   else
424 #endif
425     {
426       const Elf32_Sym *const refsym = sym;
427       Elf32_Addr value = RESOLVE (&sym, version, r_type);
428       if (sym)
429         value += sym->st_value;
430
431       switch (r_type)
432         {
433         case R_ARM_COPY:
434           if (sym == NULL)
435             /* This can happen in trace mode if an object could not be
436                found.  */
437             break;
438           if (sym->st_size > refsym->st_size
439               || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
440             {
441               const char *strtab;
442
443               strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
444               _dl_error_printf ("\
445 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
446                                 rtld_progname ?: "<program name unknown>",
447                                 strtab + refsym->st_name);
448             }
449           memcpy (reloc_addr_arg, (void *) value,
450                   MIN (sym->st_size, refsym->st_size));
451           break;
452         case R_ARM_GLOB_DAT:
453         case R_ARM_JUMP_SLOT:
454 # ifdef RTLD_BOOTSTRAP
455           /* Fix weak undefined references.  */
456           if (sym != NULL && sym->st_value == 0)
457             *reloc_addr = 0;
458           else
459 # endif
460             *reloc_addr = value;
461           break;
462         case R_ARM_ABS32:
463           {
464 # ifndef RTLD_BOOTSTRAP
465            /* This is defined in rtld.c, but nowhere in the static
466               libc.a; make the reference weak so static programs can
467               still link.  This declaration cannot be done when
468               compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) because
469               rtld.c contains the common defn for _dl_rtld_map, which
470               is incompatible with a weak decl in the same file.  */
471 #  ifndef SHARED
472             weak_extern (_dl_rtld_map);
473 #  endif
474             if (map == &GL(dl_rtld_map))
475               /* Undo the relocation done here during bootstrapping.
476                  Now we will relocate it anew, possibly using a
477                  binding found in the user program or a loaded library
478                  rather than the dynamic linker's built-in definitions
479                  used while loading those libraries.  */
480               value -= map->l_addr + refsym->st_value;
481 # endif
482             *reloc_addr += value;
483             break;
484           }
485         case R_ARM_PC24:
486           {
487              Elf32_Sword addend;
488              Elf32_Addr newvalue, topbits;
489
490              addend = *reloc_addr & 0x00ffffff;
491              if (addend & 0x00800000) addend |= 0xff000000;
492
493              newvalue = value - (Elf32_Addr)reloc_addr + (addend << 2);
494              topbits = newvalue & 0xfe000000;
495              if (topbits != 0xfe000000 && topbits != 0x00000000)
496                {
497                  newvalue = fix_bad_pc24(reloc_addr, value)
498                    - (Elf32_Addr)reloc_addr + (addend << 2);
499                  topbits = newvalue & 0xfe000000;
500                  if (topbits != 0xfe000000 && topbits != 0x00000000)
501                    {
502                      _dl_signal_error (0, map->l_name, NULL,
503                                        "R_ARM_PC24 relocation out of range");
504                    }
505                }
506              newvalue >>= 2;
507              value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
508              *reloc_addr = value;
509           }
510         break;
511         default:
512           _dl_reloc_bad_type (map, r_type, 0);
513           break;
514         }
515     }
516 }
517
518 # ifndef RTLD_BOOTSTRAP
519 static inline void
520 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
521                   const Elf32_Sym *sym, const struct r_found_version *version,
522                   void *const reloc_addr_arg)
523 {
524   Elf32_Addr *const reloc_addr = reloc_addr_arg;
525   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
526
527   if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
528     *reloc_addr = map->l_addr + reloc->r_addend;
529   else if (__builtin_expect (r_type == R_ARM_NONE, 0))
530     return;
531   else
532     {
533 # ifndef RESOLVE_CONFLICT_FIND_MAP
534       const Elf32_Sym *const refsym = sym;
535 # endif
536       Elf32_Addr value = RESOLVE (&sym, version, r_type);
537       if (sym)
538         value += sym->st_value;
539
540       switch (r_type)
541         {
542 #  ifndef RESOLVE_CONFLICT_FIND_MAP
543           /* Not needed for dl-conflict.c.  */
544         case R_ARM_COPY:
545           if (sym == NULL)
546             /* This can happen in trace mode if an object could not be
547                found.  */
548             break;
549           if (sym->st_size > refsym->st_size
550               || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
551             {
552               const char *strtab;
553
554               strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
555               _dl_error_printf ("\
556 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
557                                 rtld_progname ?: "<program name unknown>",
558                                 strtab + refsym->st_name);
559             }
560           memcpy (reloc_addr_arg, (void *) value,
561                   MIN (sym->st_size, refsym->st_size));
562           break;
563 #  endif /* !RESOLVE_CONFLICT_FIND_MAP */
564         case R_ARM_GLOB_DAT:
565         case R_ARM_JUMP_SLOT:
566         case R_ARM_ABS32:
567           *reloc_addr = value + reloc->r_addend;
568           break;
569         case R_ARM_PC24:
570           {
571              Elf32_Addr newvalue, topbits;
572
573              newvalue = value + reloc->r_addend - (Elf32_Addr)reloc_addr;
574              topbits = newvalue & 0xfe000000;
575              if (topbits != 0xfe000000 && topbits != 0x00000000)
576                {
577                  newvalue = fix_bad_pc24(reloc_addr, value)
578                    - (Elf32_Addr)reloc_addr + (reloc->r_addend << 2);
579                  topbits = newvalue & 0xfe000000;
580                  if (topbits != 0xfe000000 && topbits != 0x00000000)
581                    {
582                      _dl_signal_error (0, map->l_name, NULL,
583                                        "R_ARM_PC24 relocation out of range");
584                    }
585                }
586              newvalue >>= 2;
587              value = (*reloc_addr & 0xff000000) | (newvalue & 0x00ffffff);
588              *reloc_addr = value;
589           }
590           break;
591         default:
592           _dl_reloc_bad_type (map, r_type, 0);
593           break;
594         }
595     }
596 }
597 # endif
598
599 static inline void
600 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
601                           void *const reloc_addr_arg)
602 {
603   Elf32_Addr *const reloc_addr = reloc_addr_arg;
604   *reloc_addr += l_addr;
605 }
606
607 # ifndef RTLD_BOOTSTRAP
608 static inline void
609 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
610                            void *const reloc_addr_arg)
611 {
612   Elf32_Addr *const reloc_addr = reloc_addr_arg;
613   *reloc_addr = l_addr + reloc->r_addend;
614 }
615 # endif
616
617 static inline void
618 elf_machine_lazy_rel (struct link_map *map,
619                       Elf32_Addr l_addr, const Elf32_Rel *reloc)
620 {
621   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
622   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
623   /* Check for unexpected PLT reloc type.  */
624   if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
625     {
626       if (__builtin_expect (map->l_mach.plt, 0) == 0)
627         *reloc_addr += l_addr;
628       else
629         *reloc_addr = map->l_mach.plt;
630     }
631   else
632     _dl_reloc_bad_type (map, r_type, 1);
633 }
634
635 #endif /* RESOLVE */