elf: Ignore loader debug env vars for setuid
[glibc.git] / sysdeps / aarch64 / dl-machine.h
bloba56eb96a7956825373507c3141c53a9961bca0a3
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));
72 got = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
73 if (got[1])
75 l->l_mach.plt = got[1] + l->l_addr;
77 got[1] = (ElfW(Addr)) l;
79 /* The got[2] entry contains the address of a function which gets
80 called to get the address of a so far unresolved function and
81 jump to it. The profiling extension of the dynamic linker allows
82 to intercept the calls to collect information. In this case we
83 don't store the address in the GOT so that all future calls also
84 end in this function. */
85 #ifdef SHARED
86 extern void _dl_runtime_profile (ElfW(Word));
87 if ( profile)
89 got[2] = (ElfW(Addr)) &_dl_runtime_profile;
91 if (GLRO(dl_profile) != NULL
92 && _dl_name_match_p (GLRO(dl_profile), l))
93 /* Say that we really want profiling and the timers are
94 started. */
95 GL(dl_profile_map) = l;
97 else
98 #endif
100 /* This function will get called to fix up the GOT entry
101 indicated by the offset on the stack, and then jump to
102 the resolved address. */
103 got[2] = (ElfW(Addr)) &_dl_runtime_resolve;
107 return lazy;
110 /* In elf/rtld.c _dl_start should be global so dl-start.S can reference it. */
111 #define RTLD_START asm (".globl _dl_start");
113 #define elf_machine_type_class(type) \
114 ((((type) == R_AARCH64_JUMP_SLOT || \
115 (type) == R_AARCH64_TLS_DTPMOD || \
116 (type) == R_AARCH64_TLS_DTPREL || \
117 (type) == R_AARCH64_TLS_TPREL || \
118 (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
119 | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
121 #define ELF_MACHINE_JMP_SLOT AARCH64_R(JUMP_SLOT)
123 #define DL_PLATFORM_INIT dl_platform_init ()
125 static inline void __attribute__ ((unused))
126 dl_platform_init (void)
128 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
129 /* Avoid an empty string which would disturb us. */
130 GLRO(dl_platform) = NULL;
132 #ifdef SHARED
133 /* init_cpu_features has been called early from __libc_start_main in
134 static executable. */
135 init_cpu_features (&GLRO(dl_aarch64_cpu_features));
136 #endif
140 static inline ElfW(Addr)
141 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
142 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
143 const ElfW(Rela) *reloc,
144 ElfW(Addr) *reloc_addr,
145 ElfW(Addr) value)
147 return *reloc_addr = value;
150 /* Return the final value of a plt relocation. */
151 static inline ElfW(Addr)
152 elf_machine_plt_value (struct link_map *map,
153 const ElfW(Rela) *reloc,
154 ElfW(Addr) value)
156 return value;
159 #endif
161 /* Names of the architecture-specific auditing callback functions. */
162 #define ARCH_LA_PLTENTER aarch64_gnu_pltenter
163 #define ARCH_LA_PLTEXIT aarch64_gnu_pltexit
165 #ifdef RESOLVE_MAP
167 static inline void
168 __attribute__ ((always_inline))
169 elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
170 const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
171 const struct r_found_version *version,
172 void *const reloc_addr_arg, int skip_ifunc)
174 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
175 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
177 if (__builtin_expect (r_type == AARCH64_R(RELATIVE), 0))
178 *reloc_addr = map->l_addr + reloc->r_addend;
179 else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
180 return;
181 else
183 # ifndef RTLD_BOOTSTRAP
184 const ElfW(Sym) *const refsym = sym;
185 # endif
186 struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
187 r_type);
188 ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
190 if (sym != NULL
191 && __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
192 && __glibc_likely (sym->st_shndx != SHN_UNDEF)
193 && __glibc_likely (!skip_ifunc))
194 value = elf_ifunc_invoke (value);
196 switch (r_type)
198 case AARCH64_R(GLOB_DAT):
199 case AARCH64_R(JUMP_SLOT):
200 *reloc_addr = value + reloc->r_addend;
201 break;
203 # ifndef RTLD_BOOTSTRAP
204 case AARCH64_R(ABS32):
205 # ifdef __LP64__
206 case AARCH64_R(ABS64):
207 # endif
208 *reloc_addr = value + reloc->r_addend;
209 break;
210 case AARCH64_R(COPY):
211 if (sym == NULL)
212 break;
214 if (sym->st_size > refsym->st_size
215 || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
217 const char *strtab;
219 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
220 _dl_error_printf ("\
221 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
222 RTLD_PROGNAME, strtab + refsym->st_name);
224 memcpy (reloc_addr_arg, (void *) value,
225 sym->st_size < refsym->st_size
226 ? sym->st_size : refsym->st_size);
227 break;
229 case AARCH64_R(TLSDESC):
231 struct tlsdesc volatile *td =
232 (struct tlsdesc volatile *)reloc_addr;
233 if (! sym)
235 td->arg = (void*)reloc->r_addend;
236 td->entry = _dl_tlsdesc_undefweak;
238 else
240 # ifndef SHARED
241 CHECK_STATIC_TLS (map, sym_map);
242 # else
243 if (!TRY_STATIC_TLS (map, sym_map))
245 td->arg = _dl_make_tlsdesc_dynamic
246 (sym_map, sym->st_value + reloc->r_addend);
247 td->entry = _dl_tlsdesc_dynamic;
249 else
250 # endif
252 td->arg = (void*)(sym->st_value + sym_map->l_tls_offset
253 + reloc->r_addend);
254 td->entry = _dl_tlsdesc_return;
257 break;
260 case AARCH64_R(TLS_DTPMOD):
261 if (sym_map != NULL)
263 *reloc_addr = sym_map->l_tls_modid;
265 break;
267 case AARCH64_R(TLS_DTPREL):
268 if (sym)
269 *reloc_addr = sym->st_value + reloc->r_addend;
270 break;
272 case AARCH64_R(TLS_TPREL):
273 if (sym)
275 CHECK_STATIC_TLS (map, sym_map);
276 *reloc_addr =
277 sym->st_value + reloc->r_addend + sym_map->l_tls_offset;
279 break;
281 case AARCH64_R(IRELATIVE):
282 value = map->l_addr + reloc->r_addend;
283 if (__glibc_likely (!skip_ifunc))
284 value = elf_ifunc_invoke (value);
285 *reloc_addr = value;
286 break;
287 # endif /* !RTLD_BOOTSTRAP */
289 default:
290 _dl_reloc_bad_type (map, r_type, 0);
291 break;
296 static inline void
297 __attribute__ ((always_inline))
298 elf_machine_rela_relative (ElfW(Addr) l_addr,
299 const ElfW(Rela) *reloc,
300 void *const reloc_addr_arg)
302 ElfW(Addr) *const reloc_addr = reloc_addr_arg;
303 *reloc_addr = l_addr + reloc->r_addend;
306 static inline void
307 __attribute__ ((always_inline))
308 elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
309 ElfW(Addr) l_addr,
310 const ElfW(Rela) *reloc,
311 int skip_ifunc)
313 ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
314 const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
315 /* Check for unexpected PLT reloc type. */
316 if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
318 if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
320 /* Check the symbol table for variant PCS symbols. */
321 const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
322 const ElfW (Sym) *symtab =
323 (const void *)D_PTR (map, l_info[DT_SYMTAB]);
324 const ElfW (Sym) *sym = &symtab[symndx];
325 if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
327 /* Avoid lazy resolution of variant PCS symbols. */
328 const struct r_found_version *version = NULL;
329 if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
331 const ElfW (Half) *vernum =
332 (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
333 version = &map->l_versions[vernum[symndx] & 0x7fff];
335 elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
336 skip_ifunc);
337 return;
341 if (map->l_mach.plt == 0)
342 *reloc_addr += l_addr;
343 else
344 *reloc_addr = map->l_mach.plt;
346 else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
348 const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
349 const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
350 const ElfW (Sym) *sym = &symtab[symndx];
351 const struct r_found_version *version = NULL;
353 if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
355 const ElfW (Half) *vernum =
356 (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
357 version = &map->l_versions[vernum[symndx] & 0x7fff];
360 /* Always initialize TLS descriptors completely, because lazy
361 initialization requires synchronization at every TLS access. */
362 elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
363 skip_ifunc);
365 else if (__glibc_unlikely (r_type == AARCH64_R(IRELATIVE)))
367 ElfW(Addr) value = map->l_addr + reloc->r_addend;
368 if (__glibc_likely (!skip_ifunc))
369 value = elf_ifunc_invoke (value);
370 *reloc_addr = value;
372 else
373 _dl_reloc_bad_type (map, r_type, 1);
376 #endif