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