1 /* Machine-dependent ELF dynamic relocation inline functions. OpenRISC version.
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
22 #define ELF_MACHINE_NAME "or1k"
24 #include <sys/cdefs.h>
25 #include <sys/param.h>
28 #include <dl-static-tls.h>
29 #include <dl-machine-rel.h>
31 /* Return nonzero iff ELF header is compatible with the running host. */
32 static inline int __attribute__ ((unused
))
33 elf_machine_matches_host (const Elf32_Ehdr
*ehdr
)
35 return ehdr
->e_machine
== EM_OPENRISC
;
38 static inline Elf32_Addr
*
44 " l.movhi %0, gotpchi(_GLOBAL_OFFSET_TABLE_-4)\n"
45 "l.ori %0, %0, gotpclo(_GLOBAL_OFFSET_TABLE_+0)\n"
47 : "=r" (got
) : : "r9");
52 /* Return the link-time address of _DYNAMIC. Conveniently, this is the
53 first element of the GOT. */
54 static inline Elf32_Addr
55 elf_machine_dynamic (void)
57 Elf32_Addr
*got
= or1k_get_got ();
62 /* Return the run-time load address of the shared object. */
63 static inline Elf32_Addr
64 elf_machine_load_address (void)
66 /* Compute the difference between the runtime address of _DYNAMIC as seen
67 by a GOTOFF reference, and the link-time address found in the special
68 unrelocated first GOT entry. */
70 Elf32_Addr
*got
= or1k_get_got ();
72 asm ("l.movhi %0, gotoffhi(_DYNAMIC);"
73 "l.ori %0, %0, gotofflo(_DYNAMIC);"
75 : "=&r"(dyn
) : "r"(got
));
80 /* Initial entry point code for the dynamic linker. The function _dl_start
81 is the real entry point; it's return value is the user program's entry
84 Code is really located in dl-start.S, just tell the linker that it
86 #define RTLD_START asm (".globl _dl_start");
88 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
89 TLS variable, so undefined references should not be allowed to
91 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
92 of the main executable's symbols, as for a COPY reloc. */
94 #define elf_machine_type_class(type) \
95 (((type) == R_OR1K_JMP_SLOT \
96 || (type) == R_OR1K_TLS_DTPMOD \
97 || (type) == R_OR1K_TLS_DTPOFF \
98 || (type) == R_OR1K_TLS_TPOFF) * ELF_RTYPE_CLASS_PLT \
99 | ((type) == R_OR1K_COPY) * ELF_RTYPE_CLASS_COPY)
101 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
102 #define ELF_MACHINE_JMP_SLOT R_OR1K_JMP_SLOT
104 #define ARCH_LA_PLTENTER or1k_gnu_pltenter
105 #define ARCH_LA_PLTEXIT or1k_gnu_pltexit
107 /* Set up the loaded object described by L so its unrelocated PLT
108 entries will jump to the on-demand fixup code in dl-runtime.c. */
109 static inline int __attribute__ ((unused
, always_inline
))
110 elf_machine_runtime_setup (struct link_map
*l
, struct r_scope_elem
*scope
[],
111 int lazy
, int profile
)
114 extern void _dl_runtime_resolve (ElfW(Word
));
115 extern void _dl_runtime_profile (ElfW(Word
));
117 if (l
->l_info
[DT_JMPREL
] && lazy
)
119 pltgot
= (ElfW(Addr
) *) D_PTR (l
, l_info
[DT_PLTGOT
]);
121 /* Fill in initial entries of the plt */
123 /* Register the link_map address in the plt at pltgot[1].
124 This will also be used in the resolver for accessing the
125 link_map structure. */
126 pltgot
[1] = (ElfW(Addr
)) l
;
128 /* This function will get called to fix up the GOT entry and
129 then jump to the resolved address. */
130 pltgot
[2] = (ElfW(Addr
)) &_dl_runtime_resolve
;
137 /* Mask identifying addresses reserved for the user program,
138 where the dynamic linker should not map anything. */
139 #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL
141 /* We define an initialization functions. This is called very early in
143 #define DL_PLATFORM_INIT dl_platform_init ()
145 static inline void __attribute__ ((unused
))
146 dl_platform_init (void)
148 if (GLRO(dl_platform
) != NULL
&& *GLRO(dl_platform
) == '\0')
149 /* Avoid an empty string which would disturb us. */
150 GLRO(dl_platform
) = NULL
;
153 static inline ElfW(Addr
)
154 elf_machine_fixup_plt (struct link_map
*map
, lookup_t t
,
155 const ElfW(Sym
) *refsym
, const ElfW(Sym
) *sym
,
156 const ElfW(Rela
) *reloc
,
157 ElfW(Addr
) *reloc_addr
, ElfW(Addr
) value
)
159 return *reloc_addr
= value
;
162 /* Return the final value of a plt relocation. */
163 static inline Elf32_Addr
164 elf_machine_plt_value (struct link_map
*map
, const Elf32_Rela
*reloc
,
167 return value
+ reloc
->r_addend
;
171 #endif /* !dl_machine_h */
175 /* Perform the relocation specified by RELOC and SYM (which is fully resolved).
176 MAP is the object containing the reloc. */
179 __attribute ((always_inline
))
180 elf_machine_rela (struct link_map
*map
, struct r_scope_elem
*scope
[],
181 const ElfW(Rela
) *reloc
, const ElfW(Sym
) *sym
,
182 const struct r_found_version
*version
,
183 void *const reloc_addr_arg
, int skip_ifunc
)
185 Elf32_Addr
*const reloc_addr
= reloc_addr_arg
;
186 const unsigned int r_type
= ELF32_R_TYPE (reloc
->r_info
);
188 if (__glibc_unlikely (r_type
== R_OR1K_NONE
))
192 const Elf32_Sym
*const refsym
= sym
;
193 struct link_map
*sym_map
= RESOLVE_MAP (map
, scope
, &sym
, version
,
195 Elf32_Addr value
= SYMBOL_ADDRESS (sym_map
, sym
, true);
198 && __glibc_unlikely (ELFW(ST_TYPE
) (sym
->st_info
) == STT_GNU_IFUNC
)
199 && __glibc_likely (sym
->st_shndx
!= SHN_UNDEF
)
200 && __glibc_likely (!skip_ifunc
))
201 value
= elf_ifunc_invoke (value
);
207 /* This can happen in trace mode if an object could not be
210 if (__glibc_unlikely (sym
->st_size
> refsym
->st_size
)
211 || (__glibc_unlikely (sym
->st_size
< refsym
->st_size
)
212 && GLRO(dl_verbose
)))
216 strtab
= (const char *) D_PTR (map
, l_info
[DT_STRTAB
]);
218 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
219 rtld_progname
?: "<program name unknown>",
220 strtab
+ refsym
->st_name
);
222 memcpy (reloc_addr_arg
, (void *) value
,
223 MIN (sym
->st_size
, refsym
->st_size
));
226 /* Support relocations on mis-aligned offsets. */
227 value
+= reloc
->r_addend
;
228 memcpy (reloc_addr_arg
, &value
, 4);
230 case R_OR1K_GLOB_DAT
:
231 case R_OR1K_JMP_SLOT
:
232 *reloc_addr
= value
+ reloc
->r_addend
;
234 case R_OR1K_TLS_DTPMOD
:
235 # ifdef RTLD_BOOTSTRAP
236 /* During startup the dynamic linker is always the module
241 *reloc_addr
= sym_map
->l_tls_modid
;
244 case R_OR1K_TLS_DTPOFF
:
245 # ifndef RTLD_BOOTSTRAP
246 *reloc_addr
= (sym
== NULL
? 0 : sym
->st_value
) + reloc
->r_addend
;
250 case R_OR1K_TLS_TPOFF
:
251 # ifdef RTLD_BOOTSTRAP
252 *reloc_addr
= sym
->st_value
+ reloc
->r_addend
+
253 map
->l_tls_offset
- TLS_TCB_SIZE
;
257 CHECK_STATIC_TLS (map
, sym_map
);
258 *reloc_addr
= sym
->st_value
+ reloc
->r_addend
+
259 sym_map
->l_tls_offset
- TLS_TCB_SIZE
;
264 _dl_reloc_bad_type (map
, r_type
, 0);
271 __attribute__ ((always_inline
))
272 elf_machine_rela_relative (Elf32_Addr l_addr
, const Elf32_Rela
*reloc
,
273 void *const reloc_addr_arg
)
275 Elf32_Addr
*const reloc_addr
= reloc_addr_arg
;
276 *reloc_addr
= l_addr
+ reloc
->r_addend
;
280 __attribute__ ((always_inline
))
281 elf_machine_lazy_rel (struct link_map
*map
, struct r_scope_elem
*scope
[],
282 ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
,
285 Elf32_Addr
*const reloc_addr
= (void *) (l_addr
+ reloc
->r_offset
);
286 const unsigned int r_type
= ELF32_R_TYPE (reloc
->r_info
);
288 if (__glibc_likely (r_type
== R_OR1K_JMP_SLOT
))
289 *reloc_addr
+= l_addr
;
290 else if (__glibc_unlikely (r_type
== R_OR1K_NONE
))
293 _dl_reloc_bad_type (map
, r_type
, 1);
296 #endif /* RESOLVE_MAP */