]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/aarch64/dl-machine.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / aarch64 / dl-machine.h
CommitLineData
f7a9f785 1/* Copyright (C) 1995-2016 Free Software Foundation, Inc.
554066b8
MS
2
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 License as
7 published by the Free Software Foundation; either version 2.1 of the
8 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 <http://www.gnu.org/licenses/>. */
18
19#ifndef dl_machine_h
20#define dl_machine_h
21
22#define ELF_MACHINE_NAME "aarch64"
23
24#include <tls.h>
25#include <dl-tlsdesc.h>
7520ff8c 26#include <dl-irel.h>
554066b8
MS
27
28/* Return nonzero iff ELF header is compatible with the running host. */
29static inline int __attribute__ ((unused))
30elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
31{
32 return ehdr->e_machine == EM_AARCH64;
33}
34
35/* Return the link-time address of _DYNAMIC. Conveniently, this is the
36 first element of the GOT. */
37static inline ElfW(Addr) __attribute__ ((unused))
38elf_machine_dynamic (void)
39{
ed0257f7
MS
40 extern const ElfW(Addr) _GLOBAL_OFFSET_TABLE_[] attribute_hidden;
41 return _GLOBAL_OFFSET_TABLE_[0];
554066b8
MS
42}
43
44/* Return the run-time load address of the shared object. */
45
46static inline ElfW(Addr) __attribute__ ((unused))
47elf_machine_load_address (void)
48{
49 /* To figure out the load address we use the definition that for any symbol:
50 dynamic_addr(symbol) = static_addr(symbol) + load_addr
51
52 The choice of symbol is arbitrary. The static address we obtain
53 by constructing a non GOT reference to the symbol, the dynamic
54 address of the symbol we compute using adrp/add to compute the
6d3db89b
AP
55 symbol's address relative to the PC.
56 This depends on 32bit relocations being resolved at link time
57 and that the static address fits in the 32bits. */
554066b8
MS
58
59 ElfW(Addr) static_addr;
60 ElfW(Addr) dynamic_addr;
61
6d3db89b
AP
62 asm (" \n"
63" adrp %1, _dl_start; \n"
64" add %1, %1, #:lo12:_dl_start \n"
65" ldr %w0, 1f \n"
66" b 2f \n"
67"1: \n"
68" .word _dl_start \n"
69"2: \n"
70 : "=r" (static_addr), "=r" (dynamic_addr));
554066b8
MS
71 return dynamic_addr - static_addr;
72}
73
74/* Set up the loaded object described by L so its unrelocated PLT
75 entries will jump to the on-demand fixup code in dl-runtime.c. */
76
77static inline int __attribute__ ((unused))
78elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
79{
80 if (l->l_info[DT_JMPREL] && lazy)
81 {
82 ElfW(Addr) *got;
83 extern void _dl_runtime_resolve (ElfW(Word));
84 extern void _dl_runtime_profile (ElfW(Word));
85
86 got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
87 if (got[1])
88 {
89 l->l_mach.plt = got[1] + l->l_addr;
90 }
91 got[1] = (ElfW(Addr)) l;
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 {
101 got[2] = (ElfW(Addr)) &_dl_runtime_profile;
102
103 if (GLRO(dl_profile) != NULL
104 && _dl_name_match_p (GLRO(dl_profile), l))
105 /* Say that we really want profiling and the timers are
106 started. */
107 GL(dl_profile_map) = l;
108 }
109 else
110 {
111 /* This function will get called to fix up the GOT entry
112 indicated by the offset on the stack, and then jump to
113 the resolved address. */
114 got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
115 }
116 }
117
118 if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy)
01194ba1
WN
119 *(ElfW(Addr)*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr)
120 = (ElfW(Addr)) &_dl_tlsdesc_resolve_rela;
554066b8
MS
121
122 return lazy;
123}
124
125/* Initial entry point for the dynamic linker. The C function
126 _dl_start is the real entry point, its return value is the user
127 program's entry point */
128
129#define RTLD_START asm ("\
130.text \n\
131.globl _start \n\
132.type _start, %function \n\
133.globl _dl_start_user \n\
134.type _dl_start_user, %function \n\
135_start: \n\
136 mov x0, sp \n\
137 bl _dl_start \n\
138 // returns user entry point in x0 \n\
139 mov x21, x0 \n\
140_dl_start_user: \n\
141 // get the original arg count \n\
142 ldr x1, [sp] \n\
143 // get the argv address \n\
144 add x2, sp, #8 \n\
145 // get _dl_skip_args to see if we were \n\
146 // invoked as an executable \n\
147 adrp x4, _dl_skip_args \n\
148 ldr w4, [x4, #:lo12:_dl_skip_args] \n\
149 // do we need to adjust argc/argv \n\
150 cmp w4, 0 \n\
151 beq .L_done_stack_adjust \n\
152 // subtract _dl_skip_args from original arg count \n\
153 sub x1, x1, x4 \n\
154 // store adjusted argc back to stack \n\
155 str x1, [sp] \n\
156 // find the first unskipped argument \n\
157 mov x3, x2 \n\
158 add x4, x2, x4, lsl #3 \n\
159 // shuffle argv down \n\
1601: ldr x5, [x4], #8 \n\
161 str x5, [x3], #8 \n\
162 cmp x5, #0 \n\
163 bne 1b \n\
164 // shuffle envp down \n\
1651: ldr x5, [x4], #8 \n\
166 str x5, [x3], #8 \n\
167 cmp x5, #0 \n\
168 bne 1b \n\
169 // shuffle auxv down \n\
1701: ldp x0, x5, [x4, #16]! \n\
171 stp x0, x5, [x3], #16 \n\
172 cmp x0, #0 \n\
173 bne 1b \n\
174 // Update _dl_argv \n\
175 adrp x3, _dl_argv \n\
176 str x2, [x3, #:lo12:_dl_argv] \n\
177.L_done_stack_adjust: \n\
178 // compute envp \n\
179 add x3, x2, x1, lsl #3 \n\
180 add x3, x3, #8 \n\
181 adrp x16, _rtld_local \n\
182 add x16, x16, #:lo12:_rtld_local \n\
183 ldr x0, [x16] \n\
c5684fdb 184 bl _dl_init \n\
554066b8
MS
185 // load the finalizer function \n\
186 adrp x0, _dl_fini \n\
187 add x0, x0, #:lo12:_dl_fini \n\
188 // jump to the user_s entry point \n\
189 br x21 \n\
190");
191
192#define elf_machine_type_class(type) \
193 ((((type) == R_AARCH64_JUMP_SLOT || \
8c230039
WN
194 (type) == R_AARCH64_TLS_DTPMOD || \
195 (type) == R_AARCH64_TLS_DTPREL || \
196 (type) == R_AARCH64_TLS_TPREL || \
554066b8 197 (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
0910702c
SN
198 | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY) \
199 | (((type) == R_AARCH64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
554066b8
MS
200
201#define ELF_MACHINE_JMP_SLOT R_AARCH64_JUMP_SLOT
202
203/* AArch64 uses RELA not REL */
204#define ELF_MACHINE_NO_REL 1
4cf5b6d0 205#define ELF_MACHINE_NO_RELA 0
554066b8
MS
206
207static inline ElfW(Addr)
208elf_machine_fixup_plt (struct link_map *map, lookup_t t,
209 const ElfW(Rela) *reloc,
210 ElfW(Addr) *reloc_addr,
211 ElfW(Addr) value)
212{
213 return *reloc_addr = value;
214}
215
216/* Return the final value of a plt relocation. */
217static inline ElfW(Addr)
218elf_machine_plt_value (struct link_map *map,
219 const ElfW(Rela) *reloc,
220 ElfW(Addr) value)
221{
222 return value;
223}
224
225#endif
226
227/* Names of the architecture-specific auditing callback functions. */
228#define ARCH_LA_PLTENTER aarch64_gnu_pltenter
229#define ARCH_LA_PLTEXIT aarch64_gnu_pltexit
230
231#ifdef RESOLVE_MAP
232
233auto inline void
234__attribute__ ((always_inline))
235elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
236 const ElfW(Sym) *sym, const struct r_found_version *version,
237 void *const reloc_addr_arg, int skip_ifunc)
238{
239 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
240 const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
241
242 if (__builtin_expect (r_type == R_AARCH64_RELATIVE, 0))
243 *reloc_addr = map->l_addr + reloc->r_addend;
244 else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
245 return;
246 else
247 {
248 const ElfW(Sym) *const refsym = sym;
249 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
250 ElfW(Addr) value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
251
7520ff8c
WN
252 if (sym != NULL
253 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
254 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
255 && __glibc_likely (!skip_ifunc))
256 value = elf_ifunc_invoke (value);
257
554066b8
MS
258 switch (r_type)
259 {
260 case R_AARCH64_COPY:
261 if (sym == NULL)
262 break;
263
264 if (sym->st_size > refsym->st_size
265 || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
266 {
267 const char *strtab;
268
269 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
270 _dl_error_printf ("\
271%s: Symbol `%s' has different size in shared object, consider re-linking\n",
b9375348 272 RTLD_PROGNAME, strtab + refsym->st_name);
554066b8
MS
273 }
274 memcpy (reloc_addr_arg, (void *) value,
275 MIN (sym->st_size, refsym->st_size));
276 break;
277
278 case R_AARCH64_RELATIVE:
279 case R_AARCH64_GLOB_DAT:
280 case R_AARCH64_JUMP_SLOT:
281 case R_AARCH64_ABS32:
282 case R_AARCH64_ABS64:
283 *reloc_addr = value + reloc->r_addend;
284 break;
285
286 case R_AARCH64_TLSDESC:
287 {
288 struct tlsdesc volatile *td =
289 (struct tlsdesc volatile *)reloc_addr;
290#ifndef RTLD_BOOTSTRAP
291 if (! sym)
292 {
293 td->arg = (void*)reloc->r_addend;
294 td->entry = _dl_tlsdesc_undefweak;
295 }
296 else
297#endif
298 {
299#ifndef RTLD_BOOTSTRAP
300# ifndef SHARED
301 CHECK_STATIC_TLS (map, sym_map);
302# else
303 if (!TRY_STATIC_TLS (map, sym_map))
304 {
305 td->arg = _dl_make_tlsdesc_dynamic
306 (sym_map, sym->st_value + reloc->r_addend);
307 td->entry = _dl_tlsdesc_dynamic;
308 }
309 else
310# endif
311#endif
312 {
313 td->arg = (void*)(sym->st_value + sym_map->l_tls_offset
314 + reloc->r_addend);
315 td->entry = _dl_tlsdesc_return;
316 }
317 }
318 break;
319 }
320
8c230039 321 case R_AARCH64_TLS_DTPMOD:
554066b8
MS
322#ifdef RTLD_BOOTSTRAP
323 *reloc_addr = 1;
324#else
325 if (sym_map != NULL)
326 {
327 *reloc_addr = sym_map->l_tls_modid;
328 }
329#endif
330 break;
331
8c230039 332 case R_AARCH64_TLS_DTPREL:
554066b8 333 if (sym)
443d9489 334 *reloc_addr = sym->st_value + reloc->r_addend;
554066b8
MS
335 break;
336
8c230039 337 case R_AARCH64_TLS_TPREL:
554066b8
MS
338 if (sym)
339 {
554066b8
MS
340 CHECK_STATIC_TLS (map, sym_map);
341 *reloc_addr =
342 sym->st_value + reloc->r_addend + sym_map->l_tls_offset;
343 }
344 break;
345
7520ff8c
WN
346 case R_AARCH64_IRELATIVE:
347 value = map->l_addr + reloc->r_addend;
348 value = elf_ifunc_invoke (value);
349 *reloc_addr = value;
350 break;
351
554066b8
MS
352 default:
353 _dl_reloc_bad_type (map, r_type, 0);
354 break;
355 }
356 }
357}
358
359inline void
360__attribute__ ((always_inline))
361elf_machine_rela_relative (ElfW(Addr) l_addr,
362 const ElfW(Rela) *reloc,
363 void *const reloc_addr_arg)
364{
365 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
366 *reloc_addr = l_addr + reloc->r_addend;
367}
368
369inline void
370__attribute__ ((always_inline))
371elf_machine_lazy_rel (struct link_map *map,
372 ElfW(Addr) l_addr,
373 const ElfW(Rela) *reloc,
374 int skip_ifunc)
375{
376 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
377 const unsigned int r_type = ELF64_R_TYPE (reloc->r_info);
378 /* Check for unexpected PLT reloc type. */
379 if (__builtin_expect (r_type == R_AARCH64_JUMP_SLOT, 1))
380 {
381 if (__builtin_expect (map->l_mach.plt, 0) == 0)
382 *reloc_addr += l_addr;
383 else
384 *reloc_addr = map->l_mach.plt;
385 }
386 else if (__builtin_expect (r_type == R_AARCH64_TLSDESC, 1))
387 {
388 struct tlsdesc volatile *td =
389 (struct tlsdesc volatile *)reloc_addr;
390
391 td->arg = (void*)reloc;
392 td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
393 + map->l_addr);
394 }
7520ff8c
WN
395 else if (__glibc_unlikely (r_type == R_AARCH64_IRELATIVE))
396 {
397 ElfW(Addr) value = map->l_addr + reloc->r_addend;
398 if (__glibc_likely (!skip_ifunc))
399 value = elf_ifunc_invoke (value);
400 *reloc_addr = value;
401 }
554066b8
MS
402 else
403 _dl_reloc_bad_type (map, r_type, 1);
404}
405
406#endif