1 /* x86_64 ELF shared library loader suppport
3 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
4 * David Engel, Hongjiu Lu and Mitch D'Souza
5 * Copyright (C) 2001-2004 Erik Andersen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. The name of the above contributors may not be
15 * used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* Program to load an ELF binary on a linux system, and run it.
34 References to symbols in sharable libraries can be resolved by either
35 an ELF sharable library or a linux style of shared library. */
37 extern int _dl_linux_resolve(void);
40 _dl_linux_resolver(struct elf_resolve
*tpnt
, int reloc_entry
)
42 ELF_RELOC
*this_reloc
;
49 ElfW(Addr
) instr_addr
;
52 rel_addr
= (char *)tpnt
->dynamic_info
[DT_JMPREL
];
53 this_reloc
= (ELF_RELOC
*)(rel_addr
+ reloc_entry
);
54 symtab_index
= ELF_R_SYM(this_reloc
->r_info
);
56 symtab
= (ElfW(Sym
) *)tpnt
->dynamic_info
[DT_SYMTAB
];
57 strtab
= (char *)tpnt
->dynamic_info
[DT_STRTAB
];
58 symname
= strtab
+ symtab
[symtab_index
].st_name
;
60 /* Address of the jump instruction to fix up. */
61 instr_addr
= (this_reloc
->r_offset
+ tpnt
->loadaddr
);
62 got_addr
= (char **)instr_addr
;
64 /* Get the address of the GOT entry. */
65 new_addr
= _dl_find_hash(symname
, &_dl_loaded_modules
->symbol_scope
, tpnt
, ELF_RTYPE_CLASS_PLT
, NULL
);
66 if (unlikely(!new_addr
)) {
67 _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname
, symname
);
71 #if defined (__SUPPORT_LD_DEBUG__)
72 if ((unsigned long)got_addr
< 0x40000000) {
73 if (_dl_debug_bindings
) {
74 _dl_dprintf(_dl_debug_file
, "\nresolve function: %s", symname
);
76 _dl_dprintf(_dl_debug_file
,
77 "\tpatched: %x ==> %x @ %x\n",
78 *got_addr
, new_addr
, got_addr
);
81 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
/= 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 "
131 } else if (unlikely(res
> 0)) {
132 _dl_dprintf(2, "can't resolve symbol\n");
141 _dl_do_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
142 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
147 #if defined USE_TLS && USE_TLS
148 struct elf_resolve
*tls_tpnt
;
150 struct symbol_ref sym_ref
;
151 ElfW(Addr
) *reloc_addr
;
152 ElfW(Addr
) symbol_addr
;
153 #if defined (__SUPPORT_LD_DEBUG__)
157 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ (unsigned long)rpnt
->r_offset
);
158 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
159 symtab_index
= ELF_R_SYM(rpnt
->r_info
);
160 sym_ref
.sym
= &symtab
[symtab_index
];
163 symname
= strtab
+ sym_ref
.sym
->st_name
;
166 symbol_addr
= (ElfW(Addr
))_dl_find_hash(symname
, scope
, tpnt
,
167 elf_machine_type_class(reloc_type
), &sym_ref
);
169 * We want to allow undefined references to weak symbols - this
170 * might have been intentional. We should not be linking local
171 * symbols here, so all bases should be covered.
173 if (unlikely(!symbol_addr
&& (ELF_ST_TYPE(sym_ref
.sym
->st_info
) != STT_TLS
)
174 && (ELF_ST_BIND(sym_ref
.sym
->st_info
) != STB_WEAK
))) {
175 /* This may be non-fatal if called from dlopen. */
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
;
186 /* Relocs against STN_UNDEF are usually treated as using a
187 * symbol value of zero, and using the module containing the
189 symbol_addr
= sym_ref
.sym
->st_value
;
190 #if defined USE_TLS && USE_TLS
195 #if defined (__SUPPORT_LD_DEBUG__)
196 old_val
= *reloc_addr
;
199 switch (reloc_type
) {
204 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
208 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
- rpnt
->r_offset
;
211 case R_X86_64_GLOB_DAT
:
212 case R_X86_64_JUMP_SLOT
:
213 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
216 /* handled by elf_machine_relative()
217 case R_X86_64_RELATIVE:
218 *reloc_addr = map->l_addr + rpnt->r_addend;
221 #if defined USE_TLS && USE_TLS
222 case R_X86_64_DTPMOD64
:
223 *reloc_addr
= tls_tpnt
->l_tls_modid
;
225 case R_X86_64_DTPOFF64
:
226 /* During relocation all TLS symbols are defined and used.
227 * Therefore the offset is already correct. */
228 *reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
230 case R_X86_64_TPOFF64
:
231 /* The offset is negative, forward from the thread pointer.
232 * We know the offset of the object the symbol is contained in.
233 * It is a negative value which will be added to the
235 CHECK_STATIC_TLS ((struct link_map
*) tls_tpnt
);
236 *reloc_addr
= symbol_addr
- tls_tpnt
->l_tls_offset
+ rpnt
->r_addend
;
240 *(unsigned int *) reloc_addr
= symbol_addr
+ rpnt
->r_addend
;
241 /* XXX: should check for overflow eh ? */
246 #if defined (__SUPPORT_LD_DEBUG__)
248 _dl_dprintf(_dl_debug_file
,
249 "\t%s move %d bytes from %x to %x\n",
250 symname
, sym_ref
.sym
->st_size
,
251 symbol_addr
, reloc_addr
);
254 _dl_memcpy((char *)reloc_addr
,
256 sym_ref
.sym
->st_size
);
258 #if defined (__SUPPORT_LD_DEBUG__)
260 _dl_dprintf(_dl_debug_file
, "no symbol_addr to copy !?\n");
265 return -1; /* Calls _dl_exit(1). */
268 #if defined (__SUPPORT_LD_DEBUG__)
269 if (_dl_debug_reloc
&& _dl_debug_detail
)
270 _dl_dprintf(_dl_debug_file
, "\tpatched: %x ==> %x @ %x\n",
271 old_val
, *reloc_addr
, reloc_addr
);
278 _dl_do_lazy_reloc(struct elf_resolve
*tpnt
, struct r_scope_elem
*scope
,
279 ELF_RELOC
*rpnt
, ElfW(Sym
) *symtab
, char *strtab
)
282 ElfW(Addr
) *reloc_addr
;
283 #if defined (__SUPPORT_LD_DEBUG__)
290 reloc_addr
= (ElfW(Addr
)*)(tpnt
->loadaddr
+ rpnt
->r_offset
);
291 reloc_type
= ELF_R_TYPE(rpnt
->r_info
);
293 #if defined (__SUPPORT_LD_DEBUG__)
294 old_val
= *reloc_addr
;
297 switch (reloc_type
) {
300 case R_X86_64_JUMP_SLOT
:
301 *reloc_addr
+= (unsigned long)tpnt
->loadaddr
;
307 #if defined (__SUPPORT_LD_DEBUG__)
308 if (_dl_debug_reloc
&& _dl_debug_detail
)
309 _dl_dprintf(_dl_debug_file
, "\tpatched_lazy: %x ==> %x @ %x\n",
310 old_val
, *reloc_addr
, reloc_addr
);
317 _dl_parse_lazy_relocation_information(struct dyn_elf
*rpnt
,
318 unsigned long rel_addr
,
319 unsigned long rel_size
)
321 (void)_dl_parse(rpnt
->dyn
, NULL
, rel_addr
, rel_size
, _dl_do_lazy_reloc
);
325 _dl_parse_relocation_information(struct dyn_elf
*rpnt
,
326 struct r_scope_elem
*scope
,
327 unsigned long rel_addr
,
328 unsigned long rel_size
)
330 return _dl_parse(rpnt
->dyn
, scope
, rel_addr
, rel_size
, _dl_do_reloc
);