]>
Commit | Line | Data |
---|---|---|
c9cf6dde | 1 | /* Machine-dependent ELF dynamic relocation inline functions. x86-64 version. |
d063d164 | 2 | Copyright (C) 2001-2006, 2008-2010, 2011 Free Software Foundation, Inc. |
c9cf6dde AJ |
3 | This file is part of the GNU C Library. |
4 | Contributed by Andreas Jaeger <aj@suse.de>. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Lesser General Public | |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
10 | ||
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Lesser General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Lesser General Public | |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
20 | ||
21 | #ifndef dl_machine_h | |
22 | #define dl_machine_h | |
23 | ||
24 | #define ELF_MACHINE_NAME "x86_64" | |
25 | ||
26 | #include <sys/param.h> | |
2b1c0eea | 27 | #include <sysdep.h> |
b177ed2b | 28 | #include <tls.h> |
c9ff0187 | 29 | #include <dl-tlsdesc.h> |
c9cf6dde AJ |
30 | |
31 | /* Return nonzero iff ELF header is compatible with the running host. */ | |
32 | static inline int __attribute__ ((unused)) | |
33 | elf_machine_matches_host (const Elf64_Ehdr *ehdr) | |
34 | { | |
35 | return ehdr->e_machine == EM_X86_64; | |
36 | } | |
37 | ||
38 | ||
39 | /* Return the link-time address of _DYNAMIC. Conveniently, this is the | |
40 | first element of the GOT. This must be inlined in a function which | |
41 | uses global data. */ | |
42 | static inline Elf64_Addr __attribute__ ((unused)) | |
43 | elf_machine_dynamic (void) | |
44 | { | |
6c2b2a19 AJ |
45 | Elf64_Addr addr; |
46 | ||
47 | /* This works because we have our GOT address available in the small PIC | |
48 | model. */ | |
49 | addr = (Elf64_Addr) &_DYNAMIC; | |
c9cf6dde | 50 | |
c9cf6dde AJ |
51 | return addr; |
52 | } | |
53 | ||
54 | ||
55 | /* Return the run-time load address of the shared object. */ | |
56 | static inline Elf64_Addr __attribute__ ((unused)) | |
57 | elf_machine_load_address (void) | |
58 | { | |
943525d0 | 59 | Elf64_Addr addr; |
c9cf6dde | 60 | |
6c2b2a19 AJ |
61 | /* The easy way is just the same as on x86: |
62 | leaq _dl_start, %0 | |
63 | leaq _dl_start(%%rip), %1 | |
64 | subq %0, %1 | |
65 | but this does not work with binutils since we then have | |
66 | a R_X86_64_32S relocation in a shared lib. | |
67 | ||
68 | Instead we store the address of _dl_start in the data section | |
69 | and compare it with the current value that we can get via | |
943525d0 UD |
70 | an RIP relative addressing mode. Note that this is the address |
71 | of _dl_start before any relocation performed at runtime. In case | |
72 | the binary is prelinked the resulting "address" is actually a | |
73 | load offset which is zero if the binary was loaded at the address | |
74 | it is prelinked for. */ | |
75 | ||
76 | asm ("leaq _dl_start(%%rip), %0\n\t" | |
77 | "subq 1f(%%rip), %0\n\t" | |
21c03dbf | 78 | ".section\t.data.rel.ro\n" |
e9060347 | 79 | "1:\t.quad _dl_start\n\t" |
6c2b2a19 | 80 | ".previous\n\t" |
943525d0 | 81 | : "=r" (addr) : : "cc"); |
6c2b2a19 | 82 | |
c9cf6dde AJ |
83 | return addr; |
84 | } | |
85 | ||
86 | /* Set up the loaded object described by L so its unrelocated PLT | |
87 | entries will jump to the on-demand fixup code in dl-runtime.c. */ | |
88 | ||
50441a98 | 89 | static inline int __attribute__ ((unused, always_inline)) |
c9cf6dde AJ |
90 | elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) |
91 | { | |
92 | Elf64_Addr *got; | |
78df0fcb AJ |
93 | extern void _dl_runtime_resolve (Elf64_Word) attribute_hidden; |
94 | extern void _dl_runtime_profile (Elf64_Word) attribute_hidden; | |
c9cf6dde AJ |
95 | |
96 | if (l->l_info[DT_JMPREL] && lazy) | |
97 | { | |
98 | /* The GOT entries for functions in the PLT have not yet been filled | |
99 | in. Their initial contents will arrange when called to push an | |
100 | offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1], | |
101 | and then jump to _GLOBAL_OFFSET_TABLE[2]. */ | |
102 | got = (Elf64_Addr *) D_PTR (l, l_info[DT_PLTGOT]); | |
32e6df36 UD |
103 | /* If a library is prelinked but we have to relocate anyway, |
104 | we have to be able to undo the prelinking of .got.plt. | |
105 | The prelinker saved us here address of .plt + 0x16. */ | |
106 | if (got[1]) | |
107 | { | |
108 | l->l_mach.plt = got[1] + l->l_addr; | |
109 | l->l_mach.gotplt = (Elf64_Addr) &got[3]; | |
110 | } | |
c9cf6dde AJ |
111 | got[1] = (Elf64_Addr) l; /* Identify this shared object. */ |
112 | ||
113 | /* The got[2] entry contains the address of a function which gets | |
114 | called to get the address of a so far unresolved function and | |
115 | jump to it. The profiling extension of the dynamic linker allows | |
116 | to intercept the calls to collect information. In this case we | |
117 | don't store the address in the GOT so that all future calls also | |
118 | end in this function. */ | |
119 | if (__builtin_expect (profile, 0)) | |
120 | { | |
121 | got[2] = (Elf64_Addr) &_dl_runtime_profile; | |
122 | ||
9dcafc55 UD |
123 | if (GLRO(dl_profile) != NULL |
124 | && _dl_name_match_p (GLRO(dl_profile), l)) | |
c9cf6dde AJ |
125 | /* This is the object we are looking for. Say that we really |
126 | want profiling and the timers are started. */ | |
5688da55 | 127 | GL(dl_profile_map) = l; |
c9cf6dde AJ |
128 | } |
129 | else | |
130 | /* This function will get called to fix up the GOT entry indicated by | |
131 | the offset on the stack, and then jump to the resolved address. */ | |
132 | got[2] = (Elf64_Addr) &_dl_runtime_resolve; | |
133 | } | |
134 | ||
c9ff0187 UD |
135 | if (l->l_info[ADDRIDX (DT_TLSDESC_GOT)] && lazy) |
136 | *(Elf64_Addr*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_GOT)]) + l->l_addr) | |
137 | = (Elf64_Addr) &_dl_tlsdesc_resolve_rela; | |
138 | ||
c9cf6dde AJ |
139 | return lazy; |
140 | } | |
141 | ||
c9cf6dde AJ |
142 | /* Initial entry point code for the dynamic linker. |
143 | The C function `_dl_start' is the real entry point; | |
144 | its return value is the user program's entry point. */ | |
145 | #define RTLD_START asm ("\n\ | |
146 | .text\n\ | |
147 | .align 16\n\ | |
148 | .globl _start\n\ | |
149 | .globl _dl_start_user\n\ | |
150 | _start:\n\ | |
151 | movq %rsp, %rdi\n\ | |
152 | call _dl_start\n\ | |
153 | _dl_start_user:\n\ | |
154 | # Save the user entry point address in %r12.\n\ | |
155 | movq %rax, %r12\n\ | |
c9cf6dde AJ |
156 | # See if we were run as a command with the executable file\n\ |
157 | # name as an extra leading argument.\n\ | |
217ed70e | 158 | movl _dl_skip_args(%rip), %eax\n\ |
c9cf6dde AJ |
159 | # Pop the original argument count.\n\ |
160 | popq %rdx\n\ | |
161 | # Adjust the stack pointer to skip _dl_skip_args words.\n\ | |
162 | leaq (%rsp,%rax,8), %rsp\n\ | |
163 | # Subtract _dl_skip_args from argc.\n\ | |
164 | subl %eax, %edx\n\ | |
165 | # Push argc back on the stack.\n\ | |
166 | pushq %rdx\n\ | |
167 | # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\ | |
168 | # argc -> rsi\n\ | |
169 | movq %rdx, %rsi\n\ | |
be184b1d UD |
170 | # Save %rsp value in %r13.\n\ |
171 | movq %rsp, %r13\n\ | |
172 | # And align stack for the _dl_init_internal call. \n\ | |
173 | andq $-16, %rsp\n\ | |
c9cf6dde | 174 | # _dl_loaded -> rdi\n\ |
217ed70e | 175 | movq _rtld_local(%rip), %rdi\n\ |
c9cf6dde | 176 | # env -> rcx\n\ |
be184b1d | 177 | leaq 16(%r13,%rdx,8), %rcx\n\ |
c9cf6dde | 178 | # argv -> rdx\n\ |
be184b1d UD |
179 | leaq 8(%r13), %rdx\n\ |
180 | # Clear %rbp to mark outermost frame obviously even for constructors.\n\ | |
ee618985 | 181 | xorl %ebp, %ebp\n\ |
c9cf6dde | 182 | # Call the function to run the initializers.\n\ |
7969407a | 183 | call _dl_init_internal@PLT\n\ |
c9cf6dde | 184 | # Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\ |
217ed70e | 185 | leaq _dl_fini(%rip), %rdx\n\ |
be184b1d UD |
186 | # And make sure %rsp points to argc stored on the stack.\n\ |
187 | movq %r13, %rsp\n\ | |
c9cf6dde AJ |
188 | # Jump to the user's entry point.\n\ |
189 | jmp *%r12\n\ | |
190 | .previous\n\ | |
191 | "); | |
192 | ||
8323008c RM |
193 | /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or |
194 | TLS variable, so undefined references should not be allowed to | |
195 | define the value. | |
c9cf6dde AJ |
196 | ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one |
197 | of the main executable's symbols, as for a COPY reloc. */ | |
d063d164 | 198 | #define elf_machine_type_class(type) \ |
82c02215 RM |
199 | ((((type) == R_X86_64_JUMP_SLOT \ |
200 | || (type) == R_X86_64_DTPMOD64 \ | |
c9ff0187 UD |
201 | || (type) == R_X86_64_DTPOFF64 \ |
202 | || (type) == R_X86_64_TPOFF64 \ | |
203 | || (type) == R_X86_64_TLSDESC) \ | |
82c02215 | 204 | * ELF_RTYPE_CLASS_PLT) \ |
c9cf6dde AJ |
205 | | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY)) |
206 | ||
207 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ | |
208 | #define ELF_MACHINE_JMP_SLOT R_X86_64_JUMP_SLOT | |
209 | ||
210 | /* The x86-64 never uses Elf64_Rel relocations. */ | |
211 | #define ELF_MACHINE_NO_REL 1 | |
212 | ||
213 | /* We define an initialization functions. This is called very early in | |
214 | _dl_sysdep_start. */ | |
215 | #define DL_PLATFORM_INIT dl_platform_init () | |
216 | ||
c9cf6dde AJ |
217 | static inline void __attribute__ ((unused)) |
218 | dl_platform_init (void) | |
219 | { | |
afdca0f2 | 220 | if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0') |
c9cf6dde | 221 | /* Avoid an empty string which would disturb us. */ |
afdca0f2 | 222 | GLRO(dl_platform) = NULL; |
c9cf6dde AJ |
223 | } |
224 | ||
225 | static inline Elf64_Addr | |
226 | elf_machine_fixup_plt (struct link_map *map, lookup_t t, | |
227 | const Elf64_Rela *reloc, | |
228 | Elf64_Addr *reloc_addr, Elf64_Addr value) | |
229 | { | |
230 | return *reloc_addr = value; | |
231 | } | |
232 | ||
233 | /* Return the final value of a plt relocation. On x86-64 the | |
234 | JUMP_SLOT relocation ignores the addend. */ | |
235 | static inline Elf64_Addr | |
236 | elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, | |
237 | Elf64_Addr value) | |
238 | { | |
239 | return value; | |
240 | } | |
241 | ||
9dcafc55 UD |
242 | |
243 | /* Names of the architecture-specific auditing callback functions. */ | |
244 | #define ARCH_LA_PLTENTER x86_64_gnu_pltenter | |
245 | #define ARCH_LA_PLTEXIT x86_64_gnu_pltexit | |
246 | ||
c9cf6dde AJ |
247 | #endif /* !dl_machine_h */ |
248 | ||
9dcafc55 | 249 | #ifdef RESOLVE_MAP |
c9cf6dde AJ |
250 | |
251 | /* Perform the relocation specified by RELOC and SYM (which is fully resolved). | |
252 | MAP is the object containing the reloc. */ | |
253 | ||
7090d3ca AJ |
254 | auto inline void |
255 | __attribute__ ((always_inline)) | |
c9cf6dde | 256 | elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, |
87d254a7 AO |
257 | const Elf64_Sym *sym, const struct r_found_version *version, |
258 | void *const reloc_addr_arg) | |
c9cf6dde | 259 | { |
87d254a7 | 260 | Elf64_Addr *const reloc_addr = reloc_addr_arg; |
c9cf6dde AJ |
261 | const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info); |
262 | ||
e7f110cd | 263 | # if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC |
c9cf6dde AJ |
264 | if (__builtin_expect (r_type == R_X86_64_RELATIVE, 0)) |
265 | { | |
e7f110cd | 266 | # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC |
c9cf6dde AJ |
267 | /* This is defined in rtld.c, but nowhere in the static libc.a; |
268 | make the reference weak so static programs can still link. | |
269 | This declaration cannot be done when compiling rtld.c | |
270 | (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the | |
271 | common defn for _dl_rtld_map, which is incompatible with a | |
272 | weak decl in the same file. */ | |
e7f110cd | 273 | # ifndef SHARED |
5688da55 | 274 | weak_extern (GL(dl_rtld_map)); |
e7f110cd | 275 | # endif |
5688da55 | 276 | if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */ |
e7f110cd | 277 | # endif |
c9cf6dde AJ |
278 | *reloc_addr = map->l_addr + reloc->r_addend; |
279 | } | |
280 | else | |
e7f110cd | 281 | # endif |
c9cf6dde AJ |
282 | if (__builtin_expect (r_type == R_X86_64_NONE, 0)) |
283 | return; | |
284 | else | |
285 | { | |
e7f110cd | 286 | # ifndef RTLD_BOOTSTRAP |
c9cf6dde | 287 | const Elf64_Sym *const refsym = sym; |
e7f110cd | 288 | # endif |
8323008c | 289 | struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); |
5bbfc1ea RM |
290 | Elf64_Addr value = (sym == NULL ? 0 |
291 | : (Elf64_Addr) sym_map->l_addr + sym->st_value); | |
c9cf6dde | 292 | |
e7f110cd UD |
293 | if (sym != NULL |
294 | && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, | |
fd96f062 UD |
295 | 0) |
296 | && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)) | |
e7f110cd UD |
297 | value = ((Elf64_Addr (*) (void)) value) (); |
298 | ||
c9cf6dde AJ |
299 | switch (r_type) |
300 | { | |
301 | case R_X86_64_GLOB_DAT: | |
302 | case R_X86_64_JUMP_SLOT: | |
303 | *reloc_addr = value + reloc->r_addend; | |
304 | break; | |
8323008c | 305 | |
e7f110cd | 306 | # ifndef RESOLVE_CONFLICT_FIND_MAP |
8323008c | 307 | case R_X86_64_DTPMOD64: |
e7f110cd | 308 | # ifdef RTLD_BOOTSTRAP |
8323008c RM |
309 | /* During startup the dynamic linker is always the module |
310 | with index 1. | |
311 | XXX If this relocation is necessary move before RESOLVE | |
312 | call. */ | |
313 | *reloc_addr = 1; | |
e7f110cd | 314 | # else |
8323008c RM |
315 | /* Get the information from the link map returned by the |
316 | resolve function. */ | |
317 | if (sym_map != NULL) | |
318 | *reloc_addr = sym_map->l_tls_modid; | |
e7f110cd | 319 | # endif |
8323008c RM |
320 | break; |
321 | case R_X86_64_DTPOFF64: | |
e7f110cd | 322 | # ifndef RTLD_BOOTSTRAP |
8323008c RM |
323 | /* During relocation all TLS symbols are defined and used. |
324 | Therefore the offset is already correct. */ | |
325 | if (sym != NULL) | |
326 | *reloc_addr = sym->st_value + reloc->r_addend; | |
e7f110cd | 327 | # endif |
8323008c | 328 | break; |
c9ff0187 UD |
329 | case R_X86_64_TLSDESC: |
330 | { | |
331 | struct tlsdesc volatile *td = | |
332 | (struct tlsdesc volatile *)reloc_addr; | |
333 | ||
e7f110cd | 334 | # ifndef RTLD_BOOTSTRAP |
c9ff0187 UD |
335 | if (! sym) |
336 | { | |
337 | td->arg = (void*)reloc->r_addend; | |
338 | td->entry = _dl_tlsdesc_undefweak; | |
339 | } | |
340 | else | |
e7f110cd | 341 | # endif |
c9ff0187 | 342 | { |
e7f110cd UD |
343 | # ifndef RTLD_BOOTSTRAP |
344 | # ifndef SHARED | |
c9ff0187 | 345 | CHECK_STATIC_TLS (map, sym_map); |
e7f110cd | 346 | # else |
c9ff0187 UD |
347 | if (!TRY_STATIC_TLS (map, sym_map)) |
348 | { | |
349 | td->arg = _dl_make_tlsdesc_dynamic | |
350 | (sym_map, sym->st_value + reloc->r_addend); | |
351 | td->entry = _dl_tlsdesc_dynamic; | |
352 | } | |
353 | else | |
e7f110cd | 354 | # endif |
c9ff0187 | 355 | # endif |
c9ff0187 UD |
356 | { |
357 | td->arg = (void*)(sym->st_value - sym_map->l_tls_offset | |
358 | + reloc->r_addend); | |
359 | td->entry = _dl_tlsdesc_return; | |
360 | } | |
361 | } | |
362 | break; | |
363 | } | |
8323008c RM |
364 | case R_X86_64_TPOFF64: |
365 | /* The offset is negative, forward from the thread pointer. */ | |
e7f110cd | 366 | # ifndef RTLD_BOOTSTRAP |
8323008c | 367 | if (sym != NULL) |
e7f110cd | 368 | # endif |
2430d57a | 369 | { |
e7f110cd | 370 | # ifndef RTLD_BOOTSTRAP |
eb775e67 | 371 | CHECK_STATIC_TLS (map, sym_map); |
e7f110cd | 372 | # endif |
2430d57a RM |
373 | /* We know the offset of the object the symbol is contained in. |
374 | It is a negative value which will be added to the | |
375 | thread pointer. */ | |
376 | *reloc_addr = (sym->st_value + reloc->r_addend | |
377 | - sym_map->l_tls_offset); | |
2430d57a | 378 | } |
8323008c | 379 | break; |
e7f110cd | 380 | # endif |
8323008c | 381 | |
e7f110cd | 382 | # ifndef RTLD_BOOTSTRAP |
c9cf6dde AJ |
383 | case R_X86_64_64: |
384 | *reloc_addr = value + reloc->r_addend; | |
385 | break; | |
386 | case R_X86_64_32: | |
e7f110cd UD |
387 | value += reloc->r_addend; |
388 | *(unsigned int *) reloc_addr = value; | |
389 | ||
390 | const char *fmt; | |
391 | if (__builtin_expect (value > UINT_MAX, 0)) | |
6c2b2a19 AJ |
392 | { |
393 | const char *strtab; | |
394 | ||
e7f110cd UD |
395 | fmt = "\ |
396 | %s: Symbol `%s' causes overflow in R_X86_64_32 relocation\n"; | |
6cc8844f | 397 | # ifndef RESOLVE_CONFLICT_FIND_MAP |
e7f110cd | 398 | print_err: |
6cc8844f | 399 | # endif |
6c2b2a19 AJ |
400 | strtab = (const char *) D_PTR (map, l_info[DT_STRTAB]); |
401 | ||
e7f110cd | 402 | _dl_error_printf (fmt, |
6c2b2a19 AJ |
403 | rtld_progname ?: "<program name unknown>", |
404 | strtab + refsym->st_name); | |
405 | } | |
c9cf6dde | 406 | break; |
e7f110cd | 407 | # ifndef RESOLVE_CONFLICT_FIND_MAP |
8e27f45e | 408 | /* Not needed for dl-conflict.c. */ |
c9cf6dde | 409 | case R_X86_64_PC32: |
e7f110cd UD |
410 | value += reloc->r_addend - (Elf64_Addr) reloc_addr; |
411 | *(unsigned int *) reloc_addr = value; | |
e39acb1f | 412 | if (__builtin_expect (value != (int) value, 0)) |
6c2b2a19 | 413 | { |
e7f110cd UD |
414 | fmt = "\ |
415 | %s: Symbol `%s' causes overflow in R_X86_64_PC32 relocation\n"; | |
416 | goto print_err; | |
6c2b2a19 | 417 | } |
c9cf6dde AJ |
418 | break; |
419 | case R_X86_64_COPY: | |
420 | if (sym == NULL) | |
421 | /* This can happen in trace mode if an object could not be | |
422 | found. */ | |
423 | break; | |
e7f110cd UD |
424 | memcpy (reloc_addr_arg, (void *) value, |
425 | MIN (sym->st_size, refsym->st_size)); | |
c9cf6dde AJ |
426 | if (__builtin_expect (sym->st_size > refsym->st_size, 0) |
427 | || (__builtin_expect (sym->st_size < refsym->st_size, 0) | |
afdca0f2 | 428 | && GLRO(dl_verbose))) |
c9cf6dde | 429 | { |
e7f110cd UD |
430 | fmt = "\ |
431 | %s: Symbol `%s' has different size in shared object, consider re-linking\n"; | |
432 | goto print_err; | |
c9cf6dde | 433 | } |
c9cf6dde | 434 | break; |
e7f110cd | 435 | # endif |
74414708 UD |
436 | case R_X86_64_IRELATIVE: |
437 | value = map->l_addr + reloc->r_addend; | |
438 | value = ((Elf64_Addr (*) (void)) value) (); | |
439 | *reloc_addr = value; | |
440 | break; | |
c9cf6dde AJ |
441 | default: |
442 | _dl_reloc_bad_type (map, r_type, 0); | |
443 | break; | |
e7f110cd | 444 | # endif |
c9cf6dde | 445 | } |
c9cf6dde AJ |
446 | } |
447 | } | |
448 | ||
7090d3ca AJ |
449 | auto inline void |
450 | __attribute ((always_inline)) | |
c9cf6dde | 451 | elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, |
87d254a7 | 452 | void *const reloc_addr_arg) |
c9cf6dde | 453 | { |
87d254a7 | 454 | Elf64_Addr *const reloc_addr = reloc_addr_arg; |
c9cf6dde AJ |
455 | assert (ELF64_R_TYPE (reloc->r_info) == R_X86_64_RELATIVE); |
456 | *reloc_addr = l_addr + reloc->r_addend; | |
457 | } | |
458 | ||
7090d3ca AJ |
459 | auto inline void |
460 | __attribute ((always_inline)) | |
c9cf6dde AJ |
461 | elf_machine_lazy_rel (struct link_map *map, |
462 | Elf64_Addr l_addr, const Elf64_Rela *reloc) | |
463 | { | |
464 | Elf64_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset); | |
465 | const unsigned long int r_type = ELF64_R_TYPE (reloc->r_info); | |
466 | ||
467 | /* Check for unexpected PLT reloc type. */ | |
468 | if (__builtin_expect (r_type == R_X86_64_JUMP_SLOT, 1)) | |
32e6df36 UD |
469 | { |
470 | if (__builtin_expect (map->l_mach.plt, 0) == 0) | |
471 | *reloc_addr += l_addr; | |
472 | else | |
473 | *reloc_addr = | |
474 | map->l_mach.plt | |
475 | + (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 2; | |
476 | } | |
c9ff0187 UD |
477 | else if (__builtin_expect (r_type == R_X86_64_TLSDESC, 1)) |
478 | { | |
479 | struct tlsdesc volatile * __attribute__((__unused__)) td = | |
480 | (struct tlsdesc volatile *)reloc_addr; | |
481 | ||
482 | td->arg = (void*)reloc; | |
483 | td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)]) | |
484 | + map->l_addr); | |
485 | } | |
74414708 UD |
486 | else if (__builtin_expect (r_type == R_X86_64_IRELATIVE, 0)) |
487 | { | |
488 | Elf64_Addr value = map->l_addr + reloc->r_addend; | |
489 | value = ((Elf64_Addr (*) (void)) value) (); | |
490 | *reloc_addr = value; | |
491 | } | |
c9cf6dde AJ |
492 | else |
493 | _dl_reloc_bad_type (map, r_type, 1); | |
494 | } | |
495 | ||
9dcafc55 | 496 | #endif /* RESOLVE_MAP */ |