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