]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/nios2/dl-machine.h
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / nios2 / dl-machine.h
1 /* Machine-dependent ELF dynamic relocation inline functions. Nios II version.
2 Copyright (C) 1995-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library. If not, see
17 <http://www.gnu.org/licenses/>. */
18
19 #ifndef dl_machine_h
20 #define dl_machine_h
21
22 #define ELF_MACHINE_NAME "nios2"
23
24 #include <string.h>
25 #include <link.h>
26 #include <dl-tls.h>
27
28 /* Return nonzero iff ELF header is compatible with the running host. */
29 static inline int
30 elf_machine_matches_host (const Elf32_Ehdr *ehdr)
31 {
32 return ehdr->e_machine == EM_ALTERA_NIOS2;
33 }
34
35
36 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
37 first element of the GOT. */
38 static inline Elf32_Addr
39 elf_machine_dynamic (void)
40 {
41 Elf32_Addr *dynamic;
42 int tmp;
43 asm ("nextpc\t%0\n\t"
44 "1: movhi\t%1, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)\n\t"
45 "addi\t%1, %1, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)\n\t"
46 "add\t%0, %0, %1\n"
47 : "=r" (dynamic), "=r" (tmp));
48 return *dynamic;
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 {
56 Elf32_Addr result;
57 int tmp;
58 asm ("nextpc\t%0\n\t"
59 "1: movhi\t%1, %%hiadj(1b)\n\t"
60 "addi\t%1, %1, %%lo(1b)\n\t"
61 "sub\t%0, %0, %1\n"
62 : "=r" (result), "=r" (tmp));
63 return result;
64 }
65
66 /* Set up the loaded object described by L so its unrelocated PLT
67 entries will jump to the on-demand fixup code in dl-runtime.c. */
68
69 static inline int __attribute__ ((always_inline))
70 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
71 {
72 extern void _dl_runtime_resolve (Elf32_Word);
73
74 if (l->l_info[DT_JMPREL] && lazy)
75 {
76 /* The GOT entries for functions in the PLT have not yet been filled
77 in. Their initial contents will arrange when called to load r15 with
78 an offset into the .got section, load r14 with
79 _GLOBAL_OFFSET_TABLE_[1], and then jump to _GLOBAL_OFFSET_TABLE[2].
80 */
81 Elf32_Addr *got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
82 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
83
84 /* This function will get called to fix up the GOT entry indicated by
85 the offset on the stack, and then jump to the resolved address. */
86 got[2] = (Elf32_Addr) &_dl_runtime_resolve;
87 }
88
89 return lazy;
90 }
91
92 /* Initial entry point code for the dynamic linker.
93 The C function `_dl_start' is the real entry point;
94 its return value is the user program's entry point. */
95
96 #define RTLD_START asm ("\
97 .text\n\
98 .globl _start\n\
99 .type _start, %function\n\
100 _start:\n\
101 /* At start time, all the args are on the stack. */\n\
102 mov r4, sp\n\
103 \n\
104 /* Start the calculation of the GOT pointer. */\n\
105 nextpc r22\n\
106 1: movhi r8, %hiadj(_gp_got - 1b)\n\
107 addi r8, r8, %lo(_gp_got - 1b)\n\
108 \n\
109 /* Figure out where _dl_start will need to return to. */\n\
110 movhi ra, %hiadj(2f - 1b)\n\
111 addi ra, ra, %lo(2f - 1b)\n\
112 add ra, ra, r22\n\
113 \n\
114 /* Finish the calculation of the GOT pointer. */\n\
115 add r22, r22, r8\n\
116 \n\
117 br _dl_start\n\
118 \n\
119 /* Save the returned user entry point. */\n\
120 2: mov r16, r2\n\
121 \n\
122 /* Initialize gp. */\n\
123 ldw r4, %got(_rtld_local)(r22)\n\
124 ldw r4, 0(r4)\n\
125 ldw r8, %call(_dl_nios2_get_gp_value)(r22)\n\
126 callr r8\n\
127 mov gp, r2\n\
128 \n\
129 /* Find the number of arguments to skip. */\n\
130 ldw r8, %got(_dl_skip_args)(r22)\n\
131 ldw r8, 0(r8)\n\
132 \n\
133 /* Find the main_map from the GOT. */\n\
134 ldw r4, %got(_rtld_local)(r22)\n\
135 ldw r4, 0(r4)\n\
136 \n\
137 /* Find argc. */\n\
138 ldw r5, 0(sp)\n\
139 sub r5, r5, r8\n\
140 stw r5, 0(sp)\n\
141 \n\
142 /* Find the first unskipped argument. */\n\
143 slli r8, r8, 2\n\
144 addi r6, sp, 4\n\
145 add r9, r6, r8\n\
146 mov r10, r6\n\
147 \n\
148 /* Shuffle argv down. */\n\
149 3: ldw r11, 0(r9)\n\
150 stw r11, 0(r10)\n\
151 addi r9, r9, 4\n\
152 addi r10, r10, 4\n\
153 bne r11, zero, 3b\n\
154 \n\
155 /* Shuffle envp down. */\n\
156 mov r7, r10\n\
157 4: ldw r11, 0(r9)\n\
158 stw r11, 0(r10)\n\
159 addi r9, r9, 4\n\
160 addi r10, r10, 4\n\
161 bne r11, zero, 4b\n\
162 \n\
163 /* Shuffle auxv down. */\n\
164 5: ldw r11, 4(r9)\n\
165 stw r11, 4(r10)\n\
166 ldw r11, 0(r9)\n\
167 stw r11, 0(r10)\n\
168 addi r9, r9, 8\n\
169 addi r10, r10, 8\n\
170 bne r11, zero, 5b\n\
171 \n\
172 /* Update _dl_argv. */\n\
173 ldw r2, %got(_dl_argv)(r22)\n\
174 stw r6, 0(r2)\n\
175 \n\
176 /* Call _dl_init through the PLT. */\n\
177 ldw r8, %call(_dl_init)(r22)\n\
178 callr r8\n\
179 \n\
180 /* Find the finalization function. */\n\
181 ldw r4, %got(_dl_fini)(r22)\n\
182 \n\
183 /* Jump to the user's entry point. */\n\
184 jmp r16\n\
185 ");
186
187 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
188 PLT entries should not be allowed to define the value.
189 ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one
190 of the main executable's symbols, as for a COPY reloc. */
191 #define elf_machine_type_class(type) \
192 ((((type) == R_NIOS2_JUMP_SLOT \
193 || (type) == R_NIOS2_TLS_DTPMOD \
194 || (type) == R_NIOS2_TLS_DTPREL \
195 || (type) == R_NIOS2_TLS_TPREL) * ELF_RTYPE_CLASS_PLT) \
196 | (((type) == R_NIOS2_COPY) * ELF_RTYPE_CLASS_COPY) \
197 | (((type) == R_NIOS2_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA))
198
199 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
200 #define ELF_MACHINE_JMP_SLOT R_NIOS2_JUMP_SLOT
201
202 /* The Nios II never uses Elf32_Rel relocations. */
203 #define ELF_MACHINE_NO_REL 1
204 #define ELF_MACHINE_NO_RELA 0
205
206 /* Fixup a PLT entry to bounce directly to the function at VALUE. */
207
208 static inline Elf32_Addr
209 elf_machine_fixup_plt (struct link_map *map, lookup_t t,
210 const Elf32_Rela *reloc,
211 Elf32_Addr *reloc_addr, Elf32_Addr value)
212 {
213 return *reloc_addr = value;
214 }
215
216 /* Return the final value of a plt relocation. */
217 static inline Elf32_Addr
218 elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
219 Elf32_Addr value)
220 {
221 return value;
222 }
223
224 /* Names of the architecture-specific auditing callback functions. */
225 #define ARCH_LA_PLTENTER nios2_gnu_pltenter
226 #define ARCH_LA_PLTEXIT nios2_gnu_pltexit
227
228 #endif /* dl_machine_h */
229
230 #ifdef RESOLVE_MAP
231
232 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
233 LOADADDR is the load address of the object; INFO is an array indexed
234 by DT_* of the .dynamic section info. */
235
236 auto inline void __attribute__ ((always_inline))
237 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
238 const ElfW(Sym) *sym, const struct r_found_version *version,
239 void *const reloc_addr_arg, int skip_ifunc)
240 {
241 Elf32_Addr *const reloc_addr = reloc_addr_arg;
242 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
243
244 if (__glibc_unlikely (r_type == R_NIOS2_RELATIVE))
245 *reloc_addr = map->l_addr + reloc->r_addend;
246 else if (__glibc_unlikely (r_type == R_NIOS2_NONE))
247 return;
248 else
249 {
250 const Elf32_Sym *const refsym = sym;
251 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
252 Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
253
254 switch (r_type)
255 {
256 case R_NIOS2_COPY:
257 if (sym == NULL)
258 /* This can happen in trace mode if an object could not be
259 found. */
260 break;
261 if (sym->st_size > refsym->st_size
262 || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
263 {
264 const char *strtab;
265
266 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
267 _dl_error_printf ("\
268 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
269 rtld_progname ?: "<program name unknown>",
270 strtab + refsym->st_name);
271 }
272 memcpy (reloc_addr_arg, (void *) value,
273 MIN (sym->st_size, refsym->st_size));
274 break;
275 case R_NIOS2_GLOB_DAT:
276 case R_NIOS2_JUMP_SLOT:
277 # ifdef RTLD_BOOTSTRAP
278 /* Fix weak undefined references. */
279 if (sym != NULL && sym->st_value == 0)
280 *reloc_addr = 0;
281 else
282 # endif
283 *reloc_addr = value;
284 break;
285 #ifndef RTLD_BOOTSTRAP
286 case R_NIOS2_TLS_DTPMOD:
287 /* Get the information from the link map returned by the
288 resolv function. */
289 if (sym_map != NULL)
290 *reloc_addr = sym_map->l_tls_modid;
291 break;
292
293 case R_NIOS2_TLS_DTPREL:
294 *reloc_addr = reloc->r_addend + TLS_DTPREL_VALUE(sym);
295 break;
296
297 case R_NIOS2_TLS_TPREL:
298 if (sym != NULL)
299 {
300 CHECK_STATIC_TLS (map, sym_map);
301 *reloc_addr = reloc->r_addend + TLS_TPREL_VALUE(sym_map, sym);
302 }
303 break;
304 #endif
305 case R_NIOS2_BFD_RELOC_32:
306 *reloc_addr = value + reloc->r_addend;
307 break;
308
309 default:
310 _dl_reloc_bad_type (map, r_type, 0);
311 break;
312 }
313 }
314 }
315
316 auto inline void __attribute__((always_inline))
317 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
318 void *const reloc_addr_arg)
319 {
320 Elf32_Addr *const reloc_addr = reloc_addr_arg;
321 *reloc_addr = l_addr + reloc->r_addend;
322 }
323
324 auto inline void __attribute__((always_inline))
325 elf_machine_lazy_rel (struct link_map *map,
326 ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
327 int skip_ifunc)
328 {
329 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
330 if (ELF32_R_TYPE (reloc->r_info) == R_NIOS2_JUMP_SLOT)
331 *reloc_addr += l_addr;
332 else
333 _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1);
334 }
335
336 #endif /* RESOLVE_MAP */