]>
git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/aarch64/dl-machine.h
db3335e5ad7d406b42d5acbaa5483732501b323c
1 /* Copyright (C) 1995-2020 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/>. */
22 #define ELF_MACHINE_NAME "aarch64"
26 #include <dl-tlsdesc.h>
28 #include <cpu-features.c>
30 /* Translate a processor specific dynamic tag to the index in l_info array. */
31 #define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
33 /* Return nonzero iff ELF header is compatible with the running host. */
34 static inline int __attribute__ ((unused
))
35 elf_machine_matches_host (const ElfW(Ehdr
) *ehdr
)
37 return ehdr
->e_machine
== EM_AARCH64
;
40 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
41 first element of the GOT. */
42 static inline ElfW(Addr
) __attribute__ ((unused
))
43 elf_machine_dynamic (void)
45 extern const ElfW(Addr
) _GLOBAL_OFFSET_TABLE_
[] attribute_hidden
;
46 return _GLOBAL_OFFSET_TABLE_
[0];
49 /* Return the run-time load address of the shared object. */
51 static inline ElfW(Addr
) __attribute__ ((unused
))
52 elf_machine_load_address (void)
54 /* To figure out the load address we use the definition that for any symbol:
55 dynamic_addr(symbol) = static_addr(symbol) + load_addr
57 _DYNAMIC sysmbol is used here as its link-time address stored in
58 the special unrelocated first GOT entry. */
60 extern ElfW(Dyn
) _DYNAMIC
[] attribute_hidden
;
61 return (ElfW(Addr
)) &_DYNAMIC
- elf_machine_dynamic ();
64 /* Set up the loaded object described by L so its unrelocated PLT
65 entries will jump to the on-demand fixup code in dl-runtime.c. */
67 static inline int __attribute__ ((unused
))
68 elf_machine_runtime_setup (struct link_map
*l
, int lazy
, int profile
)
70 if (l
->l_info
[DT_JMPREL
] && lazy
)
73 extern void _dl_runtime_resolve (ElfW(Word
));
74 extern void _dl_runtime_profile (ElfW(Word
));
76 got
= (ElfW(Addr
) *) D_PTR (l
, l_info
[DT_PLTGOT
]);
79 l
->l_mach
.plt
= got
[1] + l
->l_addr
;
81 got
[1] = (ElfW(Addr
)) l
;
83 /* The got[2] entry contains the address of a function which gets
84 called to get the address of a so far unresolved function and
85 jump to it. The profiling extension of the dynamic linker allows
86 to intercept the calls to collect information. In this case we
87 don't store the address in the GOT so that all future calls also
88 end in this function. */
91 got
[2] = (ElfW(Addr
)) &_dl_runtime_profile
;
93 if (GLRO(dl_profile
) != NULL
94 && _dl_name_match_p (GLRO(dl_profile
), l
))
95 /* Say that we really want profiling and the timers are
97 GL(dl_profile_map
) = l
;
101 /* This function will get called to fix up the GOT entry
102 indicated by the offset on the stack, and then jump to
103 the resolved address. */
104 got
[2] = (ElfW(Addr
)) &_dl_runtime_resolve
;
111 /* Initial entry point for the dynamic linker. The C function
112 _dl_start is the real entry point, its return value is the user
113 program's entry point */
115 # define RTLD_START RTLD_START_1 ("x", "3", "sp")
117 # define RTLD_START RTLD_START_1 ("w", "2", "wsp")
121 #define RTLD_START_1(PTR, PTR_SIZE_LOG, PTR_SP) asm ("\
124 .type _start, %function \n\
125 .globl _dl_start_user \n\
126 .type _dl_start_user, %function \n\
128 mov " PTR "0, " PTR_SP " \n\
130 // returns user entry point in x0 \n\
133 // get the original arg count \n\
134 ldr " PTR "1, [sp] \n\
135 // get the argv address \n\
136 add " PTR "2, " PTR_SP ", #(1<<" PTR_SIZE_LOG ") \n\
137 // get _dl_skip_args to see if we were \n\
138 // invoked as an executable \n\
139 adrp x4, _dl_skip_args \n\
140 ldr w4, [x4, #:lo12:_dl_skip_args] \n\
141 // do we need to adjust argc/argv \n\
143 beq .L_done_stack_adjust \n\
144 // subtract _dl_skip_args from original arg count \n\
145 sub " PTR "1, " PTR "1, " PTR "4 \n\
146 // store adjusted argc back to stack \n\
147 str " PTR "1, [sp] \n\
148 // find the first unskipped argument \n\
149 mov " PTR "3, " PTR "2 \n\
150 add " PTR "4, " PTR "2, " PTR "4, lsl #" PTR_SIZE_LOG " \n\
151 // shuffle argv down \n\
152 1: ldr " PTR "5, [x4], #(1<<" PTR_SIZE_LOG ") \n\
153 str " PTR "5, [x3], #(1<<" PTR_SIZE_LOG ") \n\
156 // shuffle envp down \n\
157 1: ldr " PTR "5, [x4], #(1<<" PTR_SIZE_LOG ") \n\
158 str " PTR "5, [x3], #(1<<" PTR_SIZE_LOG ") \n\
161 // shuffle auxv down \n\
162 1: ldp " PTR "0, " PTR "5, [x4, #(2<<" PTR_SIZE_LOG ")]! \n\
163 stp " PTR "0, " PTR "5, [x3], #(2<<" PTR_SIZE_LOG ") \n\
166 // Update _dl_argv \n\
167 adrp x3, __GI__dl_argv \n\
168 str " PTR "2, [x3, #:lo12:__GI__dl_argv] \n\
169 .L_done_stack_adjust: \n\
171 add " PTR "3, " PTR "2, " PTR "1, lsl #" PTR_SIZE_LOG " \n\
172 add " PTR "3, " PTR "3, #(1<<" PTR_SIZE_LOG ") \n\
173 adrp x16, _rtld_local \n\
174 add " PTR "16, " PTR "16, #:lo12:_rtld_local \n\
175 ldr " PTR "0, [x16] \n\
177 // load the finalizer function \n\
178 adrp x0, _dl_fini \n\
179 add " PTR "0, " PTR "0, #:lo12:_dl_fini \n\
180 // jump to the user_s entry point \n\
184 #define elf_machine_type_class(type) \
185 ((((type) == AARCH64_R(JUMP_SLOT) \
186 || (type) == AARCH64_R(TLS_DTPMOD) \
187 || (type) == AARCH64_R(TLS_DTPREL) \
188 || (type) == AARCH64_R(TLS_TPREL) \
189 || (type) == AARCH64_R(TLSDESC)) * ELF_RTYPE_CLASS_PLT) \
190 | (((type) == AARCH64_R(COPY)) * ELF_RTYPE_CLASS_COPY) \
191 | (((type) == AARCH64_R(GLOB_DAT)) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
193 #define ELF_MACHINE_JMP_SLOT AARCH64_R(JUMP_SLOT)
195 /* AArch64 uses RELA not REL */
196 #define ELF_MACHINE_NO_REL 1
197 #define ELF_MACHINE_NO_RELA 0
199 #define DL_PLATFORM_INIT dl_platform_init ()
201 static inline void __attribute__ ((unused
))
202 dl_platform_init (void)
204 if (GLRO(dl_platform
) != NULL
&& *GLRO(dl_platform
) == '\0')
205 /* Avoid an empty string which would disturb us. */
206 GLRO(dl_platform
) = NULL
;
209 /* init_cpu_features has been called early from __libc_start_main in
210 static executable. */
211 init_cpu_features (&GLRO(dl_aarch64_cpu_features
));
216 static inline ElfW(Addr
)
217 elf_machine_fixup_plt (struct link_map
*map
, lookup_t t
,
218 const ElfW(Sym
) *refsym
, const ElfW(Sym
) *sym
,
219 const ElfW(Rela
) *reloc
,
220 ElfW(Addr
) *reloc_addr
,
223 return *reloc_addr
= value
;
226 /* Return the final value of a plt relocation. */
227 static inline ElfW(Addr
)
228 elf_machine_plt_value (struct link_map
*map
,
229 const ElfW(Rela
) *reloc
,
237 /* Names of the architecture-specific auditing callback functions. */
238 #define ARCH_LA_PLTENTER aarch64_gnu_pltenter
239 #define ARCH_LA_PLTEXIT aarch64_gnu_pltexit
244 __attribute__ ((always_inline
))
245 elf_machine_rela (struct link_map
*map
, const ElfW(Rela
) *reloc
,
246 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
247 void *const reloc_addr_arg
, int skip_ifunc
)
249 ElfW(Addr
) *const reloc_addr
= reloc_addr_arg
;
250 const unsigned int r_type
= ELFW (R_TYPE
) (reloc
->r_info
);
252 if (__builtin_expect (r_type
== AARCH64_R(RELATIVE
), 0))
253 *reloc_addr
= map
->l_addr
+ reloc
->r_addend
;
254 else if (__builtin_expect (r_type
== R_AARCH64_NONE
, 0))
258 const ElfW(Sym
) *const refsym
= sym
;
259 struct link_map
*sym_map
= RESOLVE_MAP (&sym
, version
, r_type
);
260 ElfW(Addr
) value
= SYMBOL_ADDRESS (sym_map
, sym
, true);
263 && __glibc_unlikely (ELFW(ST_TYPE
) (sym
->st_info
) == STT_GNU_IFUNC
)
264 && __glibc_likely (sym
->st_shndx
!= SHN_UNDEF
)
265 && __glibc_likely (!skip_ifunc
))
266 value
= elf_ifunc_invoke (value
);
270 case AARCH64_R(COPY
):
274 if (sym
->st_size
> refsym
->st_size
275 || (GLRO(dl_verbose
) && sym
->st_size
< refsym
->st_size
))
279 strtab
= (const void *) D_PTR (map
, l_info
[DT_STRTAB
]);
281 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
282 RTLD_PROGNAME
, strtab
+ refsym
->st_name
);
284 memcpy (reloc_addr_arg
, (void *) value
,
285 sym
->st_size
< refsym
->st_size
286 ? sym
->st_size
: refsym
->st_size
);
289 case AARCH64_R(RELATIVE
):
290 case AARCH64_R(GLOB_DAT
):
291 case AARCH64_R(JUMP_SLOT
):
292 case AARCH64_R(ABS32
):
294 case AARCH64_R(ABS64
):
296 *reloc_addr
= value
+ reloc
->r_addend
;
299 case AARCH64_R(TLSDESC
):
301 struct tlsdesc
volatile *td
=
302 (struct tlsdesc
volatile *)reloc_addr
;
303 #ifndef RTLD_BOOTSTRAP
306 td
->arg
= (void*)reloc
->r_addend
;
307 td
->entry
= _dl_tlsdesc_undefweak
;
312 #ifndef RTLD_BOOTSTRAP
314 CHECK_STATIC_TLS (map
, sym_map
);
316 if (!TRY_STATIC_TLS (map
, sym_map
))
318 td
->arg
= _dl_make_tlsdesc_dynamic
319 (sym_map
, sym
->st_value
+ reloc
->r_addend
);
320 td
->entry
= _dl_tlsdesc_dynamic
;
326 td
->arg
= (void*)(sym
->st_value
+ sym_map
->l_tls_offset
328 td
->entry
= _dl_tlsdesc_return
;
334 case AARCH64_R(TLS_DTPMOD
):
335 #ifdef RTLD_BOOTSTRAP
340 *reloc_addr
= sym_map
->l_tls_modid
;
345 case AARCH64_R(TLS_DTPREL
):
347 *reloc_addr
= sym
->st_value
+ reloc
->r_addend
;
350 case AARCH64_R(TLS_TPREL
):
353 CHECK_STATIC_TLS (map
, sym_map
);
355 sym
->st_value
+ reloc
->r_addend
+ sym_map
->l_tls_offset
;
359 case AARCH64_R(IRELATIVE
):
360 value
= map
->l_addr
+ reloc
->r_addend
;
361 if (__glibc_likely (!skip_ifunc
))
362 value
= elf_ifunc_invoke (value
);
367 _dl_reloc_bad_type (map
, r_type
, 0);
374 __attribute__ ((always_inline
))
375 elf_machine_rela_relative (ElfW(Addr
) l_addr
,
376 const ElfW(Rela
) *reloc
,
377 void *const reloc_addr_arg
)
379 ElfW(Addr
) *const reloc_addr
= reloc_addr_arg
;
380 *reloc_addr
= l_addr
+ reloc
->r_addend
;
384 __attribute__ ((always_inline
))
385 elf_machine_lazy_rel (struct link_map
*map
,
387 const ElfW(Rela
) *reloc
,
390 ElfW(Addr
) *const reloc_addr
= (void *) (l_addr
+ reloc
->r_offset
);
391 const unsigned int r_type
= ELFW (R_TYPE
) (reloc
->r_info
);
392 /* Check for unexpected PLT reloc type. */
393 if (__builtin_expect (r_type
== AARCH64_R(JUMP_SLOT
), 1))
395 if (map
->l_mach
.plt
== 0)
398 *reloc_addr
+= l_addr
;
402 if (__glibc_unlikely (map
->l_info
[DT_AARCH64 (VARIANT_PCS
)] != NULL
))
404 /* Check the symbol table for variant PCS symbols. */
405 const Elf_Symndx symndx
= ELFW (R_SYM
) (reloc
->r_info
);
406 const ElfW (Sym
) *symtab
=
407 (const void *)D_PTR (map
, l_info
[DT_SYMTAB
]);
408 const ElfW (Sym
) *sym
= &symtab
[symndx
];
409 if (__glibc_unlikely (sym
->st_other
& STO_AARCH64_VARIANT_PCS
))
411 /* Avoid lazy resolution of variant PCS symbols. */
412 const struct r_found_version
*version
= NULL
;
413 if (map
->l_info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
415 const ElfW (Half
) *vernum
=
416 (const void *)D_PTR (map
, l_info
[VERSYMIDX (DT_VERSYM
)]);
417 version
= &map
->l_versions
[vernum
[symndx
] & 0x7fff];
419 elf_machine_rela (map
, reloc
, sym
, version
, reloc_addr
,
425 *reloc_addr
= map
->l_mach
.plt
;
427 else if (__builtin_expect (r_type
== AARCH64_R(TLSDESC
), 1))
429 const Elf_Symndx symndx
= ELFW (R_SYM
) (reloc
->r_info
);
430 const ElfW (Sym
) *symtab
= (const void *)D_PTR (map
, l_info
[DT_SYMTAB
]);
431 const ElfW (Sym
) *sym
= &symtab
[symndx
];
432 const struct r_found_version
*version
= NULL
;
434 if (map
->l_info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
436 const ElfW (Half
) *vernum
=
437 (const void *)D_PTR (map
, l_info
[VERSYMIDX (DT_VERSYM
)]);
438 version
= &map
->l_versions
[vernum
[symndx
] & 0x7fff];
441 /* Always initialize TLS descriptors completely, because lazy
442 initialization requires synchronization at every TLS access. */
443 elf_machine_rela (map
, reloc
, sym
, version
, reloc_addr
, skip_ifunc
);
445 else if (__glibc_unlikely (r_type
== AARCH64_R(IRELATIVE
)))
447 ElfW(Addr
) value
= map
->l_addr
+ reloc
->r_addend
;
448 if (__glibc_likely (!skip_ifunc
))
449 value
= elf_ifunc_invoke (value
);
453 _dl_reloc_bad_type (map
, r_type
, 1);