]>
Commit | Line | Data |
---|---|---|
01f3e03b | 1 | /* Machine-dependent ELF dynamic relocation inline functions. m68k version. |
c84142e8 | 2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
47707456 | 3 | This file is part of the GNU C Library. |
01f3e03b | 4 | |
47707456 UD |
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. | |
01f3e03b | 9 | |
47707456 UD |
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. | |
01f3e03b | 14 | |
47707456 UD |
15 | You should have received a copy of the GNU Library General Public |
16 | License along with the GNU C Library; see the file COPYING.LIB. If | |
17 | not, write to the Free Software Foundation, Inc., | |
18 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
01f3e03b | 19 | |
96e1bff2 RM |
20 | #ifndef dl_machine_h |
21 | #define dl_machine_h | |
22 | ||
01f3e03b RM |
23 | #define ELF_MACHINE_NAME "m68k" |
24 | ||
25 | #include <assert.h> | |
01f3e03b RM |
26 | |
27 | /* Return nonzero iff E_MACHINE is compatible with the running host. */ | |
28 | static inline int | |
29 | elf_machine_matches_host (Elf32_Half e_machine) | |
30 | { | |
31 | switch (e_machine) | |
32 | { | |
33 | case EM_68K: | |
34 | return 1; | |
35 | default: | |
36 | return 0; | |
37 | } | |
38 | } | |
39 | ||
40 | ||
47707456 UD |
41 | /* Return the link-time address of _DYNAMIC. Conveniently, this is the |
42 | first element of the GOT. This must be inlined in a function which | |
43 | uses global data. */ | |
44 | static inline Elf32_Addr | |
45 | elf_machine_dynamic (void) | |
01f3e03b RM |
46 | { |
47 | register Elf32_Addr *got asm ("%a5"); | |
47707456 | 48 | return *got; |
01f3e03b RM |
49 | } |
50 | ||
51 | ||
52 | /* Return the run-time load address of the shared object. */ | |
53 | static inline Elf32_Addr | |
54 | elf_machine_load_address (void) | |
55 | { | |
be10a868 RM |
56 | Elf32_Addr addr; |
57 | asm ("here: lea here(%%pc), %0\n" | |
58 | " sub.l %#here, %0" | |
59 | : "=a" (addr)); | |
60 | return addr; | |
01f3e03b RM |
61 | } |
62 | ||
be10a868 RM |
63 | /* The `subl' insn above will contain an R_68K_RELATIVE relocation |
64 | entry intended to insert the run-time address of the label `here'. | |
65 | This will be the first relocation in the text of the dynamic | |
66 | linker; we skip it to avoid trying to modify read-only text in this | |
67 | early stage. */ | |
68 | #define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) \ | |
69 | ((dynamic_info)[DT_RELA]->d_un.d_ptr += sizeof (Elf32_Rela), \ | |
70 | (dynamic_info)[DT_RELASZ]->d_un.d_val -= sizeof (Elf32_Rela)) | |
71 | ||
01f3e03b RM |
72 | |
73 | /* Set up the loaded object described by L so its unrelocated PLT | |
74 | entries will jump to the on-demand fixup code in dl-runtime.c. */ | |
75 | ||
76 | static inline void | |
77 | elf_machine_runtime_setup (struct link_map *l, int lazy) | |
78 | { | |
79 | Elf32_Addr *got; | |
80 | extern void _dl_runtime_resolve (Elf32_Word); | |
81 | ||
82 | if (l->l_info[DT_JMPREL] && lazy) | |
83 | { | |
84 | /* The GOT entries for functions in the PLT have not yet been | |
85 | filled in. Their initial contents will arrange when called | |
86 | to push an offset into the .rela.plt section, push | |
87 | _GLOBAL_OFFSET_TABLE_[1], and then jump to | |
88 | _GLOBAL_OFFSET_TABLE_[2]. */ | |
89 | got = (Elf32_Addr *) (l->l_addr + l->l_info[DT_PLTGOT]->d_un.d_ptr); | |
90 | got[1] = (Elf32_Addr) l; /* Identify this shared object. */ | |
91 | /* This function will get called to fix up the GOT entry | |
92 | indicated by the offset on the stack, and then jump to the | |
93 | resolved address. */ | |
94 | got[2] = (Elf32_Addr) &_dl_runtime_resolve; | |
95 | } | |
96 | ||
97 | /* This code is used in dl-runtime.c to call the `fixup' function | |
98 | and then redirect to the address it returns. */ | |
99 | #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\ | |
100 | | Trampoline for _dl_runtime_resolver | |
101 | .globl _dl_runtime_resolve | |
102 | .type _dl_runtime_resolve, @function | |
103 | _dl_runtime_resolve: | |
be10a868 | 104 | | Save %a0 (struct return address) and %a1. |
01f3e03b | 105 | move.l %a0, -(%sp) |
be10a868 | 106 | move.l %a1, -(%sp) |
01f3e03b | 107 | | Call the real address resolver. |
be10a868 RM |
108 | jbsr fixup |
109 | | Restore register %a0 and %a1. | |
110 | move.l (%sp)+, %a1 | |
01f3e03b RM |
111 | move.l (%sp)+, %a0 |
112 | | Pop parameters | |
113 | addq.l #8, %sp | |
114 | | Call real function. | |
115 | jmp (%d0) | |
116 | .size _dl_runtime_resolve, . - _dl_runtime_resolve | |
117 | "); | |
be10a868 RM |
118 | #define ELF_MACHINE_RUNTIME_FIXUP_ARGS long int save_a0, long int save_a1 |
119 | /* The PLT uses Elf32_Rela relocs. */ | |
120 | #define elf_machine_relplt elf_machine_rela | |
01f3e03b RM |
121 | } |
122 | ||
123 | ||
124 | /* Mask identifying addresses reserved for the user program, | |
125 | where the dynamic linker should not map anything. */ | |
126 | #define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL | |
127 | ||
128 | /* Initial entry point code for the dynamic linker. | |
129 | The C function `_dl_start' is the real entry point; | |
130 | its return value is the user program's entry point. */ | |
131 | ||
132 | #define RTLD_START asm ("\ | |
133 | .text | |
134 | .globl _start | |
135 | .globl _dl_start_user | |
136 | _start: | |
8d6468d0 | 137 | move.l %sp, -(%sp) |
01f3e03b | 138 | jbsr _dl_start |
8d6468d0 | 139 | addq.l #4, %sp |
01f3e03b RM |
140 | _dl_start_user: |
141 | | Save the user entry point address in %a4. | |
142 | move.l %d0, %a4 | |
143 | | Point %a5 at the GOT. | |
144 | lea _GLOBAL_OFFSET_TABLE_@GOTPC(%pc), %a5 | |
145 | | See if we were run as a command with the executable file | |
146 | | name as an extra leading argument. | |
147 | move.l ([_dl_skip_args@GOT, %a5]), %d0 | |
148 | jeq 0f | |
149 | | Pop the original argument count | |
150 | move.l (%sp)+, %d1 | |
151 | | Subtract _dl_skip_args from it. | |
152 | sub.l %d0, %d1 | |
153 | | Adjust the stack pointer to skip _dl_skip_args words. | |
154 | lea (%sp, %d0*4), %sp | |
155 | | Push back the modified argument count. | |
156 | move.l %d1, -(%sp) | |
ba79d61b | 157 | 0: | Push _dl_default_scope[2] as argument in _dl_init_next call below. |
2cc7dc4d RM |
158 | move.l ([_dl_default_scope@GOT, %a5], 8), %d2 |
159 | 0: move.l %d2, -(%sp) | |
01f3e03b RM |
160 | | Call _dl_init_next to return the address of an initializer |
161 | | function to run. | |
f68b86cc RM |
162 | bsr.l _dl_init_next@PLTPC |
163 | add.l #4, %sp | Pop argument. | |
01f3e03b RM |
164 | | Check for zero return, when out of initializers. |
165 | tst.l %d0 | |
166 | jeq 1f | |
167 | | Call the shared object initializer function. | |
f68b86cc | 168 | | NOTE: We depend only on the registers (%d2, %a4 and %a5) |
01f3e03b RM |
169 | | and the return address pushed by this call; |
170 | | the initializer is called with the stack just | |
171 | | as it appears on entry, and it is free to move | |
172 | | the stack around, as long as it winds up jumping to | |
173 | | the return address on the top of the stack. | |
174 | move.l %d0, %a0 | |
175 | jsr (%a0) | |
176 | | Loop to call _dl_init_next for the next initializer. | |
177 | jra 0b | |
39778c6c | 178 | 1: | Clear the startup flag. |
dcf0671d | 179 | clr.l _dl_starting_up@GOT(%a5) |
39778c6c | 180 | | Pass our finalizer function to the user in %a1. |
01f3e03b RM |
181 | move.l _dl_fini@GOT(%a5), %a1 |
182 | | Initialize %fp with the stack pointer. | |
183 | move.l %sp, %fp | |
184 | | Jump to the user's entry point. | |
185 | jmp (%a4)"); | |
96e1bff2 | 186 | |
e7fd8a39 UD |
187 | /* Nonzero iff TYPE describes a relocation that should |
188 | skip the executable when looking up the symbol value. */ | |
189 | #define elf_machine_lookup_noexec_p(type) ((type) == R_68K_COPY) | |
190 | ||
96e1bff2 RM |
191 | /* Nonzero iff TYPE describes relocation of a PLT entry, so |
192 | PLT entries should not be allowed to define the value. */ | |
e7fd8a39 UD |
193 | #define elf_machine_lookup_noplt_p(type) ((type) == R_68K_JMP_SLOT) |
194 | ||
195 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ | |
196 | #define ELF_MACHINE_RELOC_NOPLT R_68K_JMP_SLOT | |
96e1bff2 RM |
197 | |
198 | /* The m68k never uses Elf32_Rel relocations. */ | |
199 | #define ELF_MACHINE_NO_REL 1 | |
200 | ||
201 | #endif /* !dl_machine_h */ | |
202 | ||
203 | #ifdef RESOLVE | |
204 | ||
205 | /* Perform the relocation specified by RELOC and SYM (which is fully resolved). | |
206 | MAP is the object containing the reloc. */ | |
207 | ||
208 | static inline void | |
c84142e8 | 209 | elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, |
1fb05e3d | 210 | const Elf32_Sym *sym, const struct r_found_version *version) |
96e1bff2 RM |
211 | { |
212 | Elf32_Addr *const reloc_addr = (void *) (map->l_addr + reloc->r_offset); | |
96e1bff2 | 213 | |
e7fd8a39 UD |
214 | if (ELF32_R_TYPE (reloc->r_info) == R_68K_RELATIVE) |
215 | *reloc_addr = map->l_addr + reloc->r_addend; | |
216 | else | |
96e1bff2 | 217 | { |
e7fd8a39 UD |
218 | Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info)); |
219 | if (sym) | |
220 | value += sym->st_value; | |
221 | ||
222 | switch (ELF32_R_TYPE (reloc->r_info)) | |
223 | { | |
224 | case R_68K_COPY: | |
225 | memcpy (reloc_addr, (void *) value, sym->st_size); | |
226 | break; | |
227 | case R_68K_GLOB_DAT: | |
228 | case R_68K_JMP_SLOT: | |
229 | *reloc_addr = value; | |
230 | break; | |
231 | case R_68K_8: | |
232 | *(char *) reloc_addr = value + reloc->r_addend; | |
233 | break; | |
234 | case R_68K_16: | |
235 | *(short *) reloc_addr = value + reloc->r_addend; | |
236 | break; | |
237 | case R_68K_32: | |
238 | *reloc_addr = value + reloc->r_addend; | |
239 | break; | |
240 | case R_68K_PC8: | |
241 | *(char *) reloc_addr | |
242 | = value + reloc->r_addend - (Elf32_Addr) reloc_addr; | |
243 | break; | |
244 | case R_68K_PC16: | |
245 | *(short *) reloc_addr | |
246 | = value + reloc->r_addend - (Elf32_Addr) reloc_addr; | |
247 | break; | |
248 | case R_68K_PC32: | |
249 | *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr; | |
250 | break; | |
251 | case R_68K_NONE: /* Alright, Wilbur. */ | |
252 | break; | |
253 | default: | |
254 | assert (! "unexpected dynamic reloc type"); | |
255 | break; | |
256 | } | |
96e1bff2 | 257 | } |
96e1bff2 RM |
258 | } |
259 | ||
260 | static inline void | |
261 | elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc) | |
262 | { | |
263 | Elf32_Addr *const reloc_addr = (void *) (map->l_addr + reloc->r_offset); | |
264 | switch (ELF32_R_TYPE (reloc->r_info)) | |
265 | { | |
266 | case R_68K_JMP_SLOT: | |
267 | *reloc_addr += map->l_addr; | |
268 | break; | |
269 | default: | |
270 | assert (! "unexpected PLT reloc type"); | |
271 | break; | |
272 | } | |
273 | } | |
274 | ||
275 | #endif /* RESOLVE */ |