1 /* Machine-dependent ELF dynamic relocation inline functions. ARC version.
2 Copyright (C) 2020-2022 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 "arc"
27 # error ENTRY_POINT needs to be defined for ARC
33 #include <dl-static-tls.h>
34 #include <dl-machine-rel.h>
36 /* Dynamic Linking ABI for ARCv2 ISA.
39 -------------------------------- <---- DT_PLTGOT
40 | ld r11, [pcl, off-to-GOT[1] | 0
42 plt0 | ld r10, [pcl, off-to-GOT[2] | 8
45 --------------------------------
46 | Base address of GOT | 20
47 --------------------------------
48 | ld r12, [pcl, off-to-GOT[3] | 24
52 --------------------------------
57 --------------------------------
62 | ... | Runtime address for data symbols
68 | [0] | Build address of .dynamic
70 | [1] | Module info - setup by ld.so
72 | [2] | resolver entry point
75 | ... | Runtime address for function symbols
79 For ARCompact, the PLT is 12 bytes due to short instructions
81 --------------------------------
82 | ld r12, [pcl, off-to-GOT[3] | 24 (12 bytes each)
86 --------------------------------
89 /* Return nonzero iff ELF header is compatible with the running host. */
91 elf_machine_matches_host (const ElfW(Ehdr
) *ehdr
)
93 return (ehdr
->e_machine
== EM_ARCV2
/* ARC HS. */
94 || ehdr
->e_machine
== EM_ARC_COMPACT
); /* ARC 700. */
97 /* Get build time address of .dynamic as setup in GOT[0]
98 This is called very early in _dl_start so it has not been relocated to
100 static inline ElfW(Addr
)
101 elf_machine_dynamic (void)
103 extern const ElfW(Addr
) _GLOBAL_OFFSET_TABLE_
[] attribute_hidden
;
104 return _GLOBAL_OFFSET_TABLE_
[0];
108 /* Return the run-time load address of the shared object. */
109 static inline ElfW(Addr
)
110 elf_machine_load_address (void)
112 ElfW(Addr
) build_addr
, run_addr
;
114 /* For build address, below generates
115 ld r0, [pcl, _GLOBAL_OFFSET_TABLE_@pcl]. */
116 build_addr
= elf_machine_dynamic ();
117 __asm__ ("add %0, pcl, _DYNAMIC@pcl \n" : "=r" (run_addr
));
119 return run_addr
- build_addr
;
122 /* Set up the loaded object described by L so its unrelocated PLT
123 entries will jump to the on-demand fixup code in dl-runtime.c. */
126 __attribute__ ((always_inline
))
127 elf_machine_runtime_setup (struct link_map
*l
, struct r_scope_elem
*scope
[],
128 int lazy
, int profile
)
130 extern void _dl_runtime_resolve (void);
132 if (l
->l_info
[DT_JMPREL
] && lazy
)
134 /* On ARC DT_PLTGOT point to .plt whose 5th word (after the PLT header)
135 contains the address of .got. */
136 ElfW(Addr
) *plt_base
= (ElfW(Addr
) *) D_PTR (l
, l_info
[DT_PLTGOT
]);
137 ElfW(Addr
) *got
= (ElfW(Addr
) *) (plt_base
[5] + l
->l_addr
);
139 got
[1] = (ElfW(Addr
)) l
; /* Identify this shared object. */
141 /* This function will get called to fix up the GOT entry indicated by
142 the offset on the stack, and then jump to the resolved address. */
143 got
[2] = (ElfW(Addr
)) &_dl_runtime_resolve
;
149 /* What this code does:
150 -ldso starts execution here when kernel returns from execve
151 -calls into generic ldso entry point _dl_start
152 -optionally adjusts argc for executable if exec passed as cmd
153 -calls into app main with address of finaliser. */
155 #define RTLD_START asm ("\
158 .type __start, @function \n\
160 /* (1). bootstrap ld.so. */ \n\
162 mov_s r0, sp /* pass ptr to aux vector tbl. */ \n\
163 mov r13, r0 /* safekeep app elf entry point. */ \n\
164 ld_s r1, [sp] /* orig argc. */ \n\
166 /* (2). call preinit stuff. */ \n\
167 ld r0, [pcl, _rtld_local@pcl] \n\
168 add r2, sp, 4 ; argv \n\
170 add r3, r3, 4 ; env \n\
173 /* (3) call app elf entry point. */ \n\
174 add r0, pcl, _dl_fini@pcl \n\
177 .size __start,.-__start \n\
181 /* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
182 PLT entries should not be allowed to define the value.
183 ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
184 of the main executable's symbols, as for a COPY reloc. */
185 #define elf_machine_type_class(type) \
186 ((((type) == R_ARC_JMP_SLOT \
187 || (type) == R_ARC_TLS_DTPMOD \
188 || (type) == R_ARC_TLS_DTPOFF \
189 || (type) == R_ARC_TLS_TPOFF) * ELF_RTYPE_CLASS_PLT) \
190 | (((type) == R_ARC_COPY) * ELF_RTYPE_CLASS_COPY))
192 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
193 #define ELF_MACHINE_JMP_SLOT R_ARC_JMP_SLOT
195 /* Fixup a PLT entry to bounce directly to the function at VALUE. */
197 static inline ElfW(Addr
)
198 elf_machine_fixup_plt (struct link_map
*map
, lookup_t t
,
199 const ElfW(Sym
) *refsym
, const ElfW(Sym
) *sym
,
200 const ElfW(Rela
) *reloc
,
201 ElfW(Addr
) *reloc_addr
, ElfW(Addr
) value
)
203 return *reloc_addr
= value
;
206 /* Return the final value of a plt relocation. */
207 #define elf_machine_plt_value(map, reloc, value) (value)
209 /* Names of the architecture-specific auditing callback functions. */
210 #define ARCH_LA_PLTENTER arc_gnu_pltenter
211 #define ARCH_LA_PLTEXIT arc_gnu_pltexit
213 #endif /* dl_machine_h */
218 __attribute__ ((always_inline
))
219 elf_machine_rela (struct link_map
*map
, struct r_scope_elem
*scope
[],
220 const ElfW(Rela
) *reloc
, const ElfW(Sym
) *sym
,
221 const struct r_found_version
*version
,
222 void *const reloc_addr_arg
, int skip_ifunc
)
224 ElfW(Addr
) r_info
= reloc
->r_info
;
225 const unsigned long int r_type
= ELFW (R_TYPE
) (r_info
);
226 ElfW(Addr
) *const reloc_addr
= reloc_addr_arg
;
228 if (__glibc_unlikely (r_type
== R_ARC_RELATIVE
))
229 *reloc_addr
+= map
->l_addr
;
230 else if (__glibc_unlikely (r_type
== R_ARC_NONE
))
234 const ElfW(Sym
) *const refsym
= sym
;
235 struct link_map
*sym_map
= RESOLVE_MAP (map
, scope
, &sym
, version
,
237 ElfW(Addr
) value
= SYMBOL_ADDRESS (sym_map
, sym
, true);
242 if (__glibc_unlikely (sym
== NULL
))
243 /* This can happen in trace mode if an object could not be
247 size_t size
= sym
->st_size
;
248 if (__glibc_unlikely (size
!= refsym
->st_size
))
250 const char *strtab
= (const void *) D_PTR (map
, l_info
[DT_STRTAB
]);
251 if (sym
->st_size
> refsym
->st_size
)
252 size
= refsym
->st_size
;
253 if (sym
->st_size
> refsym
->st_size
|| GLRO(dl_verbose
))
255 %s: Symbol `%s' has different size in shared object, consider re-linking\n",
256 rtld_progname
?: "<program name unknown>",
257 strtab
+ refsym
->st_name
);
260 memcpy (reloc_addr_arg
, (void *) value
, size
);
268 case R_ARC_TLS_DTPMOD
:
270 /* Get the information from the link map returned by the
272 *reloc_addr
= sym_map
->l_tls_modid
;
275 case R_ARC_TLS_DTPOFF
:
277 /* Offset set by the linker in the GOT entry would be overwritten
278 by dynamic loader instead of added to the symbol location.
279 Other target have the same approach on DTPOFF relocs. */
280 *reloc_addr
+= sym
->st_value
;
283 case R_ARC_TLS_TPOFF
:
286 CHECK_STATIC_TLS (map
, sym_map
);
287 *reloc_addr
= sym_map
->l_tls_offset
+ sym
->st_value
+ reloc
->r_addend
;
292 *reloc_addr
+= value
+ reloc
->r_addend
;
296 *reloc_addr
+= value
+ reloc
->r_addend
- (unsigned long int) reloc_addr
;
300 _dl_reloc_bad_type (map
, r_type
, 0);
307 __attribute__ ((always_inline
))
308 elf_machine_rela_relative (ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
,
309 void *const reloc_addr_arg
)
311 ElfW(Addr
) *const reloc_addr
= reloc_addr_arg
;
312 *reloc_addr
+= l_addr
;
316 __attribute__ ((always_inline
))
317 elf_machine_lazy_rel (struct link_map
*map
, struct r_scope_elem
*scope
[],
318 ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
,
321 ElfW(Addr
) *const reloc_addr
= (void *) (l_addr
+ reloc
->r_offset
);
322 const unsigned int r_type
= ELFW (R_TYPE
) (reloc
->r_info
);
324 if (r_type
== R_ARC_JMP_SLOT
)
325 *reloc_addr
+= l_addr
;
327 _dl_reloc_bad_type (map
, r_type
, 1);
330 #endif /* RESOLVE_MAP */