1 /* Machine-dependent ELF dynamic relocation inline functions.  ARM version.
2    Copyright (C) 1995-2021 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, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef dl_machine_h
20 #define dl_machine_h
21 
22 #define ELF_MACHINE_NAME "ARM"
23 
24 #include <assert.h>
25 #include <sys/param.h>
26 #include <tls.h>
27 #include <dl-tlsdesc.h>
28 #include <dl-irel.h>
29 #include <dl-static-tls.h>
30 #include <dl-machine-rel.h>
31 
32 #ifndef CLEAR_CACHE
33 # error CLEAR_CACHE definition required to handle TEXTREL
34 #endif
35 
36 /* Return nonzero iff ELF header is compatible with the running host.  */
37 static inline int __attribute__ ((unused))
elf_machine_matches_host(const Elf32_Ehdr * ehdr)38 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
39 {
40   return ehdr->e_machine == EM_ARM;
41 }
42 
43 /* Return the run-time load address of the shared object.  */
44 static inline ElfW(Addr) __attribute__ ((unused))
elf_machine_load_address(void)45 elf_machine_load_address (void)
46 {
47   extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
48   return (ElfW(Addr)) &__ehdr_start;
49 }
50 
51 /* Return the link-time address of _DYNAMIC.  */
52 static inline ElfW(Addr) __attribute__ ((unused))
elf_machine_dynamic(void)53 elf_machine_dynamic (void)
54 {
55   extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
56   return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
57 }
58 
59 /* Set up the loaded object described by L so its unrelocated PLT
60    entries will jump to the on-demand fixup code in dl-runtime.c.  */
61 
62 static inline int __attribute__ ((unused))
elf_machine_runtime_setup(struct link_map * l,struct r_scope_elem * scope[],int lazy,int profile)63 elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
64 			   int lazy, int profile)
65 {
66   Elf32_Addr *got;
67   extern void _dl_runtime_resolve (Elf32_Word);
68   extern void _dl_runtime_profile (Elf32_Word);
69 
70   if (l->l_info[DT_JMPREL] && lazy)
71     {
72       /* patb: this is different than i386 */
73       /* The GOT entries for functions in the PLT have not yet been filled
74 	 in.  Their initial contents will arrange when called to push an
75 	 index into the .got section, load ip with &_GLOBAL_OFFSET_TABLE_[3],
76 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
77       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
78       /* If a library is prelinked but we have to relocate anyway,
79 	 we have to be able to undo the prelinking of .got.plt.
80 	 The prelinker saved us here address of .plt.  */
81       if (got[1])
82 	l->l_mach.plt = got[1] + l->l_addr;
83       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
84 
85       /* The got[2] entry contains the address of a function which gets
86 	 called to get the address of a so far unresolved function and
87 	 jump to it.  The profiling extension of the dynamic linker allows
88 	 to intercept the calls to collect information.  In this case we
89 	 don't store the address in the GOT so that all future calls also
90 	 end in this function.  */
91       if (profile)
92 	{
93 	  got[2] = (Elf32_Addr) &_dl_runtime_profile;
94 
95 	  if (GLRO(dl_profile) != NULL
96 	      && _dl_name_match_p (GLRO(dl_profile), l))
97 	    /* Say that we really want profiling and the timers are
98 	       started.  */
99 	    GL(dl_profile_map) = l;
100 	}
101       else
102 	/* This function will get called to fix up the GOT entry indicated by
103 	   the offset on the stack, and then jump to the resolved address.  */
104 	got[2] = (Elf32_Addr) &_dl_runtime_resolve;
105     }
106 
107   return lazy;
108 }
109 
110 #if defined(ARCH_HAS_BX)
111 #define BX(x) "bx\t" #x
112 #else
113 #define BX(x) "mov\tpc, " #x
114 #endif
115 
116 /* Mask identifying addresses reserved for the user program,
117    where the dynamic linker should not map anything.  */
118 #define ELF_MACHINE_USER_ADDRESS_MASK	0xf8000000UL
119 
120 /* Initial entry point code for the dynamic linker.
121    The C function `_dl_start' is the real entry point;
122    its return value is the user program's entry point.  */
123 
124 #define RTLD_START asm ("\
125 .text\n\
126 .globl _start\n\
127 .type _start, %function\n\
128 .globl _dl_start_user\n\
129 .type _dl_start_user, %function\n\
130 _start:\n\
131 	@ we are PIC code, so get global offset table\n\
132 	ldr	sl, .L_GET_GOT\n\
133 	@ See if we were run as a command with the executable file\n\
134 	@ name as an extra leading argument.\n\
135 	ldr	r4, .L_SKIP_ARGS\n\
136 	@ at start time, all the args are on the stack\n\
137 	mov	r0, sp\n\
138 	bl	_dl_start\n\
139 	@ returns user entry point in r0\n\
140 _dl_start_user:\n\
141 	adr	r6, .L_GET_GOT\n\
142 	add	sl, sl, r6\n\
143 	ldr	r4, [sl, r4]\n\
144 	@ save the entry point in another register\n\
145 	mov	r6, r0\n\
146 	@ get the original arg count\n\
147 	ldr	r1, [sp]\n\
148 	@ get the argv address\n\
149 	add	r2, sp, #4\n\
150 	@ Fix up the stack if necessary.\n\
151 	cmp	r4, #0\n\
152 	bne	.L_fixup_stack\n\
153 .L_done_fixup:\n\
154 	@ compute envp\n\
155 	add	r3, r2, r1, lsl #2\n\
156 	add	r3, r3, #4\n\
157 	@ now we call _dl_init\n\
158 	ldr	r0, .L_LOADED\n\
159 	ldr	r0, [sl, r0]\n\
160 	@ call _dl_init\n\
161 	bl	_dl_init(PLT)\n\
162 	@ load the finalizer function\n\
163 	ldr	r0, .L_FINI_PROC\n\
164 	add	r0, sl, r0\n\
165 	@ jump to the user_s entry point\n\
166 	" BX(r6) "\n\
167 \n\
168 	@ iWMMXt and EABI targets require the stack to be eight byte\n\
169 	@ aligned - shuffle arguments etc.\n\
170 .L_fixup_stack:\n\
171 	@ subtract _dl_skip_args from original arg count\n\
172 	sub	r1, r1, r4\n\
173 	@ store the new argc in the new stack location\n\
174 	str	r1, [sp]\n\
175 	@ find the first unskipped argument\n\
176 	mov	r3, r2\n\
177 	add	r4, r2, r4, lsl #2\n\
178 	@ shuffle argv down\n\
179 1:	ldr	r5, [r4], #4\n\
180 	str	r5, [r3], #4\n\
181 	cmp	r5, #0\n\
182 	bne	1b\n\
183 	@ shuffle envp down\n\
184 1:	ldr	r5, [r4], #4\n\
185 	str	r5, [r3], #4\n\
186 	cmp	r5, #0\n\
187 	bne	1b\n\
188 	@ shuffle auxv down\n\
189 1:	ldmia	r4!, {r0, r5}\n\
190 	stmia	r3!, {r0, r5}\n\
191 	cmp	r0, #0\n\
192 	bne	1b\n\
193 	@ Update _dl_argv\n\
194 	ldr	r3, .L_ARGV\n\
195 	str	r2, [sl, r3]\n\
196 	b	.L_done_fixup\n\
197 \n\
198 .L_GET_GOT:\n\
199 	.word	_GLOBAL_OFFSET_TABLE_ - .L_GET_GOT\n\
200 .L_SKIP_ARGS:\n\
201 	.word	_dl_skip_args(GOTOFF)\n\
202 .L_FINI_PROC:\n\
203 	.word	_dl_fini(GOTOFF)\n\
204 .L_ARGV:\n\
205 	.word	__GI__dl_argv(GOTOFF)\n\
206 .L_LOADED:\n\
207 	.word	_rtld_local(GOTOFF)\n\
208 .previous\n\
209 ");
210 
211 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
212    TLS variable, so undefined references should not be allowed to
213    define the value.
214    ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
215    of the main executable's symbols, as for a COPY reloc.
216    ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA iff TYPE describes relocation against
217    protected data whose address may be external due to copy relocation.  */
218 #ifndef RTLD_BOOTSTRAP
219 # define elf_machine_type_class(type) \
220   ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32		\
221      || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32	\
222      || (type) == R_ARM_TLS_DESC)					\
223     * ELF_RTYPE_CLASS_PLT)						\
224    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)			\
225    | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
226 #else
227 #define elf_machine_type_class(type) \
228   ((((type) == R_ARM_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
229    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)	\
230    | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
231 #endif
232 
233 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
234 #define ELF_MACHINE_JMP_SLOT	R_ARM_JUMP_SLOT
235 
236 /* We define an initialization functions.  This is called very early in
237    _dl_sysdep_start.  */
238 #define DL_PLATFORM_INIT dl_platform_init ()
239 
240 static inline void __attribute__ ((unused))
dl_platform_init(void)241 dl_platform_init (void)
242 {
243   if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
244     /* Avoid an empty string which would disturb us.  */
245     GLRO(dl_platform) = NULL;
246 }
247 
248 static inline Elf32_Addr
elf_machine_fixup_plt(struct link_map * map,lookup_t t,const ElfW (Sym)* refsym,const ElfW (Sym)* sym,const Elf32_Rel * reloc,Elf32_Addr * reloc_addr,Elf32_Addr value)249 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
250 		       const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
251 		       const Elf32_Rel *reloc,
252 		       Elf32_Addr *reloc_addr, Elf32_Addr value)
253 {
254   return *reloc_addr = value;
255 }
256 
257 /* Return the final value of a plt relocation.  */
258 static inline Elf32_Addr
elf_machine_plt_value(struct link_map * map,const Elf32_Rel * reloc,Elf32_Addr value)259 elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc,
260 		       Elf32_Addr value)
261 {
262   return value;
263 }
264 
265 #endif /* !dl_machine_h */
266 
267 
268 /* Names of the architecture-specific auditing callback functions.  */
269 #define ARCH_LA_PLTENTER arm_gnu_pltenter
270 #define ARCH_LA_PLTEXIT arm_gnu_pltexit
271 
272 #ifdef RESOLVE_MAP
273 /* Handle a PC24 reloc, including the out-of-range case.  */
274 static void
relocate_pc24(struct link_map * map,Elf32_Addr value,Elf32_Addr * const reloc_addr,Elf32_Sword addend)275 relocate_pc24 (struct link_map *map, Elf32_Addr value,
276                Elf32_Addr *const reloc_addr, Elf32_Sword addend)
277 {
278   Elf32_Addr new_value;
279 
280   /* Set NEW_VALUE based on V, and return true iff it overflows 24 bits.  */
281   inline bool set_new_value (Elf32_Addr v)
282   {
283     new_value = v + addend - (Elf32_Addr) reloc_addr;
284     Elf32_Addr topbits = new_value & 0xfe000000;
285     return topbits != 0xfe000000 && topbits != 0x00000000;
286   }
287 
288   if (set_new_value (value))
289     {
290       /* The PC-relative address doesn't fit in 24 bits!  */
291 
292       static void *fix_page;
293       static size_t fix_offset;
294       if (fix_page == NULL)
295         {
296           void *new_page = __mmap (NULL, GLRO(dl_pagesize),
297                                    PROT_READ | PROT_WRITE | PROT_EXEC,
298                                    MAP_PRIVATE | MAP_ANON, -1, 0);
299           if (new_page == MAP_FAILED)
300             _dl_signal_error (0, map->l_name, NULL,
301                               "could not map page for fixup");
302           fix_page = new_page;
303           assert (fix_offset == 0);
304         }
305 
306       Elf32_Word *fix_address = fix_page + fix_offset;
307       fix_address[0] = 0xe51ff004;	/* ldr pc, [pc, #-4] */
308       fix_address[1] = value;
309 
310       fix_offset += sizeof fix_address[0] * 2;
311       if (fix_offset >= GLRO(dl_pagesize))
312         {
313           fix_page = NULL;
314           fix_offset = 0;
315         }
316 
317       if (set_new_value ((Elf32_Addr) fix_address))
318         _dl_signal_error (0, map->l_name, NULL,
319                           "R_ARM_PC24 relocation out of range");
320     }
321 
322   *reloc_addr = (*reloc_addr & 0xff000000) | ((new_value >> 2) & 0x00ffffff);
323 }
324 
325 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
326    MAP is the object containing the reloc.  */
327 
328 static inline void
329 __attribute__ ((always_inline))
elf_machine_rel(struct link_map * map,struct r_scope_elem * scope[],const Elf32_Rel * reloc,const Elf32_Sym * sym,const struct r_found_version * version,void * const reloc_addr_arg,int skip_ifunc)330 elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[],
331                  const Elf32_Rel *reloc, const Elf32_Sym *sym,
332                  const struct r_found_version *version,
333 		 void *const reloc_addr_arg, int skip_ifunc)
334 {
335   Elf32_Addr *const reloc_addr = reloc_addr_arg;
336   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
337 
338 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
339   if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
340     {
341 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
342       /* This is defined in rtld.c, but nowhere in the static libc.a;
343 	 make the reference weak so static programs can still link.
344 	 This declaration cannot be done when compiling rtld.c
345 	 (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
346 	 common defn for _dl_rtld_map, which is incompatible with a
347 	 weak decl in the same file.  */
348 #  ifndef SHARED
349       weak_extern (_dl_rtld_map);
350 #  endif
351       if (map != &GL(dl_rtld_map)) /* Already done in rtld itself.  */
352 # endif
353 	*reloc_addr += map->l_addr;
354     }
355 # ifndef RTLD_BOOTSTRAP
356   else if (__builtin_expect (r_type == R_ARM_NONE, 0))
357     return;
358 # endif
359   else
360 #endif
361     {
362       const Elf32_Sym *const refsym = sym;
363       struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
364 					      r_type);
365       Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
366 
367       if (sym != NULL
368 	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
369 	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
370 	  && __builtin_expect (!skip_ifunc, 1))
371 	value = elf_ifunc_invoke (value);
372 
373       switch (r_type)
374 	{
375 	case R_ARM_COPY:
376 	  if (sym == NULL)
377 	    /* This can happen in trace mode if an object could not be
378 	       found.  */
379 	    break;
380 	  if (sym->st_size > refsym->st_size
381 	      || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
382 	    {
383 	      const char *strtab;
384 
385 	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
386 	      _dl_error_printf ("\
387 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
388 				RTLD_PROGNAME, strtab + refsym->st_name);
389 	    }
390 	  memcpy (reloc_addr_arg, (void *) value,
391 		  MIN (sym->st_size, refsym->st_size));
392 	  break;
393 	case R_ARM_GLOB_DAT:
394 	case R_ARM_JUMP_SLOT:
395 # ifdef RTLD_BOOTSTRAP
396 	  /* Fix weak undefined references.  */
397 	  if (sym != NULL && sym->st_value == 0)
398 	    *reloc_addr = 0;
399 	  else
400 # endif
401 	    *reloc_addr = value;
402 	  break;
403 	case R_ARM_ABS32:
404 	  {
405 	    struct unaligned
406 	      {
407 		Elf32_Addr x;
408 	      } __attribute__ ((packed, may_alias));
409 # ifndef RTLD_BOOTSTRAP
410 	   /* This is defined in rtld.c, but nowhere in the static
411 	      libc.a; make the reference weak so static programs can
412 	      still link.  This declaration cannot be done when
413 	      compiling rtld.c (i.e.  #ifdef RTLD_BOOTSTRAP) because
414 	      rtld.c contains the common defn for _dl_rtld_map, which
415 	      is incompatible with a weak decl in the same file.  */
416 #  ifndef SHARED
417 	    weak_extern (_dl_rtld_map);
418 #  endif
419 	    if (map == &GL(dl_rtld_map))
420 	      /* Undo the relocation done here during bootstrapping.
421 		 Now we will relocate it anew, possibly using a
422 		 binding found in the user program or a loaded library
423 		 rather than the dynamic linker's built-in definitions
424 		 used while loading those libraries.  */
425 	      value -= SYMBOL_ADDRESS (map, refsym, true);
426 # endif
427 	    /* Support relocations on mis-aligned offsets.  */
428 	    ((struct unaligned *) reloc_addr)->x += value;
429 	    break;
430 	  }
431 	case R_ARM_TLS_DESC:
432 	  {
433 	    struct tlsdesc *td = (struct tlsdesc *)reloc_addr;
434 
435 # ifndef RTLD_BOOTSTRAP
436 	    if (! sym)
437 	      td->entry = _dl_tlsdesc_undefweak;
438 	    else
439 # endif
440 	      {
441 		if (ELF32_R_SYM (reloc->r_info) == STN_UNDEF)
442 		  value = td->argument.value;
443 		else
444 		  value = sym->st_value;
445 
446 # ifndef RTLD_BOOTSTRAP
447 #  ifndef SHARED
448 		CHECK_STATIC_TLS (map, sym_map);
449 #  else
450 		if (!TRY_STATIC_TLS (map, sym_map))
451 		  {
452 		    td->argument.pointer
453 		      = _dl_make_tlsdesc_dynamic (sym_map, value);
454 		    td->entry = _dl_tlsdesc_dynamic;
455 		  }
456 		else
457 #  endif
458 # endif
459 		{
460 		  td->argument.value = value + sym_map->l_tls_offset;
461 		  td->entry = _dl_tlsdesc_return;
462 		}
463 	      }
464 	    }
465 	    break;
466 	case R_ARM_PC24:
467           relocate_pc24 (map, value, reloc_addr,
468                          /* Sign-extend the 24-bit addend in the
469                             instruction (which counts instructions), and
470                             then shift it up two so as to count bytes.  */
471                          (((Elf32_Sword) *reloc_addr << 8) >> 8) << 2);
472 	  break;
473 #if !defined RTLD_BOOTSTRAP
474 	case R_ARM_TLS_DTPMOD32:
475 	  /* Get the information from the link map returned by the
476 	     resolv function.  */
477 	  if (sym_map != NULL)
478 	    *reloc_addr = sym_map->l_tls_modid;
479 	  break;
480 
481 	case R_ARM_TLS_DTPOFF32:
482 	  if (sym != NULL)
483 	    *reloc_addr += sym->st_value;
484 	  break;
485 
486 	case R_ARM_TLS_TPOFF32:
487 	  if (sym != NULL)
488 	    {
489 	      CHECK_STATIC_TLS (map, sym_map);
490 	      *reloc_addr += sym->st_value + sym_map->l_tls_offset;
491 	    }
492 	  break;
493 	case R_ARM_IRELATIVE:
494 	  value = map->l_addr + *reloc_addr;
495 	  if (__glibc_likely (!skip_ifunc))
496 	    value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
497 	  *reloc_addr = value;
498 	  break;
499 #endif
500 	default:
501 	  _dl_reloc_bad_type (map, r_type, 0);
502 	  break;
503 	}
504     }
505 }
506 
507 # ifndef RTLD_BOOTSTRAP
508 static inline void
509 __attribute__ ((always_inline))
elf_machine_rela(struct link_map * map,struct r_scope_elem * scope[],const Elf32_Rela * reloc,const Elf32_Sym * sym,const struct r_found_version * version,void * const reloc_addr_arg,int skip_ifunc)510 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
511                   const Elf32_Rela *reloc, const Elf32_Sym *sym,
512                   const struct r_found_version *version,
513 		  void *const reloc_addr_arg, int skip_ifunc)
514 {
515   Elf32_Addr *const reloc_addr = reloc_addr_arg;
516   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
517 
518   if (__builtin_expect (r_type == R_ARM_RELATIVE, 0))
519     *reloc_addr = map->l_addr + reloc->r_addend;
520   else if (__builtin_expect (r_type == R_ARM_NONE, 0))
521     return;
522   else
523     {
524 # ifndef RESOLVE_CONFLICT_FIND_MAP
525       const Elf32_Sym *const refsym = sym;
526 # endif
527       struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type);
528       Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true);
529 
530       if (sym != NULL
531 	  && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
532 	  && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
533 	  && __builtin_expect (!skip_ifunc, 1))
534 	value = elf_ifunc_invoke (value);
535 
536       switch (r_type)
537 	{
538 #  ifndef RESOLVE_CONFLICT_FIND_MAP
539 	  /* Not needed for dl-conflict.c.  */
540 	case R_ARM_COPY:
541 	  if (sym == NULL)
542 	    /* This can happen in trace mode if an object could not be
543 	       found.  */
544 	    break;
545 	  if (sym->st_size > refsym->st_size
546 	      || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
547 	    {
548 	      const char *strtab;
549 
550 	      strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
551 	      _dl_error_printf ("\
552 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
553 				RTLD_PROGNAME, strtab + refsym->st_name);
554 	    }
555 	  memcpy (reloc_addr_arg, (void *) value,
556 		  MIN (sym->st_size, refsym->st_size));
557 	  break;
558 #  endif /* !RESOLVE_CONFLICT_FIND_MAP */
559 	case R_ARM_GLOB_DAT:
560 	case R_ARM_JUMP_SLOT:
561 	case R_ARM_ABS32:
562 	  *reloc_addr = value + reloc->r_addend;
563 	  break;
564 	case R_ARM_PC24:
565           relocate_pc24 (map, value, reloc_addr, reloc->r_addend);
566 	  break;
567 #if !defined RTLD_BOOTSTRAP
568 	case R_ARM_TLS_DTPMOD32:
569 	  /* Get the information from the link map returned by the
570 	     resolv function.  */
571 	  if (sym_map != NULL)
572 	    *reloc_addr = sym_map->l_tls_modid;
573 	  break;
574 
575 	case R_ARM_TLS_DTPOFF32:
576 	  *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
577 	  break;
578 
579 	case R_ARM_TLS_TPOFF32:
580 	  if (sym != NULL)
581 	    {
582 	      CHECK_STATIC_TLS (map, sym_map);
583 	      *reloc_addr = (sym->st_value + sym_map->l_tls_offset
584 			     + reloc->r_addend);
585 	    }
586 	  break;
587 	case R_ARM_IRELATIVE:
588 	  value = map->l_addr + reloc->r_addend;
589 	  if (__glibc_likely (!skip_ifunc))
590 	    value = ((Elf32_Addr (*) (int)) value) (GLRO(dl_hwcap));
591 	  *reloc_addr = value;
592 	  break;
593 #endif
594 	default:
595 	  _dl_reloc_bad_type (map, r_type, 0);
596 	  break;
597 	}
598     }
599 }
600 # endif
601 
602 static inline void
603 __attribute__ ((always_inline))
elf_machine_rel_relative(Elf32_Addr l_addr,const Elf32_Rel * reloc,void * const reloc_addr_arg)604 elf_machine_rel_relative (Elf32_Addr l_addr, const Elf32_Rel *reloc,
605 			  void *const reloc_addr_arg)
606 {
607   Elf32_Addr *const reloc_addr = reloc_addr_arg;
608   *reloc_addr += l_addr;
609 }
610 
611 # ifndef RTLD_BOOTSTRAP
612 static inline void
613 __attribute__ ((always_inline))
elf_machine_rela_relative(Elf32_Addr l_addr,const Elf32_Rela * reloc,void * const reloc_addr_arg)614 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
615 			   void *const reloc_addr_arg)
616 {
617   Elf32_Addr *const reloc_addr = reloc_addr_arg;
618   *reloc_addr = l_addr + reloc->r_addend;
619 }
620 # endif
621 
622 static inline void
623 __attribute__ ((always_inline))
elf_machine_lazy_rel(struct link_map * map,struct r_scope_elem * scope[],Elf32_Addr l_addr,const Elf32_Rel * reloc,int skip_ifunc)624 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
625 		      Elf32_Addr l_addr, const Elf32_Rel *reloc,
626 		      int skip_ifunc)
627 {
628   Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
629   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
630   /* Check for unexpected PLT reloc type.  */
631   if (__builtin_expect (r_type == R_ARM_JUMP_SLOT, 1))
632     {
633       if (__builtin_expect (map->l_mach.plt, 0) == 0)
634 	*reloc_addr += l_addr;
635       else
636 	*reloc_addr = map->l_mach.plt;
637     }
638   else if (__builtin_expect (r_type == R_ARM_TLS_DESC, 1))
639     {
640       const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
641       const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
642       const ElfW (Sym) *sym = &symtab[symndx];
643       const struct r_found_version *version = NULL;
644 
645       if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
646 	{
647 	  const ElfW (Half) *vernum =
648 	    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
649 	  version = &map->l_versions[vernum[symndx] & 0x7fff];
650 	}
651 
652       /* Always initialize TLS descriptors completely, because lazy
653 	 initialization requires synchronization at every TLS access.  */
654       elf_machine_rel (map, scope, reloc, sym, version, reloc_addr, skip_ifunc);
655     }
656   else
657     _dl_reloc_bad_type (map, r_type, 1);
658 }
659 
660 #endif /* RESOLVE_MAP */
661