Move all files into ports/ subdirectory in preparation for merge with glibc
[glibc.git] / ports / sysdeps / am33 / dl-machine.h
blob52278c0a4e006563e983e55e49831c3ab036ad10
1 /* Machine-dependent ELF dynamic relocation inline functions. AM33 version.
2 Copyright (C) 1995,96,97,98,99,2000,2001, 2004, 2011
3 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
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.
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.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library. If not, see
18 <http://www.gnu.org/licenses/>. */
20 #ifndef dl_machine_h
21 #define dl_machine_h
23 #define ELF_MACHINE_NAME "mn10300"
25 #include <sys/param.h>
27 /* Return nonzero iff ELF header is compatible with the running host. */
28 static inline int __attribute__ ((unused))
29 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
31 return ehdr->e_machine == EM_MN10300;
35 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
36 first element of the GOT. This must be inlined in a function which
37 uses global data. */
38 static inline Elf32_Addr __attribute__ ((unused))
39 elf_machine_dynamic (void)
41 register Elf32_Addr *got asm ("a2");
42 return *got;
46 /* Return the run-time load address of the shared object. */
47 static inline Elf32_Addr __attribute__ ((unused))
48 elf_machine_load_address (void)
50 register Elf32_Addr gotaddr asm ("a2");
51 Elf32_Addr off, gotval;
53 asm ("mov _dl_start@GOTOFF,%0" : "=r" (off));
54 asm ("mov (_dl_start@GOT,%1),%0" : "=r" (gotval) : "r" (gotaddr));
56 return off + gotaddr - gotval;
59 #if !defined PROF && !__BOUNDED_POINTERS__
60 /* We add a declaration of this function here so that in dl-runtime.c
61 the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters
62 in registers.
64 We cannot use this scheme for profiling because the _mcount call
65 destroys the passed register information. */
66 /* GKM FIXME: Fix trampoline to pass bounds so we can do
67 without the `__unbounded' qualifier. */
68 static ElfW(Addr) fixup (struct link_map *__unbounded l, ElfW(Word) reloc_offset)
69 __attribute__ ((unused));
70 static ElfW(Addr) profile_fixup (struct link_map *l, ElfW(Word) reloc_offset,
71 ElfW(Addr) retaddr)
72 __attribute__ ((unused));
73 #endif
75 /* Set up the loaded object described by L so its unrelocated PLT
76 entries will jump to the on-demand fixup code in dl-runtime.c. */
78 static inline int __attribute__ ((unused))
79 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
81 Elf32_Addr *got;
82 extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
83 extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
85 if (l->l_info[DT_JMPREL] && lazy)
87 /* The GOT entries for functions in the PLT have not yet been filled
88 in. Their initial contents will arrange when called to push an
89 offset into the .rel.plt section, push _GLOBAL_OFFSET_TABLE_[1],
90 and then jump to _GLOBAL_OFFSET_TABLE[2]. */
91 got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
92 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
94 /* The got[2] entry contains the address of a function which gets
95 called to get the address of a so far unresolved function and
96 jump to it. The profiling extension of the dynamic linker allows
97 to intercept the calls to collect information. In this case we
98 don't store the address in the GOT so that all future calls also
99 end in this function. */
100 if (__builtin_expect (profile, 0))
102 got[2] = (Elf32_Addr) &_dl_runtime_profile;
104 if (_dl_name_match_p (GLRO(dl_profile), l))
105 /* This is the object we are looking for. Say that we really
106 want profiling and the timers are started. */
107 GL(dl_profile_map) = l;
109 else
110 /* This function will get called to fix up the GOT entry indicated by
111 the offset on the stack, and then jump to the resolved address. */
112 got[2] = (Elf32_Addr) &_dl_runtime_resolve;
115 return lazy;
118 /* This code is used in dl-runtime.c to call the `fixup' function
119 and then redirect to the address it returns. */
120 #if !defined PROF && !__BOUNDED_POINTERS__
121 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\
122 .text\n\
123 .globl _dl_runtime_resolve\n\
124 .type _dl_runtime_resolve, @function\n\
125 _dl_runtime_resolve:\n\
126 add -12,sp # Preserve registers otherwise clobbered.\n\
127 mov d1,(20,sp)\n\
128 mov d0,(16,sp)\n\
129 mov r1,d0\n\
130 mov r0,d1\n\
131 call fixup,[],0 # Call resolver.\n\
132 mov d0,a0\n\
133 mov (12,sp),d1 # Copy return address back to mdr,\n\
134 mov d1,mdr # in case the callee returns with retf\n\
135 mov (16,sp),d0 # Get register content back.\n\
136 mov (20,sp),d1\n\
137 add 12,sp\n\
138 jmp (a0)\n\
139 .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
141 .globl _dl_runtime_profile\n\
142 .type _dl_runtime_profile, @function\n\
143 _dl_runtime_profile:\n\
144 add -12,sp # Preserve registers otherwise clobbered.\n\
145 mov d1,(20,sp)\n\
146 mov d0,(16,sp)\n\
147 mov r1,d0\n\
148 mov r0,d1\n\
149 call profile_fixup,[],0 # Call resolver.\n\
150 mov d0,a0\n\
151 mov (12,sp),d1 # Copy return address back to mdr,\n\
152 mov d1,mdr # in case the callee returns with retf\n\
153 mov (16,sp),d0 # Get register content back.\n\
154 mov (20,sp),d1\n\
155 add 12,sp\n\
156 jmp (a0)\n\
157 .size _dl_runtime_profile, .-_dl_runtime_profile\n\
158 .previous\n\
160 #else
161 # define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
162 .text\n\
163 .globl _dl_runtime_resolve\n\
164 .globl _dl_runtime_profile\n\
165 .type _dl_runtime_resolve, @function\n\
166 .type _dl_runtime_profile, @function\n\
167 _dl_runtime_resolve:\n\
168 _dl_runtime_profile:\n\
169 add -12,sp # Preserve registers otherwise clobbered.\n\
170 mov d1,(20,sp)\n\
171 mov d0,(16,sp)\n\
172 mov r1,d0\n\
173 mov r0,d1\n\
174 call profile_fixup,[],0 # Call resolver.\n\
175 mov d0,a0\n\
176 mov (12,sp),d1 # Copy return address back to mdr,\n\
177 mov d1,mdr # in case the callee returns with retf\n\
178 mov (16,sp),d0 # Get register content back.\n\
179 mov (20,sp),d1\n\
180 add 12,sp\n\
181 jmp (a0)\n\
182 .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\
183 .size _dl_runtime_profile, .-_dl_runtime_profile\n\
184 .previous\n\
186 #endif
188 /* Mask identifying addresses reserved for the user program,
189 where the dynamic linker should not map anything. */
190 #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL
192 /* Initial entry point code for the dynamic linker.
193 The C function `_dl_start' is the real entry point;
194 its return value is the user program's entry point. */
195 #define RTLD_START asm ("\n\
196 .text\n\
197 .globl _start\n\
198 .globl _dl_start_user\n\
199 _start:\n\
200 mov 0,a3 # Mark the top of the stack\n\
201 mov sp,a1\n\
202 add -20,sp # Prepare for function call\n\
203 mov a1,d0\n\
204 call _dl_start,[],0\n\
205 _dl_start_user:\n\
206 # Save the user entry point address in d2.\n\
207 mov d0,d2\n\
208 # Point a2 at the GOT.\n\
209 0: mov pc,a2\n\
210 add _GLOBAL_OFFSET_TABLE_ - (0b-.),a2\n\
211 # Store the highest stack address\n\
212 mov (__libc_stack_end@GOT,a2),a0\n\
213 mov a1,(a0)\n\
214 # See if we were run as a command with the executable file\n\
215 # name as an extra leading argument.\n\
216 mov (_dl_skip_args@GOT,a2),a0\n\
217 mov (a0),d0\n\
218 # Pop the original argument count.\n\
219 mov (20,sp),d3\n\
220 # Subtract _dl_skip_args from it.\n\
221 sub d0,d3\n\
222 # Adjust the stack pointer to skip _dl_skip_args words.\n\
223 asl2 d0\n\
224 mov sp,a0\n\
225 add d0,a0\n\
226 mov a0,sp\n\
227 # Push argc back on the stack.\n\
228 mov d3,(20,sp)\n\
229 # The special initializer gets called with the stack just\n\
230 # as the application's entry point will see it; it can\n\
231 # switch stacks if it moves these contents over.\n\
232 " RTLD_START_SPECIAL_INIT "\n\
233 # Load the parameters again.\n\
234 # (d0, d1, (12,sp), (16,sp)) = (_dl_loaded, argc, argv, envp)\n\
235 add 24,a0\n\
236 mov a0,(12,sp) # a0 is 24+sp\n\
237 mov d3,d1 # d3 contained argc\n\
238 inc d3\n\
239 asl2 d3 # d3 is now (argc+1)*4,\n\
240 add d3,a0 # the offset between argv and envp\n\
241 mov a0,(16,sp)\n\
242 mov (_rtld_local@GOTOFF,a2),d0\n\
243 # Call the function to run the initializers.\n\
244 call _dl_init@PLT,[],0\n\
245 # Pass our finalizer function to the user in d0, as per ELF ABI.\n\
246 mov (_dl_fini@GOT,a2),d0\n\
247 add 20,sp\n\
248 # Jump to the user's entry point.\n\
249 mov d2,a1\n\
250 jmp (a1)\n\
251 .previous\n\
254 #ifndef RTLD_START_SPECIAL_INIT
255 #define RTLD_START_SPECIAL_INIT /* nothing */
256 #endif
258 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
259 PLT entries should not be allowed to define the value.
260 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
261 of the main executable's symbols, as for a COPY reloc. */
262 #define elf_machine_type_class(type) \
263 ((((type) == R_MN10300_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
264 | (((type) == R_MN10300_COPY) * ELF_RTYPE_CLASS_COPY))
266 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
267 #define ELF_MACHINE_JMP_SLOT R_MN10300_JMP_SLOT
269 static inline Elf32_Addr
270 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
271 const Elf32_Rela *reloc,
272 Elf32_Addr *reloc_addr, Elf32_Addr value)
274 return *reloc_addr = value;
277 /* Return the final value of a plt relocation. */
278 static inline Elf32_Addr
279 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
280 Elf32_Addr value)
282 return value + reloc->r_addend;
285 #endif /* !dl_machine_h */
287 #ifdef RESOLVE
289 /* The mn10300 never uses Elf32_Rel relocations. */
290 #define ELF_MACHINE_NO_REL 1
292 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
293 MAP is the object containing the reloc. */
295 static inline void
296 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
297 const Elf32_Sym *sym, const struct r_found_version *version,
298 void *const reloc_addr_arg, int skip_ifunc)
300 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
301 Elf32_Addr value, *reloc_addr;
303 /* Make sure we drop any previous alignment assumptions. */
304 asm ("" : "=r" (reloc_addr) : "0" (reloc_addr_arg));
306 #define COPY_UNALIGNED_WORD(sw, tw, align) \
308 unsigned long *__sl = (void*)&(sw), *__tl = (void*)&(tw); \
309 unsigned short *__ss = (void*)&(sw), *__ts = (void*)&(tw); \
310 unsigned char *__sc = (void*)&(sw), *__tc = (void*)&(tw); \
311 switch ((align)) \
313 case 0: \
314 *__tl = *__sl; \
315 break; \
316 case 2: \
317 *__ts++ = *__ss++; \
318 *__ts = *__ss; \
319 break; \
320 default: \
321 *__tc++ = *__sc++; \
322 *__tc++ = *__sc++; \
323 *__tc++ = *__sc++; \
324 *__tc = *__sc; \
325 break; \
329 #define COPY_UNALIGNED_HALFWORD(sw, tw, align) \
331 unsigned short *__ss = (void*)&(sw), *__ts = (void*)&(tw); \
332 unsigned char *__sc = (void*)&(sw), *__tc = (void*)&(tw); \
333 switch ((align)) \
335 case 0: \
336 *__ts = *__ss; \
337 break; \
338 default: \
339 *__tc++ = *__sc++; \
340 *__tc = *__sc; \
341 break; \
345 #if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
346 if (__builtin_expect (r_type == R_MN10300_RELATIVE, 0))
348 # if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
349 /* This is defined in rtld.c, but nowhere in the static libc.a;
350 make the reference weak so static programs can still link.
351 This declaration cannot be done when compiling rtld.c (i.e.
352 #ifdef RTLD_BOOTSTRAP) because rtld.c contains the common
353 defn for _dl_rtld_map, which is incompatible with a weak decl
354 in the same file. */
355 weak_extern (_dl_rtld_map);
356 if (map != &_dl_rtld_map) /* Already done in rtld itself. */
357 # endif
359 COPY_UNALIGNED_WORD (*reloc_addr, value, (int) reloc_addr & 3);
360 value += map->l_addr;
361 COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
364 # ifndef RTLD_BOOTSTRAP
365 else if (__builtin_expect (r_type == R_MN10300_NONE, 0))
366 return;
367 # endif
368 else
369 #endif
371 #ifndef RTLD_BOOTSTRAP
372 const Elf32_Sym *const refsym = sym;
373 #endif
375 value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
376 if (sym)
377 value += sym->st_value;
378 value += reloc->r_addend; /* Assume copy relocs have zero addend. */
380 switch (r_type)
382 #ifndef RTLD_BOOTSTRAP
383 case R_MN10300_COPY:
384 if (sym == NULL)
385 /* This can happen in trace mode if an object could not be
386 found. */
387 break;
388 if (sym->st_size > refsym->st_size
389 || (GLRO(dl_verbose) && sym->st_size < refsym->st_size))
391 extern char **_dl_argv;
392 const char *strtab;
394 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
395 _dl_error_printf ("\
396 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
397 _dl_argv[0] ?: "<program name unknown>",
398 strtab + refsym->st_name);
400 memcpy (reloc_addr, (void *) value, MIN (sym->st_size,
401 refsym->st_size));
402 break;
403 #endif
404 case R_MN10300_GLOB_DAT:
405 case R_MN10300_JMP_SLOT:
406 /* These addresses are always aligned. */
407 *reloc_addr = value;
408 break;
409 case R_MN10300_32:
410 COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
411 break;
412 #ifndef RTLD_BOOTSTRAP
413 case R_MN10300_16:
414 COPY_UNALIGNED_HALFWORD (value, *reloc_addr, (int) reloc_addr & 1);
415 break;
416 case R_MN10300_8:
417 *(char *) reloc_addr = value;
418 break;
419 case R_MN10300_PCREL32:
420 value -= (Elf32_Addr) reloc_addr;
421 COPY_UNALIGNED_WORD (value, *reloc_addr, (int) reloc_addr & 3);
422 break;
423 case R_MN10300_PCREL16:
424 value -= (Elf32_Addr) reloc_addr;
425 COPY_UNALIGNED_HALFWORD (value, *reloc_addr, (int) reloc_addr & 1);
426 break;
427 case R_MN10300_PCREL8:
428 value -= (Elf32_Addr) reloc_addr;
429 *(char *) reloc_addr = (value - (Elf32_Addr) reloc_addr);
430 break;
431 #endif
432 case R_MN10300_NONE: /* Alright, Wilbur. */
433 break;
434 #if !defined RTLD_BOOTSTRAP || defined _NDEBUG
435 default:
436 _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0);
437 break;
438 #endif
444 static inline void
445 elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
446 void *const reloc_addr_arg)
448 Elf32_Addr value, *reloc_addr;
450 asm ("" : "=r" (reloc_addr) : "0" (reloc_addr_arg));
452 COPY_UNALIGNED_WORD (*reloc_addr, value, (int)reloc_addr & 3);
453 value += l_addr;
454 COPY_UNALIGNED_WORD (value, *reloc_addr, (int)reloc_addr & 3);
457 static inline void
458 elf_machine_lazy_rel (struct link_map *map,
459 Elf32_Addr l_addr, const Elf32_Rela *reloc,
460 int skip_ifunc)
462 unsigned long int const r_type = ELF32_R_TYPE (reloc->r_info);
464 /* Check for unexpected PLT reloc type. */
465 if (__builtin_expect (r_type, R_MN10300_JMP_SLOT) == R_MN10300_JMP_SLOT)
467 Elf32_Addr* const reloc_addr = (void *)(l_addr + reloc->r_offset);
468 Elf32_Addr value;
470 /* Perform a RELATIVE reloc on the .got entry that transfers
471 to the .plt. */
472 COPY_UNALIGNED_WORD (*reloc_addr, value, (int)reloc_addr & 3);
473 value += l_addr;
474 COPY_UNALIGNED_WORD (value, *reloc_addr, (int)reloc_addr & 3);
476 else if (__builtin_expect (r_type, R_MN10300_NONE) != R_MN10300_NONE)
477 _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 1);
481 #endif /* RESOLVE */