]>
Commit | Line | Data |
---|---|---|
a6963e69 | 1 | /* Machine-dependent ELF dynamic relocation inline functions. |
cfc91acd | 2 | PowerPC64 version. |
568035b7 | 3 | Copyright 1995-2013 Free Software Foundation, Inc. |
cfc91acd RM |
4 | This file is part of the GNU C Library. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
7 | modify it under the terms of the GNU Library General Public License as | |
8 | published by the Free Software Foundation; either version 2 of the | |
9 | 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 | Library General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Library General Public | |
59ba27a6 PE |
17 | License along with the GNU C Library; see the file COPYING.LIB. If |
18 | not, see <http://www.gnu.org/licenses/>. */ | |
cfc91acd RM |
19 | |
20 | #ifndef dl_machine_h | |
21 | #define dl_machine_h | |
22 | ||
23 | #define ELF_MACHINE_NAME "powerpc64" | |
24 | ||
25 | #include <assert.h> | |
26 | #include <sys/param.h> | |
790eed83 | 27 | #include <dl-tls.h> |
590b40f7 | 28 | #include <sysdep.h> |
cfc91acd RM |
29 | |
30 | /* Translate a processor specific dynamic tag to the index | |
31 | in l_info array. */ | |
32 | #define DT_PPC64(x) (DT_PPC64_##x - DT_LOPROC + DT_NUM) | |
33 | ||
34 | /* A PowerPC64 function descriptor. The .plt (procedure linkage | |
35 | table) and .opd (official procedure descriptor) sections are | |
36 | arrays of these. */ | |
37 | typedef struct | |
38 | { | |
39 | Elf64_Addr fd_func; | |
40 | Elf64_Addr fd_toc; | |
41 | Elf64_Addr fd_aux; | |
42 | } Elf64_FuncDesc; | |
43 | ||
44 | #define ELF_MULT_MACHINES_SUPPORTED | |
45 | ||
46 | /* Return nonzero iff ELF header is compatible with the running host. */ | |
47 | static inline int | |
48 | elf_machine_matches_host (const Elf64_Ehdr *ehdr) | |
49 | { | |
50 | return ehdr->e_machine == EM_PPC64; | |
51 | } | |
52 | ||
53 | /* Return nonzero iff ELF header is compatible with the running host, | |
54 | but not this loader. */ | |
55 | static inline int | |
56 | elf_host_tolerates_machine (const Elf64_Ehdr *ehdr) | |
57 | { | |
58 | return ehdr->e_machine == EM_PPC; | |
59 | } | |
60 | ||
61 | /* Return nonzero iff ELF header is compatible with the running host, | |
62 | but not this loader. */ | |
63 | static inline int | |
64 | elf_host_tolerates_class (const Elf64_Ehdr *ehdr) | |
65 | { | |
66 | return ehdr->e_ident[EI_CLASS] == ELFCLASS32; | |
67 | } | |
68 | ||
69 | ||
70 | /* Return the run-time load address of the shared object, assuming it | |
71 | was originally linked at zero. */ | |
72 | static inline Elf64_Addr | |
73 | elf_machine_load_address (void) __attribute__ ((const)); | |
74 | ||
75 | static inline Elf64_Addr | |
76 | elf_machine_load_address (void) | |
77 | { | |
78 | Elf64_Addr ret; | |
79 | ||
80 | /* The first entry in .got (and thus the first entry in .toc) is the | |
81 | link-time TOC_base, ie. r2. So the difference between that and | |
82 | the current r2 set by the kernel is how far the shared lib has | |
83 | moved. */ | |
84 | asm ( " ld %0,-32768(2)\n" | |
85 | " subf %0,%0,2\n" | |
86 | : "=r" (ret)); | |
87 | return ret; | |
88 | } | |
89 | ||
90 | /* Return the link-time address of _DYNAMIC. */ | |
91 | static inline Elf64_Addr | |
92 | elf_machine_dynamic (void) | |
93 | { | |
94 | Elf64_Addr runtime_dynamic; | |
95 | /* It's easier to get the run-time address. */ | |
96 | asm ( " addis %0,2,_DYNAMIC@toc@ha\n" | |
97 | " addi %0,%0,_DYNAMIC@toc@l\n" | |
98 | : "=b" (runtime_dynamic)); | |
99 | /* Then subtract off the load address offset. */ | |
100 | return runtime_dynamic - elf_machine_load_address() ; | |
101 | } | |
102 | ||
103 | #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */ | |
104 | ||
105 | /* The PLT uses Elf64_Rela relocs. */ | |
106 | #define elf_machine_relplt elf_machine_rela | |
107 | ||
cfc91acd | 108 | |
ce6e047f UD |
109 | #ifdef HAVE_INLINED_SYSCALLS |
110 | /* We do not need _dl_starting_up. */ | |
111 | # define DL_STARTING_UP_DEF | |
112 | #else | |
113 | # define DL_STARTING_UP_DEF \ | |
114 | ".LC__dl_starting_up:\n" \ | |
115 | " .tc _dl_starting_up_internal[TC],_dl_starting_up_internal\n" | |
116 | #endif | |
117 | ||
cfc91acd RM |
118 | |
119 | /* Initial entry point code for the dynamic linker. The C function | |
120 | `_dl_start' is the real entry point; its return value is the user | |
121 | program's entry point. */ | |
122 | #define RTLD_START \ | |
c3d36434 | 123 | asm (".pushsection \".text\"\n" \ |
cfc91acd | 124 | " .align 2\n" \ |
590b40f7 | 125 | " .type " BODY_PREFIX "_start,@function\n" \ |
c3d36434 | 126 | " .pushsection \".opd\",\"aw\"\n" \ |
cfc91acd RM |
127 | " .align 3\n" \ |
128 | " .globl _start\n" \ | |
590b40f7 | 129 | " " ENTRY_2(_start) "\n" \ |
cfc91acd | 130 | "_start:\n" \ |
590b40f7 | 131 | " " OPD_ENT(_start) "\n" \ |
c3d36434 | 132 | " .popsection\n" \ |
590b40f7 | 133 | BODY_PREFIX "_start:\n" \ |
cfc91acd RM |
134 | /* We start with the following on the stack, from top: \ |
135 | argc (4 bytes); \ | |
136 | arguments for program (terminated by NULL); \ | |
137 | environment variables (terminated by NULL); \ | |
138 | arguments for the program loader. */ \ | |
139 | " mr 3,1\n" \ | |
140 | " li 4,0\n" \ | |
141 | " stdu 4,-128(1)\n" \ | |
142 | /* Call _dl_start with one parameter pointing at argc. */ \ | |
590b40f7 | 143 | " bl " DOT_PREFIX "_dl_start\n" \ |
cfc91acd RM |
144 | " nop\n" \ |
145 | /* Transfer control to _dl_start_user! */ \ | |
590b40f7 UD |
146 | " b " DOT_PREFIX "_dl_start_user\n" \ |
147 | ".LT__start:\n" \ | |
148 | " .long 0\n" \ | |
cfc91acd | 149 | " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \ |
590b40f7 | 150 | " .long .LT__start-" BODY_PREFIX "_start\n" \ |
cfc91acd RM |
151 | " .short .LT__start_name_end-.LT__start_name_start\n" \ |
152 | ".LT__start_name_start:\n" \ | |
153 | " .ascii \"_start\"\n" \ | |
154 | ".LT__start_name_end:\n" \ | |
155 | " .align 2\n" \ | |
590b40f7 | 156 | " " END_2(_start) "\n" \ |
cfc91acd | 157 | " .globl _dl_start_user\n" \ |
c3d36434 | 158 | " .pushsection \".opd\",\"aw\"\n" \ |
cfc91acd | 159 | "_dl_start_user:\n" \ |
590b40f7 | 160 | " " OPD_ENT(_dl_start_user) "\n" \ |
c3d36434 RM |
161 | " .popsection\n" \ |
162 | " .pushsection \".toc\",\"aw\"\n" \ | |
ce6e047f | 163 | DL_STARTING_UP_DEF \ |
37fb1dc0 AS |
164 | ".LC__rtld_local:\n" \ |
165 | " .tc _rtld_local[TC],_rtld_local\n" \ | |
ce6e047f UD |
166 | ".LC__dl_argc:\n" \ |
167 | " .tc _dl_argc[TC],_dl_argc\n" \ | |
168 | ".LC__dl_argv:\n" \ | |
169 | " .tc _dl_argv_internal[TC],_dl_argv_internal\n" \ | |
170 | ".LC__dl_fini:\n" \ | |
171 | " .tc _dl_fini[TC],_dl_fini\n" \ | |
c3d36434 | 172 | " .popsection\n" \ |
590b40f7 UD |
173 | " .type " BODY_PREFIX "_dl_start_user,@function\n" \ |
174 | " " ENTRY_2(_dl_start_user) "\n" \ | |
175 | /* Now, we do our main work of calling initialisation procedures. \ | |
176 | The ELF ABI doesn't say anything about parameters for these, \ | |
177 | so we just pass argc, argv, and the environment. \ | |
178 | Changing these is strongly discouraged (not least because argc is \ | |
179 | passed by value!). */ \ | |
180 | BODY_PREFIX "_dl_start_user:\n" \ | |
cfc91acd RM |
181 | /* the address of _start in r30. */ \ |
182 | " mr 30,3\n" \ | |
183 | /* &_dl_argc in 29, &_dl_argv in 27, and _dl_loaded in 28. */ \ | |
37fb1dc0 | 184 | " ld 28,.LC__rtld_local@toc(2)\n" \ |
590b40f7 UD |
185 | " ld 29,.LC__dl_argc@toc(2)\n" \ |
186 | " ld 27,.LC__dl_argv@toc(2)\n" \ | |
cfc91acd RM |
187 | /* _dl_init (_dl_loaded, _dl_argc, _dl_argv, _dl_argv+_dl_argc+1). */ \ |
188 | " ld 3,0(28)\n" \ | |
189 | " lwa 4,0(29)\n" \ | |
190 | " ld 5,0(27)\n" \ | |
191 | " sldi 6,4,3\n" \ | |
192 | " add 6,5,6\n" \ | |
193 | " addi 6,6,8\n" \ | |
590b40f7 | 194 | " bl " DOT_PREFIX "_dl_init\n" \ |
cfc91acd RM |
195 | " nop\n" \ |
196 | /* Now, to conform to the ELF ABI, we have to: \ | |
197 | Pass argc (actually _dl_argc) in r3; */ \ | |
198 | " lwa 3,0(29)\n" \ | |
199 | /* Pass argv (actually _dl_argv) in r4; */ \ | |
200 | " ld 4,0(27)\n" \ | |
201 | /* Pass argv+argc+1 in r5; */ \ | |
202 | " sldi 5,3,3\n" \ | |
203 | " add 6,4,5\n" \ | |
204 | " addi 5,6,8\n" \ | |
205 | /* Pass the auxilary vector in r6. This is passed to us just after \ | |
206 | _envp. */ \ | |
207 | "2: ldu 0,8(6)\n" \ | |
208 | " cmpdi 0,0\n" \ | |
209 | " bne 2b\n" \ | |
210 | " addi 6,6,8\n" \ | |
211 | /* Pass a termination function pointer (in this case _dl_fini) in \ | |
212 | r7. */ \ | |
ce6e047f | 213 | " ld 7,.LC__dl_fini@toc(2)\n" \ |
cfc91acd RM |
214 | /* Pass the stack pointer in r1 (so far so good), pointing to a NULL \ |
215 | value. This lets our startup code distinguish between a program \ | |
216 | linked statically, which linux will call with argc on top of the \ | |
217 | stack which will hopefully never be zero, and a dynamically linked \ | |
218 | program which will always have a NULL on the top of the stack. \ | |
590b40f7 | 219 | Take the opportunity to clear LR, so anyone who accidentally \ |
cfc91acd RM |
220 | returns from _start gets SEGV. Also clear the next few words of \ |
221 | the stack. */ \ | |
222 | " li 31,0\n" \ | |
223 | " std 31,0(1)\n" \ | |
224 | " mtlr 31\n" \ | |
225 | " std 31,8(1)\n" \ | |
226 | " std 31,16(1)\n" \ | |
227 | " std 31,24(1)\n" \ | |
cfc91acd | 228 | /* Now, call the start function descriptor at r30... */ \ |
590b40f7 UD |
229 | " .globl ._dl_main_dispatch\n" \ |
230 | "._dl_main_dispatch:\n" \ | |
cfc91acd RM |
231 | " ld 0,0(30)\n" \ |
232 | " ld 2,8(30)\n" \ | |
233 | " mtctr 0\n" \ | |
234 | " ld 11,16(30)\n" \ | |
235 | " bctr\n" \ | |
590b40f7 | 236 | ".LT__dl_start_user:\n" \ |
cfc91acd RM |
237 | " .long 0\n" \ |
238 | " .byte 0x00,0x0c,0x24,0x40,0x00,0x00,0x00,0x00\n" \ | |
590b40f7 | 239 | " .long .LT__dl_start_user-" BODY_PREFIX "_dl_start_user\n" \ |
cfc91acd RM |
240 | " .short .LT__dl_start_user_name_end-.LT__dl_start_user_name_start\n" \ |
241 | ".LT__dl_start_user_name_start:\n" \ | |
242 | " .ascii \"_dl_start_user\"\n" \ | |
243 | ".LT__dl_start_user_name_end:\n" \ | |
244 | " .align 2\n" \ | |
590b40f7 | 245 | " " END_2(_dl_start_user) "\n" \ |
c3d36434 | 246 | " .popsection"); |
cfc91acd | 247 | |
d2207f32 UD |
248 | /* ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to |
249 | one of the main executable's symbols, as for a COPY reloc. | |
cfc91acd | 250 | |
d2207f32 UD |
251 | To make function pointer comparisons work on most targets, the |
252 | relevant ABI states that the address of a non-local function in a | |
253 | dynamically linked executable is the address of the PLT entry for | |
254 | that function. This is quite reasonable since using the real | |
255 | function address in a non-PIC executable would typically require | |
256 | dynamic relocations in .text, something to be avoided. For such | |
257 | functions, the linker emits a SHN_UNDEF symbol in the executable | |
258 | with value equal to the PLT entry address. Normally, SHN_UNDEF | |
259 | symbols have a value of zero, so this is a clue to ld.so that it | |
260 | should treat these symbols specially. For relocations not in | |
261 | ELF_RTYPE_CLASS_PLT (eg. those on function pointers), ld.so should | |
262 | use the value of the executable SHN_UNDEF symbol, ie. the PLT entry | |
263 | address. For relocations in ELF_RTYPE_CLASS_PLT (eg. the relocs in | |
264 | the PLT itself), ld.so should use the value of the corresponding | |
265 | defined symbol in the object that defines the function, ie. the | |
266 | real function address. This complicates ld.so in that there are | |
267 | now two possible values for a given symbol, and it gets even worse | |
268 | because protected symbols need yet another set of rules. | |
cfc91acd | 269 | |
d2207f32 UD |
270 | On PowerPC64 we don't need any of this. The linker won't emit |
271 | SHN_UNDEF symbols with non-zero values. ld.so can make all | |
272 | relocations behave "normally", ie. always use the real address | |
273 | like PLT relocations. So always set ELF_RTYPE_CLASS_PLT. */ | |
afafddab | 274 | |
cfc91acd | 275 | #define elf_machine_type_class(type) \ |
d2207f32 | 276 | (ELF_RTYPE_CLASS_PLT | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY)) |
cfc91acd RM |
277 | |
278 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ | |
279 | #define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT | |
280 | ||
281 | /* The PowerPC never uses REL relocations. */ | |
282 | #define ELF_MACHINE_NO_REL 1 | |
283 | ||
284 | /* Stuff for the PLT. */ | |
285 | #define PLT_INITIAL_ENTRY_WORDS 3 | |
286 | #define GLINK_INITIAL_ENTRY_WORDS 8 | |
287 | ||
288 | #define PPC_DCBST(where) asm volatile ("dcbst 0,%0" : : "r"(where) : "memory") | |
153cf972 UD |
289 | #define PPC_DCBT(where) asm volatile ("dcbt 0,%0" : : "r"(where) : "memory") |
290 | #define PPC_DCBF(where) asm volatile ("dcbf 0,%0" : : "r"(where) : "memory") | |
cfc91acd RM |
291 | #define PPC_SYNC asm volatile ("sync" : : : "memory") |
292 | #define PPC_ISYNC asm volatile ("sync; isync" : : : "memory") | |
293 | #define PPC_ICBI(where) asm volatile ("icbi 0,%0" : : "r"(where) : "memory") | |
294 | #define PPC_DIE asm volatile ("tweq 0,0") | |
295 | /* Use this when you've modified some code, but it won't be in the | |
296 | instruction fetch queue (or when it doesn't matter if it is). */ | |
297 | #define MODIFIED_CODE_NOQUEUE(where) \ | |
298 | do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0) | |
299 | /* Use this when it might be in the instruction queue. */ | |
300 | #define MODIFIED_CODE(where) \ | |
301 | do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0) | |
302 | ||
303 | /* Set up the loaded object described by MAP so its unrelocated PLT | |
304 | entries will jump to the on-demand fixup code in dl-runtime.c. */ | |
9e365fe7 | 305 | static inline int __attribute__ ((always_inline)) |
cfc91acd RM |
306 | elf_machine_runtime_setup (struct link_map *map, int lazy, int profile) |
307 | { | |
308 | if (map->l_info[DT_JMPREL]) | |
309 | { | |
310 | Elf64_Word i; | |
311 | Elf64_Word *glink = NULL; | |
312 | Elf64_Xword *plt = (Elf64_Xword *) D_PTR (map, l_info[DT_PLTGOT]); | |
313 | Elf64_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val | |
314 | / sizeof (Elf64_Rela)); | |
315 | Elf64_Addr l_addr = map->l_addr; | |
316 | Elf64_Dyn **info = map->l_info; | |
317 | char *p; | |
318 | ||
319 | extern void _dl_runtime_resolve (void); | |
320 | extern void _dl_profile_resolve (void); | |
321 | ||
322 | /* Relocate the DT_PPC64_GLINK entry in the _DYNAMIC section. | |
323 | elf_get_dynamic_info takes care of the standard entries but | |
a6963e69 | 324 | doesn't know exactly what to do with processor specific |
cfc91acd RM |
325 | entires. */ |
326 | if (info[DT_PPC64(GLINK)] != NULL) | |
327 | info[DT_PPC64(GLINK)]->d_un.d_ptr += l_addr; | |
328 | ||
329 | if (lazy) | |
330 | { | |
331 | /* The function descriptor of the appropriate trampline | |
332 | routine is used to set the 1st and 2nd doubleword of the | |
333 | plt_reserve. */ | |
334 | Elf64_FuncDesc *resolve_fd; | |
335 | Elf64_Word glink_offset; | |
336 | /* the plt_reserve area is the 1st 3 doublewords of the PLT */ | |
337 | Elf64_FuncDesc *plt_reserve = (Elf64_FuncDesc *) plt; | |
338 | Elf64_Word offset; | |
339 | ||
340 | resolve_fd = (Elf64_FuncDesc *) (profile ? _dl_profile_resolve | |
341 | : _dl_runtime_resolve); | |
4e2d5491 UD |
342 | if (profile && GLRO(dl_profile) != NULL |
343 | && _dl_name_match_p (GLRO(dl_profile), map)) | |
cfc91acd RM |
344 | /* This is the object we are looking for. Say that we really |
345 | want profiling and the timers are started. */ | |
346 | GL(dl_profile_map) = map; | |
347 | ||
348 | ||
349 | /* We need to stuff the address/TOC of _dl_runtime_resolve | |
350 | into doublewords 0 and 1 of plt_reserve. Then we need to | |
351 | stuff the map address into doubleword 2 of plt_reserve. | |
352 | This allows the GLINK0 code to transfer control to the | |
353 | correct trampoline which will transfer control to fixup | |
354 | in dl-machine.c. */ | |
355 | plt_reserve->fd_func = resolve_fd->fd_func; | |
356 | plt_reserve->fd_toc = resolve_fd->fd_toc; | |
357 | plt_reserve->fd_aux = (Elf64_Addr) map; | |
358 | #ifdef RTLD_BOOTSTRAP | |
359 | /* When we're bootstrapping, the opd entry will not have | |
360 | been relocated yet. */ | |
361 | plt_reserve->fd_func += l_addr; | |
362 | plt_reserve->fd_toc += l_addr; | |
363 | #endif | |
a6963e69 | 364 | |
cfc91acd RM |
365 | /* Set up the lazy PLT entries. */ |
366 | glink = (Elf64_Word *) D_PTR (map, l_info[DT_PPC64(GLINK)]); | |
367 | offset = PLT_INITIAL_ENTRY_WORDS; | |
368 | glink_offset = GLINK_INITIAL_ENTRY_WORDS; | |
369 | for (i = 0; i < num_plt_entries; i++) | |
370 | { | |
371 | ||
372 | plt[offset] = (Elf64_Xword) &glink[glink_offset]; | |
373 | offset += 3; | |
374 | /* The first 32k entries of glink can set an index and | |
375 | branch using two instructions; Past that point, | |
376 | glink uses three instructions. */ | |
377 | if (i < 0x8000) | |
d063d164 | 378 | glink_offset += 2; |
cfc91acd | 379 | else |
d063d164 | 380 | glink_offset += 3; |
cfc91acd RM |
381 | } |
382 | ||
383 | /* Now, we've modified data. We need to write the changes from | |
384 | the data cache to a second-level unified cache, then make | |
385 | sure that stale data in the instruction cache is removed. | |
386 | (In a multiprocessor system, the effect is more complex.) | |
387 | Most of the PLT shouldn't be in the instruction cache, but | |
388 | there may be a little overlap at the start and the end. | |
389 | ||
390 | Assumes that dcbst and icbi apply to lines of 16 bytes or | |
391 | more. Current known line sizes are 16, 32, and 128 bytes. */ | |
392 | ||
393 | for (p = (char *) plt; p < (char *) &plt[offset]; p += 16) | |
394 | PPC_DCBST (p); | |
395 | PPC_SYNC; | |
396 | } | |
397 | } | |
398 | return lazy; | |
399 | } | |
400 | ||
cfc91acd RM |
401 | /* Change the PLT entry whose reloc is 'reloc' to call the actual |
402 | routine. */ | |
9e365fe7 | 403 | static inline Elf64_Addr __attribute__ ((always_inline)) |
cfc91acd RM |
404 | elf_machine_fixup_plt (struct link_map *map, lookup_t sym_map, |
405 | const Elf64_Rela *reloc, | |
406 | Elf64_Addr *reloc_addr, Elf64_Addr finaladdr) | |
407 | { | |
408 | Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr; | |
409 | Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr; | |
410 | Elf64_Addr offset = 0; | |
cfc91acd | 411 | |
153cf972 UD |
412 | PPC_DCBT (&plt->fd_aux); |
413 | PPC_DCBT (&plt->fd_func); | |
414 | PPC_DCBT (&rel->fd_aux); | |
415 | PPC_DCBT (&rel->fd_func); | |
416 | ||
cfc91acd RM |
417 | /* If sym_map is NULL, it's a weak undefined sym; Leave the plt zero. */ |
418 | if (sym_map == NULL) | |
419 | return 0; | |
420 | ||
421 | /* If the opd entry is not yet relocated (because it's from a shared | |
422 | object that hasn't been processed yet), then manually reloc it. */ | |
423 | if (map != sym_map && !sym_map->l_relocated | |
bb0ddc2f | 424 | #if !defined RTLD_BOOTSTRAP && defined SHARED |
cfc91acd RM |
425 | /* Bootstrap map doesn't have l_relocated set for it. */ |
426 | && sym_map != &GL(dl_rtld_map) | |
427 | #endif | |
428 | ) | |
429 | offset = sym_map->l_addr; | |
430 | ||
431 | /* For PPC64, fixup_plt copies the function descriptor from opd | |
432 | over the corresponding PLT entry. | |
433 | Initially, PLT Entry[i] is set up for lazy linking, or is zero. | |
434 | For lazy linking, the fd_toc and fd_aux entries are irrelevant, | |
435 | so for thread safety we write them before changing fd_func. */ | |
436 | ||
437 | plt->fd_aux = rel->fd_aux + offset; | |
438 | plt->fd_toc = rel->fd_toc + offset; | |
153cf972 UD |
439 | PPC_DCBF (&plt->fd_toc); |
440 | PPC_ISYNC; | |
cfc91acd RM |
441 | |
442 | plt->fd_func = rel->fd_func + offset; | |
443 | PPC_DCBST (&plt->fd_func); | |
153cf972 | 444 | PPC_ISYNC; |
cfc91acd RM |
445 | |
446 | return finaladdr; | |
447 | } | |
448 | ||
9e365fe7 | 449 | static inline void __attribute__ ((always_inline)) |
06e2e0a7 UD |
450 | elf_machine_plt_conflict (Elf64_Addr *reloc_addr, Elf64_Addr finaladdr) |
451 | { | |
452 | Elf64_FuncDesc *plt = (Elf64_FuncDesc *) reloc_addr; | |
453 | Elf64_FuncDesc *rel = (Elf64_FuncDesc *) finaladdr; | |
454 | ||
455 | plt->fd_func = rel->fd_func; | |
456 | plt->fd_aux = rel->fd_aux; | |
457 | plt->fd_toc = rel->fd_toc; | |
458 | PPC_DCBST (&plt->fd_func); | |
459 | PPC_DCBST (&plt->fd_aux); | |
460 | PPC_DCBST (&plt->fd_toc); | |
461 | PPC_SYNC; | |
462 | } | |
463 | ||
cfc91acd RM |
464 | /* Return the final value of a plt relocation. */ |
465 | static inline Elf64_Addr | |
466 | elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, | |
467 | Elf64_Addr value) | |
468 | { | |
469 | return value + reloc->r_addend; | |
470 | } | |
a6963e69 | 471 | |
82221992 UD |
472 | |
473 | /* Names of the architecture-specific auditing callback functions. */ | |
474 | #define ARCH_LA_PLTENTER ppc64_gnu_pltenter | |
475 | #define ARCH_LA_PLTEXIT ppc64_gnu_pltexit | |
476 | ||
cfc91acd RM |
477 | #endif /* dl_machine_h */ |
478 | ||
479 | #ifdef RESOLVE_MAP | |
480 | ||
481 | #define PPC_LO(v) ((v) & 0xffff) | |
482 | #define PPC_HI(v) (((v) >> 16) & 0xffff) | |
483 | #define PPC_HA(v) PPC_HI ((v) + 0x8000) | |
484 | #define PPC_HIGHER(v) (((v) >> 32) & 0xffff) | |
485 | #define PPC_HIGHERA(v) PPC_HIGHER ((v) + 0x8000) | |
486 | #define PPC_HIGHEST(v) (((v) >> 48) & 0xffff) | |
487 | #define PPC_HIGHESTA(v) PPC_HIGHEST ((v) + 0x8000) | |
bb0ddc2f | 488 | #define BIT_INSERT(var, val, mask) \ |
790eed83 | 489 | ((var) = ((var) & ~(Elf64_Addr) (mask)) | ((val) & (mask))) |
cfc91acd RM |
490 | |
491 | #define dont_expect(X) __builtin_expect ((X), 0) | |
492 | ||
493 | extern void _dl_reloc_overflow (struct link_map *map, | |
d063d164 UD |
494 | const char *name, |
495 | Elf64_Addr *const reloc_addr, | |
496 | const Elf64_Sym *refsym) | |
497 | attribute_hidden; | |
cfc91acd | 498 | |
7de00121 | 499 | auto inline void __attribute__ ((always_inline)) |
cfc91acd | 500 | elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, |
87d254a7 | 501 | void *const reloc_addr_arg) |
cfc91acd | 502 | { |
87d254a7 | 503 | Elf64_Addr *const reloc_addr = reloc_addr_arg; |
cfc91acd | 504 | *reloc_addr = l_addr + reloc->r_addend; |
afafddab | 505 | } |
cfc91acd | 506 | |
b3838ebd | 507 | /* This computes the value used by TPREL* relocs. */ |
7de00121 | 508 | auto inline Elf64_Addr __attribute__ ((always_inline, const)) |
b3838ebd RM |
509 | elf_machine_tprel (struct link_map *map, |
510 | struct link_map *sym_map, | |
511 | const Elf64_Sym *sym, | |
512 | const Elf64_Rela *reloc) | |
513 | { | |
d063d164 | 514 | #ifndef RTLD_BOOTSTRAP |
b3838ebd RM |
515 | if (sym_map) |
516 | { | |
517 | CHECK_STATIC_TLS (map, sym_map); | |
d063d164 | 518 | #endif |
b3838ebd | 519 | return TLS_TPREL_VALUE (sym_map, sym, reloc); |
d063d164 | 520 | #ifndef RTLD_BOOTSTRAP |
b3838ebd | 521 | } |
d063d164 | 522 | #endif |
b3838ebd RM |
523 | return 0; |
524 | } | |
b3838ebd | 525 | |
77799d9d AM |
526 | /* Call function at address VALUE (an OPD entry) to resolve ifunc relocs. */ |
527 | auto inline Elf64_Addr __attribute__ ((always_inline)) | |
528 | resolve_ifunc (Elf64_Addr value, | |
529 | const struct link_map *map, const struct link_map *sym_map) | |
530 | { | |
872873d4 | 531 | #ifndef RESOLVE_CONFLICT_FIND_MAP |
77799d9d AM |
532 | /* The function we are calling may not yet have its opd entry relocated. */ |
533 | Elf64_FuncDesc opd; | |
534 | if (map != sym_map | |
872873d4 | 535 | # if !defined RTLD_BOOTSTRAP && defined SHARED |
77799d9d AM |
536 | /* Bootstrap map doesn't have l_relocated set for it. */ |
537 | && sym_map != &GL(dl_rtld_map) | |
872873d4 | 538 | # endif |
77799d9d AM |
539 | && !sym_map->l_relocated) |
540 | { | |
541 | Elf64_FuncDesc *func = (Elf64_FuncDesc *) value; | |
542 | opd.fd_func = func->fd_func + sym_map->l_addr; | |
543 | opd.fd_toc = func->fd_toc + sym_map->l_addr; | |
544 | opd.fd_aux = func->fd_aux; | |
545 | value = (Elf64_Addr) &opd; | |
546 | } | |
872873d4 | 547 | #endif |
a386f1cc | 548 | return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap)); |
77799d9d AM |
549 | } |
550 | ||
cfc91acd RM |
551 | /* Perform the relocation specified by RELOC and SYM (which is fully |
552 | resolved). MAP is the object containing the reloc. */ | |
7de00121 | 553 | auto inline void __attribute__ ((always_inline)) |
cfc91acd RM |
554 | elf_machine_rela (struct link_map *map, |
555 | const Elf64_Rela *reloc, | |
556 | const Elf64_Sym *sym, | |
557 | const struct r_found_version *version, | |
3a62d00d AS |
558 | void *const reloc_addr_arg, |
559 | int skip_ifunc) | |
cfc91acd | 560 | { |
87d254a7 | 561 | Elf64_Addr *const reloc_addr = reloc_addr_arg; |
bb0ddc2f | 562 | const int r_type = ELF64_R_TYPE (reloc->r_info); |
cfc91acd | 563 | const Elf64_Sym *const refsym = sym; |
cfc91acd RM |
564 | |
565 | if (r_type == R_PPC64_RELATIVE) | |
566 | { | |
afafddab | 567 | *reloc_addr = map->l_addr + reloc->r_addend; |
cfc91acd RM |
568 | return; |
569 | } | |
570 | ||
bb0ddc2f | 571 | if (__builtin_expect (r_type == R_PPC64_NONE, 0)) |
cfc91acd RM |
572 | return; |
573 | ||
77799d9d AM |
574 | /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt |
575 | and STT_GNU_IFUNC. */ | |
bb0ddc2f | 576 | struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); |
b3838ebd | 577 | Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value) |
790eed83 | 578 | + reloc->r_addend); |
cfc91acd | 579 | |
77799d9d AM |
580 | if (sym != NULL |
581 | && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0) | |
3a62d00d AS |
582 | && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1) |
583 | && __builtin_expect (!skip_ifunc, 1)) | |
77799d9d AM |
584 | value = resolve_ifunc (value, map, sym_map); |
585 | ||
bb0ddc2f RM |
586 | /* For relocs that don't edit code, return. |
587 | For relocs that might edit instructions, break from the switch. */ | |
cfc91acd RM |
588 | switch (r_type) |
589 | { | |
590 | case R_PPC64_ADDR64: | |
591 | case R_PPC64_GLOB_DAT: | |
a6963e69 | 592 | *reloc_addr = value; |
cfc91acd | 593 | return; |
a6963e69 | 594 | |
77799d9d | 595 | case R_PPC64_IRELATIVE: |
3a62d00d AS |
596 | if (__builtin_expect (!skip_ifunc, 1)) |
597 | value = resolve_ifunc (value, map, sym_map); | |
77799d9d AM |
598 | *reloc_addr = value; |
599 | return; | |
600 | ||
601 | case R_PPC64_JMP_IREL: | |
3a62d00d AS |
602 | if (__builtin_expect (!skip_ifunc, 1)) |
603 | value = resolve_ifunc (value, map, sym_map); | |
77799d9d | 604 | /* Fall thru */ |
bb0ddc2f RM |
605 | case R_PPC64_JMP_SLOT: |
606 | #ifdef RESOLVE_CONFLICT_FIND_MAP | |
06e2e0a7 UD |
607 | elf_machine_plt_conflict (reloc_addr, value); |
608 | #else | |
bb0ddc2f | 609 | elf_machine_fixup_plt (map, sym_map, reloc, reloc_addr, value); |
06e2e0a7 | 610 | #endif |
bb0ddc2f | 611 | return; |
afafddab RM |
612 | |
613 | case R_PPC64_DTPMOD64: | |
d063d164 | 614 | #ifdef RTLD_BOOTSTRAP |
b3838ebd | 615 | /* During startup the dynamic linker is always index 1. */ |
afafddab | 616 | *reloc_addr = 1; |
d063d164 | 617 | #else |
b3838ebd RM |
618 | /* Get the information from the link map returned by the |
619 | resolve function. */ | |
afafddab | 620 | if (sym_map != NULL) |
d063d164 UD |
621 | *reloc_addr = sym_map->l_tls_modid; |
622 | #endif | |
afafddab | 623 | return; |
a6963e69 | 624 | |
3a601d31 | 625 | case R_PPC64_DTPREL64: |
bb0ddc2f | 626 | /* During relocation all TLS symbols are defined and used. |
d063d164 UD |
627 | Therefore the offset is already correct. */ |
628 | #ifndef RTLD_BOOTSTRAP | |
22163624 UD |
629 | if (sym_map != NULL) |
630 | *reloc_addr = TLS_DTPREL_VALUE (sym, reloc); | |
d063d164 | 631 | #endif |
b3838ebd RM |
632 | return; |
633 | ||
3a601d31 | 634 | case R_PPC64_TPREL64: |
b3838ebd RM |
635 | *reloc_addr = elf_machine_tprel (map, sym_map, sym, reloc); |
636 | return; | |
637 | ||
638 | case R_PPC64_TPREL16_LO_DS: | |
639 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
640 | if (dont_expect ((value & 3) != 0)) | |
d063d164 | 641 | _dl_reloc_overflow (map, "R_PPC64_TPREL16_LO_DS", reloc_addr, refsym); |
817328ee | 642 | BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc); |
b3838ebd RM |
643 | break; |
644 | ||
645 | case R_PPC64_TPREL16_DS: | |
646 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
647 | if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0)) | |
d063d164 | 648 | _dl_reloc_overflow (map, "R_PPC64_TPREL16_DS", reloc_addr, refsym); |
817328ee | 649 | BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc); |
b3838ebd RM |
650 | break; |
651 | ||
652 | case R_PPC64_TPREL16: | |
653 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
654 | if (dont_expect ((value + 0x8000) >= 0x10000)) | |
d063d164 | 655 | _dl_reloc_overflow (map, "R_PPC64_TPREL16", reloc_addr, refsym); |
b3838ebd RM |
656 | *(Elf64_Half *) reloc_addr = PPC_LO (value); |
657 | break; | |
658 | ||
659 | case R_PPC64_TPREL16_LO: | |
660 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
661 | *(Elf64_Half *) reloc_addr = PPC_LO (value); | |
662 | break; | |
663 | ||
664 | case R_PPC64_TPREL16_HI: | |
665 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
666 | *(Elf64_Half *) reloc_addr = PPC_HI (value); | |
667 | break; | |
668 | ||
669 | case R_PPC64_TPREL16_HA: | |
670 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
671 | *(Elf64_Half *) reloc_addr = PPC_HA (value); | |
672 | break; | |
673 | ||
674 | case R_PPC64_TPREL16_HIGHER: | |
675 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
676 | *(Elf64_Half *) reloc_addr = PPC_HIGHER (value); | |
677 | break; | |
678 | ||
679 | case R_PPC64_TPREL16_HIGHEST: | |
680 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
681 | *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value); | |
682 | break; | |
683 | ||
684 | case R_PPC64_TPREL16_HIGHERA: | |
685 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
686 | *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value); | |
687 | break; | |
688 | ||
689 | case R_PPC64_TPREL16_HIGHESTA: | |
690 | value = elf_machine_tprel (map, sym_map, sym, reloc); | |
691 | *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value); | |
bb0ddc2f | 692 | break; |
cfc91acd RM |
693 | |
694 | #ifndef RTLD_BOOTSTRAP /* None of the following appear in ld.so */ | |
695 | case R_PPC64_ADDR16_LO_DS: | |
696 | if (dont_expect ((value & 3) != 0)) | |
d063d164 | 697 | _dl_reloc_overflow (map, "R_PPC64_ADDR16_LO_DS", reloc_addr, refsym); |
bb0ddc2f | 698 | BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc); |
afafddab RM |
699 | break; |
700 | ||
cfc91acd RM |
701 | case R_PPC64_ADDR16_LO: |
702 | *(Elf64_Half *) reloc_addr = PPC_LO (value); | |
703 | break; | |
704 | ||
705 | case R_PPC64_ADDR16_HI: | |
706 | *(Elf64_Half *) reloc_addr = PPC_HI (value); | |
707 | break; | |
708 | ||
709 | case R_PPC64_ADDR16_HA: | |
710 | *(Elf64_Half *) reloc_addr = PPC_HA (value); | |
711 | break; | |
712 | ||
b3838ebd | 713 | case R_PPC64_ADDR30: |
cfc91acd | 714 | { |
d063d164 UD |
715 | Elf64_Addr delta = value - (Elf64_Xword) reloc_addr; |
716 | if (dont_expect ((delta + 0x80000000) >= 0x10000000 | |
b3838ebd | 717 | || (delta & 3) != 0)) |
d063d164 UD |
718 | _dl_reloc_overflow (map, "R_PPC64_ADDR30", reloc_addr, refsym); |
719 | BIT_INSERT (*(Elf64_Word *) reloc_addr, delta, 0xfffffffc); | |
cfc91acd RM |
720 | } |
721 | break; | |
722 | ||
723 | case R_PPC64_COPY: | |
724 | if (dont_expect (sym == NULL)) | |
b3838ebd | 725 | /* This can happen in trace mode when an object could not be found. */ |
d063d164 | 726 | return; |
cfc91acd | 727 | if (dont_expect (sym->st_size > refsym->st_size |
afdca0f2 UD |
728 | || (GLRO(dl_verbose) |
729 | && sym->st_size < refsym->st_size))) | |
b3838ebd | 730 | { |
d063d164 | 731 | const char *strtab; |
cfc91acd | 732 | |
d063d164 UD |
733 | strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); |
734 | _dl_error_printf ("%s: Symbol `%s' has different size" \ | |
735 | " in shared object," \ | |
736 | " consider re-linking\n", | |
37fb1dc0 | 737 | rtld_progname ?: "<program name unknown>", |
b3838ebd RM |
738 | strtab + refsym->st_name); |
739 | } | |
87d254a7 AO |
740 | memcpy (reloc_addr_arg, (char *) value, |
741 | MIN (sym->st_size, refsym->st_size)); | |
cfc91acd RM |
742 | return; |
743 | ||
744 | case R_PPC64_UADDR64: | |
745 | /* We are big-endian. */ | |
87d254a7 AO |
746 | ((char *) reloc_addr_arg)[0] = (value >> 56) & 0xff; |
747 | ((char *) reloc_addr_arg)[1] = (value >> 48) & 0xff; | |
748 | ((char *) reloc_addr_arg)[2] = (value >> 40) & 0xff; | |
749 | ((char *) reloc_addr_arg)[3] = (value >> 32) & 0xff; | |
750 | ((char *) reloc_addr_arg)[4] = (value >> 24) & 0xff; | |
751 | ((char *) reloc_addr_arg)[5] = (value >> 16) & 0xff; | |
752 | ((char *) reloc_addr_arg)[6] = (value >> 8) & 0xff; | |
753 | ((char *) reloc_addr_arg)[7] = (value >> 0) & 0xff; | |
cfc91acd RM |
754 | return; |
755 | ||
756 | case R_PPC64_UADDR32: | |
757 | /* We are big-endian. */ | |
87d254a7 AO |
758 | ((char *) reloc_addr_arg)[0] = (value >> 24) & 0xff; |
759 | ((char *) reloc_addr_arg)[1] = (value >> 16) & 0xff; | |
760 | ((char *) reloc_addr_arg)[2] = (value >> 8) & 0xff; | |
761 | ((char *) reloc_addr_arg)[3] = (value >> 0) & 0xff; | |
cfc91acd RM |
762 | return; |
763 | ||
b3838ebd RM |
764 | case R_PPC64_ADDR32: |
765 | if (dont_expect ((value + 0x80000000) >= 0x10000000)) | |
d063d164 | 766 | _dl_reloc_overflow (map, "R_PPC64_ADDR32", reloc_addr, refsym); |
b3838ebd RM |
767 | *(Elf64_Word *) reloc_addr = value; |
768 | return; | |
769 | ||
cfc91acd RM |
770 | case R_PPC64_ADDR24: |
771 | if (dont_expect ((value + 0x2000000) >= 0x4000000 || (value & 3) != 0)) | |
d063d164 | 772 | _dl_reloc_overflow (map, "R_PPC64_ADDR24", reloc_addr, refsym); |
bb0ddc2f | 773 | BIT_INSERT (*(Elf64_Word *) reloc_addr, value, 0x3fffffc); |
cfc91acd RM |
774 | break; |
775 | ||
776 | case R_PPC64_ADDR16: | |
777 | if (dont_expect ((value + 0x8000) >= 0x10000)) | |
d063d164 | 778 | _dl_reloc_overflow (map, "R_PPC64_ADDR16", reloc_addr, refsym); |
cfc91acd RM |
779 | *(Elf64_Half *) reloc_addr = value; |
780 | break; | |
781 | ||
782 | case R_PPC64_UADDR16: | |
783 | if (dont_expect ((value + 0x8000) >= 0x10000)) | |
d063d164 | 784 | _dl_reloc_overflow (map, "R_PPC64_UADDR16", reloc_addr, refsym); |
cfc91acd | 785 | /* We are big-endian. */ |
87d254a7 AO |
786 | ((char *) reloc_addr_arg)[0] = (value >> 8) & 0xff; |
787 | ((char *) reloc_addr_arg)[1] = (value >> 0) & 0xff; | |
cfc91acd RM |
788 | break; |
789 | ||
790 | case R_PPC64_ADDR16_DS: | |
791 | if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0)) | |
d063d164 | 792 | _dl_reloc_overflow (map, "R_PPC64_ADDR16_DS", reloc_addr, refsym); |
bb0ddc2f | 793 | BIT_INSERT (*(Elf64_Half *) reloc_addr, value, 0xfffc); |
afafddab RM |
794 | break; |
795 | ||
cfc91acd RM |
796 | case R_PPC64_ADDR16_HIGHER: |
797 | *(Elf64_Half *) reloc_addr = PPC_HIGHER (value); | |
798 | break; | |
799 | ||
800 | case R_PPC64_ADDR16_HIGHEST: | |
801 | *(Elf64_Half *) reloc_addr = PPC_HIGHEST (value); | |
802 | break; | |
803 | ||
804 | case R_PPC64_ADDR16_HIGHERA: | |
805 | *(Elf64_Half *) reloc_addr = PPC_HIGHERA (value); | |
806 | break; | |
807 | ||
808 | case R_PPC64_ADDR16_HIGHESTA: | |
809 | *(Elf64_Half *) reloc_addr = PPC_HIGHESTA (value); | |
810 | break; | |
811 | ||
812 | case R_PPC64_ADDR14: | |
813 | case R_PPC64_ADDR14_BRTAKEN: | |
814 | case R_PPC64_ADDR14_BRNTAKEN: | |
815 | { | |
d063d164 | 816 | if (dont_expect ((value + 0x8000) >= 0x10000 || (value & 3) != 0)) |
63c7a7e8 | 817 | _dl_reloc_overflow (map, "R_PPC64_ADDR14", reloc_addr, refsym); |
d063d164 UD |
818 | Elf64_Word insn = *(Elf64_Word *) reloc_addr; |
819 | BIT_INSERT (insn, value, 0xfffc); | |
820 | if (r_type != R_PPC64_ADDR14) | |
bb0ddc2f RM |
821 | { |
822 | insn &= ~(1 << 21); | |
823 | if (r_type == R_PPC64_ADDR14_BRTAKEN) | |
824 | insn |= 1 << 21; | |
825 | if ((insn & (0x14 << 21)) == (0x04 << 21)) | |
826 | insn |= 0x02 << 21; | |
827 | else if ((insn & (0x14 << 21)) == (0x10 << 21)) | |
828 | insn |= 0x08 << 21; | |
829 | } | |
d063d164 | 830 | *(Elf64_Word *) reloc_addr = insn; |
cfc91acd RM |
831 | } |
832 | break; | |
833 | ||
834 | case R_PPC64_REL32: | |
b3838ebd RM |
835 | *(Elf64_Word *) reloc_addr = value - (Elf64_Addr) reloc_addr; |
836 | return; | |
837 | ||
838 | case R_PPC64_REL64: | |
839 | *reloc_addr = value - (Elf64_Addr) reloc_addr; | |
cfc91acd RM |
840 | return; |
841 | #endif /* !RTLD_BOOTSTRAP */ | |
842 | ||
843 | default: | |
844 | _dl_reloc_bad_type (map, r_type, 0); | |
845 | return; | |
846 | } | |
847 | MODIFIED_CODE_NOQUEUE (reloc_addr); | |
848 | } | |
849 | ||
7de00121 | 850 | auto inline void __attribute__ ((always_inline)) |
7ba7c829 | 851 | elf_machine_lazy_rel (struct link_map *map, |
3a62d00d AS |
852 | Elf64_Addr l_addr, const Elf64_Rela *reloc, |
853 | int skip_ifunc) | |
7ba7c829 UD |
854 | { |
855 | /* elf_machine_runtime_setup handles this. */ | |
856 | } | |
857 | ||
7de00121 | 858 | |
cfc91acd | 859 | #endif /* RESOLVE */ |