Warning: This file is not a C or C++ file. It does not have highlighting.
1 | /* Copyright (C) 1995-2022 Free Software Foundation, Inc. |
---|---|
2 | |
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 License as |
7 | published by the Free Software Foundation; either version 2.1 of the |
8 | 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 "microblaze" |
23 | |
24 | #include <sys/param.h> |
25 | #include <tls.h> |
26 | #include <dl-static-tls.h> |
27 | #include <dl-machine-rel.h> |
28 | |
29 | /* Return nonzero iff ELF header is compatible with the running host. */ |
30 | static inline int |
31 | elf_machine_matches_host (const Elf32_Ehdr *ehdr) |
32 | { |
33 | return (ehdr->e_machine == EM_MICROBLAZE); |
34 | } |
35 | |
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 |
40 | elf_machine_dynamic (void) |
41 | { |
42 | /* This produces a GOTOFF reloc that resolves to zero at link time, so in |
43 | fact just loads from the GOT register directly. By doing it without |
44 | an asm we can let the compiler choose any register. */ |
45 | |
46 | Elf32_Addr got_entry_0; |
47 | __asm__ __volatile__( |
48 | "lwi %0,r20,0" |
49 | :"=r"(got_entry_0) |
50 | ); |
51 | return got_entry_0; |
52 | } |
53 | |
54 | /* Return the run-time load address of the shared object. */ |
55 | static inline Elf32_Addr |
56 | elf_machine_load_address (void) |
57 | { |
58 | /* Compute the difference between the runtime address of _DYNAMIC as seen |
59 | by a GOTOFF reference, and the link-time address found in the special |
60 | unrelocated first GOT entry. */ |
61 | |
62 | Elf32_Addr dyn; |
63 | __asm__ __volatile__ ( |
64 | "addik %0,r20,_DYNAMIC@GOTOFF" |
65 | : "=r"(dyn) |
66 | ); |
67 | return dyn - elf_machine_dynamic (); |
68 | } |
69 | |
70 | /* Set up the loaded object described by L so its unrelocated PLT |
71 | entries will jump to the on-demand fixup code in dl-runtime.c. */ |
72 | |
73 | static inline int __attribute__ ((always_inline)) |
74 | elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], |
75 | int lazy, int profile) |
76 | { |
77 | extern void _dl_runtime_resolve (Elf32_Word); |
78 | extern void _dl_runtime_profile (Elf32_Word); |
79 | |
80 | return lazy; |
81 | } |
82 | |
83 | /* The PLT uses Elf32_Rela relocs. */ |
84 | #define elf_machine_relplt elf_machine_rela |
85 | |
86 | /* Mask identifying addresses reserved for the user program, |
87 | where the dynamic linker should not map anything. */ |
88 | #define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL |
89 | |
90 | /* Initial entry point code for the dynamic linker. |
91 | The C function `_dl_start' is the real entry point; |
92 | its return value is the user program's entry point. */ |
93 | |
94 | #define RTLD_START asm ("\ |
95 | .text\n\ |
96 | .globl _start\n\ |
97 | .type _start,@function\n\ |
98 | _start:\n\ |
99 | addk r5,r0,r1\n\ |
100 | addk r3,r0,r0\n\ |
101 | 1:\n\ |
102 | addik r5,r5,4\n\ |
103 | lw r4,r5,r0\n\ |
104 | bneid r4,1b\n\ |
105 | addik r3,r3,1\n\ |
106 | addik r3,r3,-1\n\ |
107 | addk r5,r0,r1\n\ |
108 | sw r3,r5,r0\n\ |
109 | addik r1,r1,-24\n\ |
110 | sw r15,r1,r0\n\ |
111 | brlid r15,_dl_start\n\ |
112 | nop\n\ |
113 | /* FALLTHRU. */\n\ |
114 | \n\ |
115 | .globl _dl_start_user\n\ |
116 | .type _dl_start_user,@function\n\ |
117 | _dl_start_user:\n\ |
118 | mfs r20,rpc\n\ |
119 | addik r20,r20,_GLOBAL_OFFSET_TABLE_+8\n\ |
120 | lwi r4,r20,_dl_skip_args@GOTOFF\n\ |
121 | lwi r5,r1,24\n\ |
122 | rsubk r5,r4,r5\n\ |
123 | addk r4,r4,r4\n\ |
124 | addk r4,r4,r4\n\ |
125 | addk r1,r1,r4\n\ |
126 | swi r5,r1,24\n\ |
127 | swi r3,r1,20\n\ |
128 | addk r6,r5,r0\n\ |
129 | addk r5,r5,r5\n\ |
130 | addk r5,r5,r5\n\ |
131 | addik r7,r1,28\n\ |
132 | addk r8,r7,r5\n\ |
133 | addik r8,r8,4\n\ |
134 | lwi r5,r20,_rtld_local@GOTOFF\n\ |
135 | brlid r15,_dl_init\n\ |
136 | nop\n\ |
137 | lwi r5,r1,24\n\ |
138 | lwi r3,r1,20\n\ |
139 | addk r4,r5,r5\n\ |
140 | addk r4,r4,r4\n\ |
141 | addik r6,r1,28\n\ |
142 | addk r7,r6,r4\n\ |
143 | addik r7,r7,4\n\ |
144 | addik r15,r20,_dl_fini@GOTOFF\n\ |
145 | addik r15,r15,-8\n\ |
146 | brad r3\n\ |
147 | addik r1,r1,24\n\ |
148 | nop\n\ |
149 | .size _dl_start_user, . - _dl_start_user\n\ |
150 | .previous"); |
151 | |
152 | /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or |
153 | TLS variable, so undefined references should not be allowed to |
154 | define the value. |
155 | ELF_RTYPE_CLASS_COPY iff TYPE should not be allowed to resolve to one |
156 | of the main executable's symbols, as for a COPY reloc. */ |
157 | #ifndef RTLD_BOOTSTRAP |
158 | # define elf_machine_type_class(type) \ |
159 | (((type) == R_MICROBLAZE_JUMP_SLOT \ |
160 | || (type) == R_MICROBLAZE_TLSDTPREL32 \ |
161 | || (type) == R_MICROBLAZE_TLSDTPMOD32 \ |
162 | || (type) == R_MICROBLAZE_TLSTPREL32) \ |
163 | * ELF_RTYPE_CLASS_PLT \ |
164 | | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY) |
165 | #else |
166 | # define elf_machine_type_class(type) \ |
167 | (((type) == R_MICROBLAZE_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT \ |
168 | | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY) |
169 | #endif |
170 | |
171 | /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */ |
172 | #define ELF_MACHINE_JMP_SLOT R_MICROBLAZE_JUMP_SLOT |
173 | |
174 | static inline Elf32_Addr |
175 | elf_machine_fixup_plt (struct link_map *map, lookup_t t, |
176 | const ElfW(Sym) *refsym, const ElfW(Sym) *sym, |
177 | const Elf32_Rela *reloc, |
178 | Elf32_Addr *reloc_addr, Elf32_Addr value) |
179 | { |
180 | return *reloc_addr = value; |
181 | } |
182 | |
183 | /* Return the final value of a plt relocation. Ignore the addend. */ |
184 | static inline Elf32_Addr |
185 | elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc, |
186 | Elf32_Addr value) |
187 | { |
188 | return value; |
189 | } |
190 | |
191 | #endif /* !dl_machine_h. */ |
192 | |
193 | /* Names of the architecture-specific auditing callback functions. */ |
194 | #define ARCH_LA_PLTENTER microblaze_gnu_pltenter |
195 | #define ARCH_LA_PLTEXIT microblaze_gnu_pltexit |
196 | |
197 | #ifdef RESOLVE_MAP |
198 | |
199 | /* Perform the relocation specified by RELOC and SYM (which is fully resolved). |
200 | MAP is the object containing the reloc. */ |
201 | |
202 | /* Macro to put 32-bit relocation value into 2 words. */ |
203 | #define PUT_REL_64(rel_addr,val) \ |
204 | do { \ |
205 | ((unsigned short *)(rel_addr))[1] = (val) >> 16; \ |
206 | ((unsigned short *)(rel_addr))[3] = (val) & 0xffff; \ |
207 | } while (0) |
208 | |
209 | static inline void __attribute__ ((always_inline)) |
210 | elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], |
211 | const Elf32_Rela *reloc, const Elf32_Sym *sym, |
212 | const struct r_found_version *version, |
213 | void *const reloc_addr_arg, int skip_ifunc) |
214 | { |
215 | Elf32_Addr *const reloc_addr = reloc_addr_arg; |
216 | const int r_type = ELF32_R_TYPE (reloc->r_info); |
217 | |
218 | if (__builtin_expect (r_type == R_MICROBLAZE_64_PCREL, 0)) |
219 | PUT_REL_64 (reloc_addr, map->l_addr + reloc->r_addend); |
220 | else if (r_type == R_MICROBLAZE_REL) |
221 | *reloc_addr = map->l_addr + reloc->r_addend; |
222 | else |
223 | { |
224 | const Elf32_Sym *const refsym = sym; |
225 | struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, |
226 | r_type); |
227 | Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true); |
228 | |
229 | value += reloc->r_addend; |
230 | if (r_type == R_MICROBLAZE_GLOB_DAT |
231 | || r_type == R_MICROBLAZE_JUMP_SLOT |
232 | || r_type == R_MICROBLAZE_32) |
233 | { |
234 | *reloc_addr = value; |
235 | } |
236 | else if (r_type == R_MICROBLAZE_COPY) |
237 | { |
238 | if (sym != NULL && (sym->st_size > refsym->st_size |
239 | || (sym->st_size < refsym->st_size && GLRO (dl_verbose))) ) |
240 | { |
241 | const char *strtab; |
242 | |
243 | strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); |
244 | _dl_error_printf ("\ |
245 | %s: Symbol `%s' has different size in shared object, consider re-linking\n", |
246 | RTLD_PROGNAME, strtab + refsym->st_name); |
247 | } |
248 | memcpy (reloc_addr_arg, (void *) value, |
249 | MIN (sym->st_size, refsym->st_size)); |
250 | } |
251 | else if (r_type == R_MICROBLAZE_NONE) |
252 | { |
253 | } |
254 | #if !defined RTLD_BOOTSTRAP |
255 | else if (r_type == R_MICROBLAZE_TLSDTPMOD32) |
256 | { |
257 | if (sym_map != NULL) |
258 | *reloc_addr = sym_map->l_tls_modid; |
259 | } |
260 | else if (r_type == R_MICROBLAZE_TLSDTPREL32) |
261 | { |
262 | if (sym != NULL) |
263 | *reloc_addr = sym->st_value + reloc->r_addend; |
264 | } |
265 | else if (r_type == R_MICROBLAZE_TLSTPREL32) |
266 | { |
267 | if (sym != NULL) |
268 | { |
269 | CHECK_STATIC_TLS (map, sym_map); |
270 | *reloc_addr = sym->st_value + sym_map->l_tls_offset + reloc->r_addend; |
271 | } |
272 | } |
273 | #endif |
274 | else |
275 | { |
276 | _dl_reloc_bad_type (map, r_type, 0); |
277 | } |
278 | } |
279 | } |
280 | |
281 | static inline void |
282 | elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc, |
283 | void *const reloc_addr_arg) |
284 | { |
285 | Elf32_Addr *const reloc_addr = reloc_addr_arg; |
286 | PUT_REL_64 (reloc_addr, l_addr + reloc->r_addend); |
287 | } |
288 | |
289 | static inline void |
290 | elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], |
291 | Elf32_Addr l_addr, const Elf32_Rela *reloc, |
292 | int skip_ifunc) |
293 | { |
294 | Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset); |
295 | if (ELF32_R_TYPE (reloc->r_info) == R_MICROBLAZE_JUMP_SLOT) |
296 | *reloc_addr += l_addr; |
297 | else |
298 | _dl_reloc_bad_type (map, ELF32_R_TYPE (reloc->r_info), 1); |
299 | } |
300 | |
301 | #endif /* RESOLVE_MAP. */ |
302 |
Warning: This file is not a C or C++ file. It does not have highlighting.