1 /* AARCH64 ELF shared library loader suppport
3 * Copyright (C) 2001-2004 Erik Andersen
4 * Copyright (C) 2016-2017 Waldemar Brodkorb <wbx@uclibc-ng.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. The name of the above contributors may not be
14 * used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 /* Program to load an ELF binary on a linux system, and run it.
31 References to symbols in sharable libraries can be resolved by either
32 an ELF sharable library or a linux style of shared library. */
36 #if defined(USE_TLS) && USE_TLS
38 #include "tlsdeschtab.h"
41 extern int _dl_linux_resolve(void);
43 unsigned long _dl_linux_resolver(struct elf_resolve
*tpnt
, int reloc_entry
)
45 ELF_RELOC
*this_reloc
;
52 ElfW(Addr
) instr_addr
;
55 rel_addr
= (char *)tpnt
->dynamic_info
[DT_JMPREL
];
56 this_reloc
= (ELF_RELOC
*)(rel_addr
+ reloc_entry
);
57 symtab_index
= ELF_R_SYM(this_reloc
->r_info
);
59 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
60 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
61 symname
= strtab
+ symtab
[symtab_index
].st_name
;
63 /* Address of jump instruction to fix up */
64 instr_addr
= (this_reloc
->r_offset
+ tpnt
->loadaddr
);
65 got_addr
= (char **)instr_addr
;
67 /* Get the address of the GOT entry */
68 new_addr
= _dl_find_hash(symname
, &_dl_loaded_modules
->symbol_scope
, tpnt
, ELF_RTYPE_CLASS_PLT
, NULL
);
69 if (unlikely(!new_addr
)) {
70 _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname
, symname
);
73 #if defined (__SUPPORT_LD_DEBUG__)
74 if (_dl_debug_bindings
) {
75 _dl_dprintf(_dl_debug_file
, "\nresolve function: %s", symname
);
76 if (_dl_debug_detail
) _dl_dprintf(_dl_debug_file
,
77 "\tpatched %x ==> %x @ %x", *got_addr
, new_addr
, got_addr
);
79 if (!_dl_debug_nofixups
) {
85 return (unsigned long)new_addr
;
89 _dl_parse(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
90 unsigned long rel_addr
, unsigned long rel_size
,
91 int (*reloc_fnc
) (struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
92 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
))
100 /* Parse the relocation information */
101 rpnt
= (ELF_RELOC
*)rel_addr
;
102 rel_size
= rel_size
/ sizeof(ELF_RELOC
);
104 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
105 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
107 for (i
= 0; i
< rel_size
; i
++, rpnt
++) {
110 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
112 debug_sym(symtab
, strtab
, symtab_index
);
113 debug_reloc(symtab
, strtab
, rpnt
);
115 res
= reloc_fnc(tpnt
, scope
, rpnt
, symtab
, strtab
);
120 _dl_dprintf(2, "\n%s: ", _dl_progname
);
123 _dl_dprintf(2, "symbol '%s': ",
124 strtab
+ symtab
[symtab_index
].st_name
);
126 if (unlikely(res
< 0)) {
127 int reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
128 _dl_dprintf(2, "can't handle reloc type %x\n", reloc_type
);
130 } else if (unlikely(res
> 0)) {
131 _dl_dprintf(2, "can't resolve symbol\n");
140 _dl_do_reloc (struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
141 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
146 #if defined USE_TLS && USE_TLS
147 struct elf_resolve
*tls_tpnt
= NULL
;
149 struct symbol_ref sym_ref
;
150 ElfW(Addr
) *reloc_addr
;
151 ElfW(Addr
) symbol_addr
;
152 #if defined (__SUPPORT_LD_DEBUG__)
156 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ (unsigned long)rpnt
->r_offset
);
157 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
158 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
159 sym_ref
.sym
= &symtab
[symtab_index
];
162 symname
= strtab
+ sym_ref
.sym
->st_name
;
165 symbol_addr
= (ElfW(Addr
))_dl_find_hash(symname
, scope
, tpnt
,
166 elf_machine_type_class(reloc_type
), &sym_ref
);
169 * We want to allow undefined references to weak symbols - this might
170 * have been intentional. We should not be linking local symbols
171 * here, so all bases should be covered.
173 if (unlikely (!symbol_addr
&&
174 (ELF_ST_TYPE(symtab
[symtab_index
].st_info
) != STT_TLS
) &&
175 (ELF_ST_BIND(symtab
[symtab_index
].st_info
) != STB_WEAK
))) {
178 if (_dl_trace_prelink
) {
179 _dl_debug_lookup (symname
, tpnt
, &symtab
[symtab_index
],
180 &sym_ref
, elf_machine_type_class(reloc_type
));
182 #if defined USE_TLS && USE_TLS
183 tls_tpnt
= sym_ref
.tpnt
;
187 * Relocs against STN_UNDEF are usually treated as using a
188 * symbol value of zero, and using the module containing the
191 symbol_addr
= sym_ref
.sym
->st_value
;
192 #if defined USE_TLS && USE_TLS
197 #if defined (__SUPPORT_LD_DEBUG__)
198 old_val
= *reloc_addr
;
201 switch (reloc_type
) {
204 case R_AARCH64_ABS64
: /* REL_SYMBOLIC */
205 case R_AARCH64_GLOB_DAT
: /* REL_GOT */
206 case R_AARCH64_JUMP_SLOT
: /* REL_PLT */
207 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
209 case R_AARCH64_RELATIVE
:
210 *reloc_addr
+= tpnt
->loadaddr
+ rpnt
->r_addend
;
213 _dl_memcpy((void *) reloc_addr
,
214 (void *) symbol_addr
, sym_ref
.sym
->st_size
);
216 #if defined USE_TLS && USE_TLS
217 case R_AARCH64_TLS_TPREL
:
218 CHECK_STATIC_TLS ((struct link_map
*) tls_tpnt
);
219 *reloc_addr
= (symbol_addr
+ tls_tpnt
->l_tls_offset
);
221 case R_AARCH64_TLSDESC
:
223 struct tlsdesc
volatile *td
=
224 (struct tlsdesc
volatile *)reloc_addr
;
226 CHECK_STATIC_TLS((struct link_map
*) tls_tpnt
);
228 if (!TRY_STATIC_TLS ((struct link_map
*) tls_tpnt
))
230 td
->arg
= _dl_make_tlsdesc_dynamic((struct link_map
*) tls_tpnt
, symbol_addr
);
231 td
->entry
= _dl_tlsdesc_dynamic
;
236 td
->arg
= symbol_addr
+ tls_tpnt
->l_tls_offset
;
237 td
->entry
= _dl_tlsdesc_return
;
243 return -1; /*call _dl_exit(1) */
246 #if defined (__SUPPORT_LD_DEBUG__)
247 if (_dl_debug_reloc
&& _dl_debug_detail
) {
248 _dl_dprintf(_dl_debug_file
, "\tpatched: %x ==> %x @ %x\n",
249 old_val
, *reloc_addr
, reloc_addr
);
257 _dl_do_lazy_reloc (struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
258 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
261 ElfW(Addr
) *reloc_addr
;
262 #if defined (__SUPPORT_LD_DEBUG__)
269 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ rpnt
->r_offset
);
270 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
272 #if defined (__SUPPORT_LD_DEBUG__)
273 old_val
= *reloc_addr
;
276 switch (reloc_type
) {
279 case R_AARCH64_JUMP_SLOT
:
280 *reloc_addr
+= tpnt
->loadaddr
;
283 return -1; /*call _dl_exit(1) */
286 #if defined (__SUPPORT_LD_DEBUG__)
287 if (_dl_debug_reloc
&& _dl_debug_detail
) {
288 _dl_dprintf(_dl_debug_file
, "\tpatched_lazy: %x ==> %x @ %x\n",
289 old_val
, *reloc_addr
, reloc_addr
);
296 void _dl_parse_lazy_relocation_information(struct dyn_elf
*rpnt
,
297 unsigned long rel_addr
, unsigned long rel_size
)
299 (void)_dl_parse(rpnt
->dyn
, NULL
, rel_addr
, rel_size
, _dl_do_lazy_reloc
);
302 int _dl_parse_relocation_information(struct dyn_elf
*rpnt
,
303 struct r_scope_elem
*scope
, unsigned long rel_addr
, unsigned long rel_size
)
305 return _dl_parse(rpnt
->dyn
, scope
, rel_addr
, rel_size
, _dl_do_reloc
);