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