1 /* On-demand PLT fixup for shared objects.
2 Copyright (C) 1995-2021 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
7 License as published by the Free Software Foundation; either
8 version 2.1 of the 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 #define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */
24 #include <sys/param.h>
26 #include <sysdep-cancel.h>
27 #include "dynamic-link.h"
30 #include <dl-runtime.h>
33 #if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \
35 # define PLTREL ElfW(Rela)
37 # define PLTREL ElfW(Rel)
40 /* The fixup functions might have need special attributes. If none
41 are provided define the macro as empty. */
42 #ifndef ARCH_FIXUP_ATTRIBUTE
43 # define ARCH_FIXUP_ATTRIBUTE
46 /* This function is called through a special trampoline from the PLT the
47 first time each PLT entry is called. We must perform the relocation
48 specified in the PLT of the given shared object, and return the resolved
49 function address to the trampoline, which will restart the original call
50 to that address. Future calls will bounce directly from the PLT to the
54 attribute_hidden
__attribute ((noinline
)) ARCH_FIXUP_ATTRIBUTE
56 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
57 ELF_MACHINE_RUNTIME_FIXUP_ARGS
,
59 struct link_map
*l
, ElfW(Word
) reloc_arg
)
61 const ElfW(Sym
) *const symtab
62 = (const void *) D_PTR (l
, l_info
[DT_SYMTAB
]);
63 const char *strtab
= (const void *) D_PTR (l
, l_info
[DT_STRTAB
]);
65 const uintptr_t pltgot
= (uintptr_t) D_PTR (l
, l_info
[DT_PLTGOT
]);
67 const PLTREL
*const reloc
68 = (const void *) (D_PTR (l
, l_info
[DT_JMPREL
])
69 + reloc_offset (pltgot
, reloc_arg
));
70 const ElfW(Sym
) *sym
= &symtab
[ELFW(R_SYM
) (reloc
->r_info
)];
71 const ElfW(Sym
) *refsym
= sym
;
72 void *const rel_addr
= (void *)(l
->l_addr
+ reloc
->r_offset
);
74 DL_FIXUP_VALUE_TYPE value
;
76 /* Sanity check that we're really looking at a PLT relocation. */
77 assert (ELFW(R_TYPE
)(reloc
->r_info
) == ELF_MACHINE_JMP_SLOT
);
79 /* Look up the target symbol. If the normal lookup rules are not
80 used don't look in the global scope. */
81 if (__builtin_expect (ELFW(ST_VISIBILITY
) (sym
->st_other
), 0) == 0)
83 const struct r_found_version
*version
= NULL
;
85 if (l
->l_info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
87 const ElfW(Half
) *vernum
=
88 (const void *) D_PTR (l
, l_info
[VERSYMIDX (DT_VERSYM
)]);
89 ElfW(Half
) ndx
= vernum
[ELFW(R_SYM
) (reloc
->r_info
)] & 0x7fff;
90 version
= &l
->l_versions
[ndx
];
91 if (version
->hash
== 0)
95 /* We need to keep the scope around so do some locking. This is
96 not necessary for objects which cannot be unloaded or when
97 we are not using any threads (yet). */
98 int flags
= DL_LOOKUP_ADD_DEPENDENCY
;
99 if (!RTLD_SINGLE_THREAD_P
)
101 THREAD_GSCOPE_SET_FLAG ();
102 flags
|= DL_LOOKUP_GSCOPE_LOCK
;
105 #ifdef RTLD_ENABLE_FOREIGN_CALL
106 RTLD_ENABLE_FOREIGN_CALL
;
109 result
= _dl_lookup_symbol_x (strtab
+ sym
->st_name
, l
, &sym
, l
->l_scope
,
110 version
, ELF_RTYPE_CLASS_PLT
, flags
, NULL
);
112 /* We are done with the global scope. */
113 if (!RTLD_SINGLE_THREAD_P
)
114 THREAD_GSCOPE_RESET_FLAG ();
116 #ifdef RTLD_FINALIZE_FOREIGN_CALL
117 RTLD_FINALIZE_FOREIGN_CALL
;
120 /* Currently result contains the base load address (or link map)
121 of the object that defines sym. Now add in the symbol
123 value
= DL_FIXUP_MAKE_VALUE (result
,
124 SYMBOL_ADDRESS (result
, sym
, false));
128 /* We already found the symbol. The module (and therefore its load
129 address) is also known. */
130 value
= DL_FIXUP_MAKE_VALUE (l
, SYMBOL_ADDRESS (l
, sym
, true));
134 /* And now perhaps the relocation addend. */
135 value
= elf_machine_plt_value (l
, reloc
, value
);
138 && __builtin_expect (ELFW(ST_TYPE
) (sym
->st_info
) == STT_GNU_IFUNC
, 0))
139 value
= elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value
));
141 /* Finally, fix up the plt itself. */
142 if (__glibc_unlikely (GLRO(dl_bind_not
)))
145 return elf_machine_fixup_plt (l
, result
, refsym
, sym
, reloc
, rel_addr
, value
);
150 __attribute ((noinline
)) ARCH_FIXUP_ATTRIBUTE
152 #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
153 ELF_MACHINE_RUNTIME_FIXUP_ARGS
,
155 struct link_map
*l
, ElfW(Word
) reloc_arg
,
156 ElfW(Addr
) retaddr
, void *regs
, long int *framesizep
)
158 void (*mcount_fct
) (ElfW(Addr
), ElfW(Addr
)) = _dl_mcount
;
160 if (l
->l_reloc_result
== NULL
)
162 /* BZ #14843: ELF_DYNAMIC_RELOCATE is called before l_reloc_result
163 is allocated. We will get here if ELF_DYNAMIC_RELOCATE calls a
164 resolver function to resolve an IRELATIVE relocation and that
165 resolver calls a function that is not yet resolved (lazy). For
166 example, the resolver in x86-64 libm.so calls __get_cpu_features
167 defined in libc.so. Skip audit and resolve the external function
171 # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS
172 # ifndef ELF_MACHINE_RUNTIME_FIXUP_PARAMS
173 # error Please define ELF_MACHINE_RUNTIME_FIXUP_PARAMS.
175 ELF_MACHINE_RUNTIME_FIXUP_PARAMS
,
180 const uintptr_t pltgot
= (uintptr_t) D_PTR (l
, l_info
[DT_PLTGOT
]);
182 /* This is the address in the array where we store the result of previous
184 struct reloc_result
*reloc_result
185 = &l
->l_reloc_result
[reloc_index (pltgot
, reloc_arg
, sizeof (PLTREL
))];
187 /* CONCURRENCY NOTES:
189 Multiple threads may be calling the same PLT sequence and with
190 LD_AUDIT enabled they will be calling into _dl_profile_fixup to
191 update the reloc_result with the result of the lazy resolution.
192 The reloc_result guard variable is reloc_init, and we use
193 acquire/release loads and store to it to ensure that the results of
194 the structure are consistent with the loaded value of the guard.
195 This does not fix all of the data races that occur when two or more
196 threads read reloc_result->reloc_init with a value of zero and read
197 and write to that reloc_result concurrently. The expectation is
198 generally that while this is a data race it works because the
199 threads write the same values. Until the data races are fixed
200 there is a potential for problems to arise from these data races.
201 The reloc result updates should happen in parallel but there should
202 be an atomic RMW which does the final update to the real result
203 entry (see bug 23790).
205 The following code uses reloc_result->init set to 0 to indicate if it is
206 the first time this object is being relocated, otherwise 1 which
207 indicates the object has already been relocated.
209 Reading/Writing from/to reloc_result->reloc_init must not happen
210 before previous writes to reloc_result complete as they could
211 end-up with an incomplete struct. */
212 DL_FIXUP_VALUE_TYPE value
;
213 unsigned int init
= atomic_load_acquire (&reloc_result
->init
);
217 /* This is the first time we have to relocate this object. */
218 const ElfW(Sym
) *const symtab
219 = (const void *) D_PTR (l
, l_info
[DT_SYMTAB
]);
220 const char *strtab
= (const char *) D_PTR (l
, l_info
[DT_STRTAB
]);
222 const uintptr_t pltgot
= (uintptr_t) D_PTR (l
, l_info
[DT_PLTGOT
]);
224 const PLTREL
*const reloc
225 = (const void *) (D_PTR (l
, l_info
[DT_JMPREL
])
226 + reloc_offset (pltgot
, reloc_arg
));
227 const ElfW(Sym
) *refsym
= &symtab
[ELFW(R_SYM
) (reloc
->r_info
)];
228 const ElfW(Sym
) *defsym
= refsym
;
231 /* Sanity check that we're really looking at a PLT relocation. */
232 assert (ELFW(R_TYPE
)(reloc
->r_info
) == ELF_MACHINE_JMP_SLOT
);
234 /* Look up the target symbol. If the symbol is marked STV_PROTECTED
235 don't look in the global scope. */
236 if (__builtin_expect (ELFW(ST_VISIBILITY
) (refsym
->st_other
), 0) == 0)
238 const struct r_found_version
*version
= NULL
;
240 if (l
->l_info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
242 const ElfW(Half
) *vernum
=
243 (const void *) D_PTR (l
, l_info
[VERSYMIDX (DT_VERSYM
)]);
244 ElfW(Half
) ndx
= vernum
[ELFW(R_SYM
) (reloc
->r_info
)] & 0x7fff;
245 version
= &l
->l_versions
[ndx
];
246 if (version
->hash
== 0)
250 /* We need to keep the scope around so do some locking. This is
251 not necessary for objects which cannot be unloaded or when
252 we are not using any threads (yet). */
253 int flags
= DL_LOOKUP_ADD_DEPENDENCY
;
254 if (!RTLD_SINGLE_THREAD_P
)
256 THREAD_GSCOPE_SET_FLAG ();
257 flags
|= DL_LOOKUP_GSCOPE_LOCK
;
260 result
= _dl_lookup_symbol_x (strtab
+ refsym
->st_name
, l
,
261 &defsym
, l
->l_scope
, version
,
262 ELF_RTYPE_CLASS_PLT
, flags
, NULL
);
264 /* We are done with the global scope. */
265 if (!RTLD_SINGLE_THREAD_P
)
266 THREAD_GSCOPE_RESET_FLAG ();
268 /* Currently result contains the base load address (or link map)
269 of the object that defines sym. Now add in the symbol
271 value
= DL_FIXUP_MAKE_VALUE (result
,
272 SYMBOL_ADDRESS (result
, defsym
, false));
275 && __builtin_expect (ELFW(ST_TYPE
) (defsym
->st_info
)
276 == STT_GNU_IFUNC
, 0))
277 value
= elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value
));
281 /* We already found the symbol. The module (and therefore its load
282 address) is also known. */
283 value
= DL_FIXUP_MAKE_VALUE (l
, SYMBOL_ADDRESS (l
, refsym
, true));
285 if (__builtin_expect (ELFW(ST_TYPE
) (refsym
->st_info
)
286 == STT_GNU_IFUNC
, 0))
287 value
= elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value
));
291 /* And now perhaps the relocation addend. */
292 value
= elf_machine_plt_value (l
, reloc
, value
);
295 /* Auditing checkpoint: we have a new binding. Provide the
296 auditing libraries the possibility to change the value and
297 tell us whether further auditing is wanted. */
298 if (defsym
!= NULL
&& GLRO(dl_naudit
) > 0)
300 reloc_result
->bound
= result
;
301 /* Compute index of the symbol entry in the symbol table of
302 the DSO with the definition. */
303 reloc_result
->boundndx
= (defsym
304 - (ElfW(Sym
) *) D_PTR (result
,
307 /* Determine whether any of the two participating DSOs is
308 interested in auditing. */
309 if ((l
->l_audit_any_plt
| result
->l_audit_any_plt
) != 0)
311 unsigned int flags
= 0;
312 struct audit_ifaces
*afct
= GLRO(dl_audit
);
313 /* Synthesize a symbol record where the st_value field is
315 ElfW(Sym
) sym
= *defsym
;
316 sym
.st_value
= DL_FIXUP_VALUE_ADDR (value
);
318 /* Keep track whether there is any interest in tracing
319 the call in the lower two bits. */
320 assert (DL_NNS
* 2 <= sizeof (reloc_result
->flags
) * 8);
321 assert ((LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
) == 3);
322 reloc_result
->enterexit
= LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
;
324 const char *strtab2
= (const void *) D_PTR (result
,
327 for (unsigned int cnt
= 0; cnt
< GLRO(dl_naudit
); ++cnt
)
329 /* XXX Check whether both DSOs must request action or
331 struct auditstate
*l_state
= link_map_audit_state (l
, cnt
);
332 struct auditstate
*result_state
333 = link_map_audit_state (result
, cnt
);
334 if ((l_state
->bindflags
& LA_FLG_BINDFROM
) != 0
335 && (result_state
->bindflags
& LA_FLG_BINDTO
) != 0)
337 if (afct
->symbind
!= NULL
)
340 = afct
->symbind (&sym
, reloc_result
->boundndx
,
342 &result_state
->cookie
,
344 strtab2
+ defsym
->st_name
);
345 if (new_value
!= (uintptr_t) sym
.st_value
)
347 flags
|= LA_SYMB_ALTVALUE
;
348 sym
.st_value
= new_value
;
352 /* Remember the results for every audit library and
353 store a summary in the first two bits. */
354 reloc_result
->enterexit
355 &= flags
& (LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
);
356 reloc_result
->enterexit
357 |= ((flags
& (LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
))
361 /* If the bind flags say this auditor is not interested,
362 set the bits manually. */
363 reloc_result
->enterexit
364 |= ((LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
)
370 reloc_result
->flags
= flags
;
371 value
= DL_FIXUP_ADDR_VALUE (sym
.st_value
);
374 /* Set all bits since this symbol binding is not interesting. */
375 reloc_result
->enterexit
= (1u << DL_NNS
) - 1;
379 /* Store the result for later runs. */
380 if (__glibc_likely (! GLRO(dl_bind_not
)))
382 reloc_result
->addr
= value
;
383 /* Guarantee all previous writes complete before
384 init is updated. See CONCURRENCY NOTES earlier */
385 atomic_store_release (&reloc_result
->init
, 1);
390 value
= reloc_result
->addr
;
392 /* By default we do not call the pltexit function. */
393 long int framesize
= -1;
397 /* Auditing checkpoint: report the PLT entering and allow the
398 auditors to change the value. */
399 if (GLRO(dl_naudit
) > 0
400 /* Don't do anything if no auditor wants to intercept this call. */
401 && (reloc_result
->enterexit
& LA_SYMB_NOPLTENTER
) == 0)
403 /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been
404 initialized earlier in this function or in another thread. */
405 assert (DL_FIXUP_VALUE_CODE_ADDR (value
) != 0);
406 ElfW(Sym
) *defsym
= ((ElfW(Sym
) *) D_PTR (reloc_result
->bound
,
408 + reloc_result
->boundndx
);
410 /* Set up the sym parameter. */
411 ElfW(Sym
) sym
= *defsym
;
412 sym
.st_value
= DL_FIXUP_VALUE_ADDR (value
);
414 /* Get the symbol name. */
415 const char *strtab
= (const void *) D_PTR (reloc_result
->bound
,
417 const char *symname
= strtab
+ sym
.st_name
;
419 /* Keep track of overwritten addresses. */
420 unsigned int flags
= reloc_result
->flags
;
422 struct audit_ifaces
*afct
= GLRO(dl_audit
);
423 for (unsigned int cnt
= 0; cnt
< GLRO(dl_naudit
); ++cnt
)
425 if (afct
->ARCH_LA_PLTENTER
!= NULL
426 && (reloc_result
->enterexit
427 & (LA_SYMB_NOPLTENTER
<< (2 * (cnt
+ 1)))) == 0)
429 long int new_framesize
= -1;
430 struct auditstate
*l_state
= link_map_audit_state (l
, cnt
);
431 struct auditstate
*bound_state
432 = link_map_audit_state (reloc_result
->bound
, cnt
);
434 = afct
->ARCH_LA_PLTENTER (&sym
, reloc_result
->boundndx
,
436 &bound_state
->cookie
,
437 regs
, &flags
, symname
,
439 if (new_value
!= (uintptr_t) sym
.st_value
)
441 flags
|= LA_SYMB_ALTVALUE
;
442 sym
.st_value
= new_value
;
445 /* Remember the results for every audit library and
446 store a summary in the first two bits. */
447 reloc_result
->enterexit
448 |= ((flags
& (LA_SYMB_NOPLTENTER
| LA_SYMB_NOPLTEXIT
))
451 if ((reloc_result
->enterexit
& (LA_SYMB_NOPLTEXIT
453 == 0 && new_framesize
!= -1 && framesize
!= -2)
455 /* If this is the first call providing information,
458 framesize
= new_framesize
;
459 /* If two pltenter calls provide conflicting information,
460 use the larger value. */
461 else if (new_framesize
!= framesize
)
462 framesize
= MAX (new_framesize
, framesize
);
469 value
= DL_FIXUP_ADDR_VALUE (sym
.st_value
);
473 /* Store the frame size information. */
474 *framesizep
= framesize
;
476 (*mcount_fct
) (retaddr
, DL_FIXUP_VALUE_CODE_ADDR (value
));
487 _dl_call_pltexit (struct link_map
*l
, ElfW(Word
) reloc_arg
,
488 const void *inregs
, void *outregs
)
491 const uintptr_t pltgot
= (uintptr_t) D_PTR (l
, l_info
[DT_PLTGOT
]);
493 /* This is the address in the array where we store the result of previous
495 // XXX Maybe the bound information must be stored on the stack since
496 // XXX with bind_not a new value could have been stored in the meantime.
497 struct reloc_result
*reloc_result
=
498 &l
->l_reloc_result
[reloc_index (pltgot
, reloc_arg
, sizeof (PLTREL
))];
499 ElfW(Sym
) *defsym
= ((ElfW(Sym
) *) D_PTR (reloc_result
->bound
,
501 + reloc_result
->boundndx
);
503 /* Set up the sym parameter. */
504 ElfW(Sym
) sym
= *defsym
;
505 sym
.st_value
= DL_FIXUP_VALUE_ADDR (reloc_result
->addr
);
507 /* Get the symbol name. */
508 const char *strtab
= (const void *) D_PTR (reloc_result
->bound
,
510 const char *symname
= strtab
+ sym
.st_name
;
512 struct audit_ifaces
*afct
= GLRO(dl_audit
);
513 for (unsigned int cnt
= 0; cnt
< GLRO(dl_naudit
); ++cnt
)
515 if (afct
->ARCH_LA_PLTEXIT
!= NULL
516 && (reloc_result
->enterexit
517 & (LA_SYMB_NOPLTEXIT
>> (2 * cnt
))) == 0)
519 struct auditstate
*l_state
= link_map_audit_state (l
, cnt
);
520 struct auditstate
*bound_state
521 = link_map_audit_state (reloc_result
->bound
, cnt
);
522 afct
->ARCH_LA_PLTEXIT (&sym
, reloc_result
->boundndx
,
523 &l_state
->cookie
, &bound_state
->cookie
,
524 inregs
, outregs
, symname
);