configure: Move nm, objdump, and readelf to LIBC_PROG_BINUTILS
[glibc.git] / sysdeps / aarch64 / dl-machine.h
blob4170b9269f7a79590091820201ed85e7a1e1f399
1 /* Copyright (C) 1995-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
19 #ifndef dl_machine_h
20 #define dl_machine_h
22 #define ELF_MACHINE_NAME "aarch64"
24 #include <sysdep.h>
25 #include <tls.h>
26 #include <dl-tlsdesc.h>
27 #include <dl-static-tls.h>
28 #include <dl-irel.h>
29 #include <dl-machine-rel.h>
30 #include <cpu-features.c>
32 /* Translate a processor specific dynamic tag to the index in l_info array. */
33 #define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
35 /* Return nonzero iff ELF header is compatible with the running host. */
36 static inline int __attribute__ ((unused))
37 elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
39 return ehdr->e_machine == EM_AARCH64;
42 /* Return the run-time load address of the shared object. */
44 static inline ElfW(Addr) __attribute__ ((unused))
45 elf_machine_load_address (void)
47 extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
48 return (ElfW(Addr)) &__ehdr_start;
51 /* Return the link-time address of _DYNAMIC. */
53 static inline ElfW(Addr) __attribute__ ((unused))
54 elf_machine_dynamic (void)
56 extern ElfW(Dyn) _DYNAMIC[] attribute_hidden;
57 return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address ();
60 /* Set up the loaded object described by L so its unrelocated PLT
61 entries will jump to the on-demand fixup code in dl-runtime.c. */
63 static inline int __attribute__ ((unused))
64 elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
65 int lazy, int profile)
67 if (l->l_info[DT_JMPREL] && lazy)
69 ElfW(Addr) *got;
70 extern void _dl_runtime_resolve (ElfW(Word));
71 extern void _dl_runtime_profile (ElfW(Word));
73 got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
74 if (got[1])
76 l->l_mach.plt = got[1] + l->l_addr;
78 got[1] = (ElfW(Addr)) l;
80 /* The got[2] entry contains the address of a function which gets
81 called to get the address of a so far unresolved function and
82 jump to it. The profiling extension of the dynamic linker allows
83 to intercept the calls to collect information. In this case we
84 don't store the address in the GOT so that all future calls also
85 end in this function. */
86 if ( profile)
88 got[2] = (ElfW(Addr)) &_dl_runtime_profile;
90 if (GLRO(dl_profile) != NULL
91 && _dl_name_match_p (GLRO(dl_profile), l))
92 /* Say that we really want profiling and the timers are
93 started. */
94 GL(dl_profile_map) = l;
96 else
98 /* This function will get called to fix up the GOT entry
99 indicated by the offset on the stack, and then jump to
100 the resolved address. */
101 got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
105 return lazy;
108 /* In elf/rtld.c _dl_start should be global so dl-start.S can reference it. */
109 #define RTLD_START asm (".globl _dl_start");
111 #define elf_machine_type_class(type) \
112 ((((type) == R_AARCH64_JUMP_SLOT || \
113 (type) == R_AARCH64_TLS_DTPMOD || \
114 (type) == R_AARCH64_TLS_DTPREL || \
115 (type) == R_AARCH64_TLS_TPREL || \
116 (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
117 | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
119 #define ELF_MACHINE_JMP_SLOT AARCH64_R(JUMP_SLOT)
121 #define DL_PLATFORM_INIT dl_platform_init ()
123 static inline void __attribute__ ((unused))
124 dl_platform_init (void)
126 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
127 /* Avoid an empty string which would disturb us. */
128 GLRO(dl_platform) = NULL;
130 #ifdef SHARED
131 /* init_cpu_features has been called early from __libc_start_main in
132 static executable. */
133 init_cpu_features (&GLRO(dl_aarch64_cpu_features));
134 #endif
138 static inline ElfW(Addr)
139 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
140 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
141 const ElfW(Rela) *reloc,
142 ElfW(Addr) *reloc_addr,
143 ElfW(Addr) value)
145 return *reloc_addr = value;
148 /* Return the final value of a plt relocation. */
149 static inline ElfW(Addr)
150 elf_machine_plt_value (struct link_map *map,
151 const ElfW(Rela) *reloc,
152 ElfW(Addr) value)
154 return value;
157 #endif
159 /* Names of the architecture-specific auditing callback functions. */
160 #define ARCH_LA_PLTENTER aarch64_gnu_pltenter
161 #define ARCH_LA_PLTEXIT aarch64_gnu_pltexit
163 #ifdef RESOLVE_MAP
165 static inline void
166 __attribute__ ((always_inline))
167 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
168 const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
169 const struct r_found_version *version,
170 void *const reloc_addr_arg, int skip_ifunc)
172 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
173 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
175 if (__builtin_expect (r_type == AARCH64_R(RELATIVE), 0))
176 *reloc_addr = map->l_addr + reloc->r_addend;
177 else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
178 return;
179 else
181 # ifndef RTLD_BOOTSTRAP
182 const ElfW(Sym) *const refsym = sym;
183 # endif
184 struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
185 r_type);
186 ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
188 if (sym != NULL
189 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
190 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
191 && __glibc_likely (!skip_ifunc))
192 value = elf_ifunc_invoke (value);
194 switch (r_type)
196 case AARCH64_R(GLOB_DAT):
197 case AARCH64_R(JUMP_SLOT):
198 *reloc_addr = value + reloc->r_addend;
199 break;
201 # ifndef RTLD_BOOTSTRAP
202 case AARCH64_R(ABS32):
203 # ifdef __LP64__
204 case AARCH64_R(ABS64):
205 # endif
206 *reloc_addr = value + reloc->r_addend;
207 break;
208 case AARCH64_R(COPY):
209 if (sym == NULL)
210 break;
212 if (sym->st_size > refsym->st_size
213 || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
215 const char *strtab;
217 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
218 _dl_error_printf ("\
219 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
220 RTLD_PROGNAME, strtab + refsym->st_name);
222 memcpy (reloc_addr_arg, (void *) value,
223 sym->st_size < refsym->st_size
224 ? sym->st_size : refsym->st_size);
225 break;
227 case AARCH64_R(TLSDESC):
229 struct tlsdesc volatile *td =
230 (struct tlsdesc volatile *)reloc_addr;
231 if (! sym)
233 td->arg = (void*)reloc->r_addend;
234 td->entry = _dl_tlsdesc_undefweak;
236 else
238 # ifndef SHARED
239 CHECK_STATIC_TLS (map, sym_map);
240 # else
241 if (!TRY_STATIC_TLS (map, sym_map))
243 td->arg = _dl_make_tlsdesc_dynamic
244 (sym_map, sym->st_value + reloc->r_addend);
245 td->entry = _dl_tlsdesc_dynamic;
247 else
248 # endif
250 td->arg = (void*)(sym->st_value + sym_map->l_tls_offset
251 + reloc->r_addend);
252 td->entry = _dl_tlsdesc_return;
255 break;
258 case AARCH64_R(TLS_DTPMOD):
259 if (sym_map != NULL)
261 *reloc_addr = sym_map->l_tls_modid;
263 break;
265 case AARCH64_R(TLS_DTPREL):
266 if (sym)
267 *reloc_addr = sym->st_value + reloc->r_addend;
268 break;
270 case AARCH64_R(TLS_TPREL):
271 if (sym)
273 CHECK_STATIC_TLS (map, sym_map);
274 *reloc_addr =
275 sym->st_value + reloc->r_addend + sym_map->l_tls_offset;
277 break;
279 case AARCH64_R(IRELATIVE):
280 value = map->l_addr + reloc->r_addend;
281 if (__glibc_likely (!skip_ifunc))
282 value = elf_ifunc_invoke (value);
283 *reloc_addr = value;
284 break;
285 # endif /* !RTLD_BOOTSTRAP */
287 default:
288 _dl_reloc_bad_type (map, r_type, 0);
289 break;
294 static inline void
295 __attribute__ ((always_inline))
296 elf_machine_rela_relative (ElfW(Addr) l_addr,
297 const ElfW(Rela) *reloc,
298 void *const reloc_addr_arg)
300 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
301 *reloc_addr = l_addr + reloc->r_addend;
304 static inline void
305 __attribute__ ((always_inline))
306 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
307 ElfW(Addr) l_addr,
308 const ElfW(Rela) *reloc,
309 int skip_ifunc)
311 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
312 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
313 /* Check for unexpected PLT reloc type. */
314 if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
316 if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
318 /* Check the symbol table for variant PCS symbols. */
319 const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
320 const ElfW (Sym) *symtab =
321 (const void *)D_PTR (map, l_info[DT_SYMTAB]);
322 const ElfW (Sym) *sym = &symtab[symndx];
323 if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
325 /* Avoid lazy resolution of variant PCS symbols. */
326 const struct r_found_version *version = NULL;
327 if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
329 const ElfW (Half) *vernum =
330 (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
331 version = &map->l_versions[vernum[symndx] & 0x7fff];
333 elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
334 skip_ifunc);
335 return;
339 if (map->l_mach.plt == 0)
340 *reloc_addr += l_addr;
341 else
342 *reloc_addr = map->l_mach.plt;
344 else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
346 const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
347 const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
348 const ElfW (Sym) *sym = &symtab[symndx];
349 const struct r_found_version *version = NULL;
351 if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
353 const ElfW (Half) *vernum =
354 (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
355 version = &map->l_versions[vernum[symndx] & 0x7fff];
358 /* Always initialize TLS descriptors completely, because lazy
359 initialization requires synchronization at every TLS access. */
360 elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
361 skip_ifunc);
363 else if (__glibc_unlikely (r_type == AARCH64_R(IRELATIVE)))
365 ElfW(Addr) value = map->l_addr + reloc->r_addend;
366 if (__glibc_likely (!skip_ifunc))
367 value = elf_ifunc_invoke (value);
368 *reloc_addr = value;
370 else
371 _dl_reloc_bad_type (map, r_type, 1);
374 #endif