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