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

1/* Machine-dependent ELF dynamic relocation inline functions. C-SKY version.
2 Copyright (C) 2018-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 "csky"
23
24#include <sys/param.h>
25#include <sysdep.h>
26#include <dl-tls.h>
27#include <dl-static-tls.h>
28#include <dl-machine-rel.h>
29
30/* Return nonzero if 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_CSKY;
35}
36
37/* Return the link-time address of _DYNAMIC.
38 This must be inlined in a function which uses global data. */
39static inline Elf32_Addr
40elf_machine_dynamic (void)
41{
42 register Elf32_Addr *got __asm__ ("gb");
43 return *got;
44}
45
46/* Return the run-time load address ,of the shared object. */
47static inline Elf32_Addr
48elf_machine_load_address (void)
49{
50 extern Elf32_Addr __dl_start (void *) asm ("_dl_start");
51 Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
52 Elf32_Addr pcrel_addr;
53 asm ("grs %0,_dl_start\n" : "=r" (pcrel_addr));
54
55 return pcrel_addr - got_addr;
56}
57
58
59/* Set up the loaded object described by L so its unrelocated PLT
60 entries will jump to the on-demand fixup code in dl-runtime.c. */
61
62static inline int __attribute__ ((always_inline))
63elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
64 int lazy, int profile)
65{
66 Elf32_Addr *got;
67 extern void _dl_runtime_resolve (Elf32_Word);
68
69 if (l->l_info[DT_JMPREL] && lazy)
70 {
71 /* The GOT entries for functions in the PLT have not yet been
72 filled in. Their initial contents will arrange when called
73 to push an offset into the .rela.plt section, push
74 _GLOBAL_OFFSET_TABLE_[1], and then jump to
75 _GLOBAL_OFFSET_TABLE_[2]. */
76 got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
77
78 if (got[1])
79 l->l_mach.plt = got[1] + l->l_addr;
80 got[1] = (Elf32_Addr) l; /* Identify this shared object. */
81
82 /* The got[2] entry contains the address of a function which gets
83 called to get the address of a so far unresolved function and
84 jump to it. The profiling extension of the dynamic linker allows
85 to intercept the calls to collect information. In this case we
86 don't store the address in the GOT so that all future calls also
87 end in this function. */
88 got[2] = (Elf32_Addr) &_dl_runtime_resolve;
89 }
90 return lazy;
91}
92
93/* Mask identifying addresses reserved for the user program,
94 where the dynamic linker should not map anything. */
95#define ELF_MACHINE_USER_ADDRESS_MASK 0x80000000UL
96
97/* Initial entry point code for the dynamic linker.
98 The C function `_dl_start' is the real entry point;
99 its return value is the user program's entry point. */
100#define RTLD_START asm ("\
101.text\n\
102.globl _start\n\
103.type _start, @function\n\
104.globl _dl_start_user\n\
105.type _dl_start_user, @function\n\
106_start:\n\
107 grs gb, .Lgetpc1\n\
108.Lgetpc1:\n\
109 lrw t0, .Lgetpc1@GOTPC\n\
110 addu gb, t0\n\
111 mov a0, sp\n\
112 lrw t1, _dl_start@GOTOFF\n\
113 addu t1, gb\n\
114 jsr t1\n\
115_dl_start_user:\n\
116 /* get _dl_skip_args */ \n\
117 lrw r11, _dl_skip_args@GOTOFF\n\
118 addu r11, gb\n\
119 ldw r11, (r11, 0)\n\
120 /* store program entry address in r11 */ \n\
121 mov r10, a0\n\
122 /* Get argc */\n\
123 ldw a1, (sp, 0)\n\
124 /* Get **argv */\n\
125 mov a2, sp\n\
126 addi a2, 4\n\
127 cmpnei r11, 0\n\
128 bt .L_fixup_stack\n\
129.L_done_fixup:\n\
130 mov a3, a1\n\
131 lsli a3, 2\n\
132 add a3, a2\n\
133 addi a3, 4\n\
134 lrw a0, _rtld_local@GOTOFF\n\
135 addu a0, gb\n\
136 ldw a0, (a0, 0)\n\
137 lrw t1, _dl_init@PLT\n\
138 addu t1, gb\n\
139 ldw t1, (t1)\n\
140 jsr t1\n\
141 lrw a0, _dl_fini@GOTOFF\n\
142 addu a0, gb\n\
143 jmp r10\n\
144.L_fixup_stack:\n\
145 subu a1, r11\n\
146 lsli r11, 2\n\
147 addu sp, r11\n\
148 stw a1, (sp, 0)\n\
149 mov a2, sp\n\
150 addi a2, 4\n\
151 lrw a3, _dl_argv@GOTOFF\n\
152 addu a3, gb\n\
153 stw a2, (a3, 0)\n\
154 br .L_done_fixup\n\
155");
156
157/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
158 TLS variable, so undefined references should not be allowed to
159 define the value.
160 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
161 of the main executable's symbols, as for a COPY reloc. */
162#ifndef RTLD_BOOTSTRAP
163# define elf_machine_type_class(type) \
164 ((((type) == R_CKCORE_JUMP_SLOT || (type) == R_CKCORE_TLS_DTPMOD32 \
165 || (type) == R_CKCORE_TLS_DTPOFF32 || (type) == R_CKCORE_TLS_TPOFF32) \
166 * ELF_RTYPE_CLASS_PLT) \
167 | (((type) == R_CKCORE_COPY) * ELF_RTYPE_CLASS_COPY))
168#else
169# define elf_machine_type_class(type) \
170 ((((type) == R_CKCORE_JUMP_SLOT \
171 | (((type) == R_CKCORE_COPY) * ELF_RTYPE_CLASS_COPY))
172#endif
173
174/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
175#define ELF_MACHINE_JMP_SLOT R_CKCORE_JUMP_SLOT
176
177/* We define an initialization functions. This is called very early in
178 _dl_sysdep_start. */
179#define DL_PLATFORM_INIT dl_platform_init ()
180
181static inline void __attribute__ ((unused))
182dl_platform_init (void)
183{
184 if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
185 /* Avoid an empty string which would disturb us. */
186 GLRO(dl_platform) = NULL;
187}
188
189static inline Elf32_Addr
190elf_machine_fixup_plt (struct link_map *map, lookup_t t,
191 const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
192 const Elf32_Rela *reloc,
193 Elf32_Addr *reloc_addr, Elf32_Addr value)
194{
195 return *reloc_addr = value;
196}
197
198/* Return the final value of a plt relocation. On the csky the JMP_SLOT
199 relocation ignores the addend. */
200static inline Elf32_Addr
201elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
202 Elf32_Addr value)
203{
204 return value;
205}
206
207/* Names of the architecture-specific auditing callback functions. */
208#define ARCH_LA_PLTENTER csky_gnu_pltenter
209#define ARCH_LA_PLTEXIT csky_gnu_pltexit
210
211#endif /* !dl_machine_h */
212#ifdef RESOLVE_MAP
213
214/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
215 MAP is the object containing the reloc. */
216
217static inline void __attribute__ ((unused, always_inline))
218elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
219 const Elf32_Rela *reloc, const Elf32_Sym *sym,
220 const struct r_found_version *version,
221 void *const reloc_addr_arg, int skip_ifunc)
222{
223 Elf32_Addr *const reloc_addr = reloc_addr_arg;
224 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
225 unsigned short __attribute__ ((unused)) *opcode16_addr;
226 Elf32_Addr __attribute__ ((unused)) insn_opcode = 0x0;
227
228 if (__builtin_expect (r_type == R_CKCORE_RELATIVE, 0))
229 *reloc_addr = map->l_addr + reloc->r_addend;
230 else
231 {
232 const Elf32_Sym *const refsym = sym;
233 struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
234 r_type);
235 ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true);
236 opcode16_addr = (unsigned short *)reloc_addr;
237
238 switch (r_type)
239 {
240 case R_CKCORE_COPY:
241 if (sym == NULL)
242 /* This can happen in trace mode if an object could not be
243 found. */
244 break;
245 if (sym->st_size > refsym->st_size
246 || (sym->st_size < refsym->st_size && GLRO(dl_verbose)))
247 {
248 const char *strtab;
249
250 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
251 _dl_error_printf ("\
252%s: Symbol `%s' has different size in shared object, consider re-linking\n",
253 rtld_progname ?: "<program name unknown>",
254 strtab + refsym->st_name);
255 }
256 memcpy (reloc_addr_arg, (void *) value,
257 MIN (sym->st_size, refsym->st_size));
258 break;
259 case R_CKCORE_GLOB_DAT:
260 case R_CKCORE_JUMP_SLOT:
261 *reloc_addr = value;
262 break;
263 case R_CKCORE_ADDR32:
264 *reloc_addr = value + reloc->r_addend;
265 break;
266 case R_CKCORE_PCREL32:
267 *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
268 break;
269#if defined(__CK810__) || defined(__CK807__)
270 case R_CKCORE_ADDR_HI16:
271 insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
272 insn_opcode = (insn_opcode & 0xffff0000)
273 | (((value + reloc->r_addend) >> 16) & 0xffff);
274 *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
275 *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
276 break;
277 case R_CKCORE_ADDR_LO16:
278 insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
279 insn_opcode = (insn_opcode & 0xffff0000)
280 | ((value + reloc->r_addend) & 0xffff);
281 *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
282 *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
283 break;
284 case R_CKCORE_PCREL_IMM26BY2:
285 {
286 unsigned int offset = ((value + reloc->r_addend
287 - (unsigned int)reloc_addr) >> 1);
288 insn_opcode = (*opcode16_addr << 16) | (*(opcode16_addr + 1));
289 if (offset > 0x3ffffff){
290 const char *strtab;
291 strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
292
293 _dl_error_printf ("\
294%s:The reloc R_CKCORE_PCREL_IMM26BY2 cannot reach the symbol '%s'.\n",
295 rtld_progname ?: "<program name unknown>",
296 strtab + refsym->st_name);
297 break;
298 }
299 insn_opcode = (insn_opcode & ~0x3ffffff) | offset;
300 *(opcode16_addr++) = (unsigned short)(insn_opcode >> 16);
301 *opcode16_addr = (unsigned short)(insn_opcode & 0xffff);
302 break;
303 }
304 case R_CKCORE_PCREL_JSR_IMM26BY2:
305 break;
306#endif
307#ifndef RTLD_BOOTSTRAP
308 case R_CKCORE_TLS_DTPMOD32:
309 /* Get the information from the link map returned by the
310 resolv function. */
311 if (sym_map != NULL)
312 *reloc_addr = sym_map->l_tls_modid;
313 break;
314 case R_CKCORE_TLS_DTPOFF32:
315 if (sym != NULL)
316 *reloc_addr =(sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
317 break;
318 case R_CKCORE_TLS_TPOFF32:
319 if (sym != NULL)
320 {
321 CHECK_STATIC_TLS (map, sym_map);
322 *reloc_addr = (sym->st_value + sym_map->l_tls_offset
323 + reloc->r_addend);
324 }
325 break;
326#endif /* !RTLD_BOOTSTRAP */
327 case R_CKCORE_NONE:
328 break;
329 default:
330 break;
331 }
332 }
333}
334
335static inline void __attribute__ ((unused, always_inline))
336elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
337 void *const reloc_addr_arg)
338{
339 Elf32_Addr *const reloc_addr = reloc_addr_arg;
340 *reloc_addr = l_addr + reloc->r_addend;
341}
342
343static inline void __attribute__ ((unused, always_inline))
344elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
345 Elf32_Addr l_addr, const Elf32_Rela *reloc,
346 int skip_ifunc)
347{
348 Elf32_Addr *const reloc_addr = (void *) (l_addr + reloc->r_offset);
349 const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
350 if (ELF32_R_TYPE (reloc->r_info) == R_CKCORE_JUMP_SLOT)
351 {
352 /* Check for unexpected PLT reloc type. */
353 if (__builtin_expect (r_type == R_CKCORE_JUMP_SLOT, 1))
354 {
355 if (__builtin_expect (map->l_mach.plt, 0) == 0)
356 *reloc_addr = l_addr + reloc->r_addend;
357 else
358 *reloc_addr = map->l_mach.plt;
359 }
360 }
361}
362
363#endif /* RESOLVE_MAP */
364

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

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