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