Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of glibc/sysdeps/nios2/dl-machine.h