blob: 29d1a007f5e298bedb4e5b0c67bdbee80664be51 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2000-2005 by Erik Andersen <andersen@codepoet.org>
4 *
5 * GNU Lesser General Public License version 2.1 or later.
6 */
7
8#ifndef LINUXELF_H
9#define LINUXELF_H
10
11#include <dl-string.h> /* before elf.h to get ELF_USES_RELOCA right */
12#include <elf.h>
13#include <link.h>
14
15/* Forward declarations for stuff defined in ld_hash.h */
16struct dyn_elf;
17struct elf_resolve;
18struct r_scope_elem;
19
20#include <dl-defs.h>
21#ifdef __LDSO_CACHE_SUPPORT__
22extern int _dl_map_cache(void);
23extern int _dl_unmap_cache(void);
24#else
25static __inline__ void _dl_map_cache(void) { }
26static __inline__ void _dl_unmap_cache(void) { }
27#endif
28
29#define DL_RESOLVE_SECURE 0x0001
30#define DL_RESOLVE_NOLOAD 0x0002
31
32/* Function prototypes for non-static stuff in readelflib1.c */
33extern void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
34 unsigned long rel_addr, unsigned long rel_size);
35extern int _dl_parse_relocation_information(struct dyn_elf *rpnt,
36 struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size);
37extern struct elf_resolve * _dl_load_shared_library(unsigned rflags,
38 struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname,
39 int trace_loaded_objects);
40extern struct elf_resolve * _dl_load_elf_shared_library(unsigned rflags,
41 struct dyn_elf **rpnt, const char *libname);
42extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname,
43 int trace_loaded_objects);
44extern int _dl_linux_resolve(void);
45extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int flag);
46extern void _dl_protect_relro (struct elf_resolve *l);
47
48/*
49 * Bitsize related settings for things ElfW()
50 * does not handle already
51 */
52#if __WORDSIZE == 64
53# define ELF_ST_BIND(val) ELF64_ST_BIND(val)
54# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val)
55# define ELF_R_SYM(i) ELF64_R_SYM(i)
56# define ELF_R_TYPE(i) ELF64_R_TYPE(i)
57# ifndef ELF_CLASS
58# define ELF_CLASS ELFCLASS64
59# endif
60#else
61# define ELF_ST_BIND(val) ELF32_ST_BIND(val)
62# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val)
63# define ELF_R_SYM(i) ELF32_R_SYM(i)
64# define ELF_R_TYPE(i) ELF32_R_TYPE(i)
65# ifndef ELF_CLASS
66# define ELF_CLASS ELFCLASS32
67# endif
68#endif
69
70/*
71 * Datatype of a relocation on this platform
72 */
73#ifdef ELF_USES_RELOCA
74# define ELF_RELOC ElfW(Rela)
75# define DT_RELOC_TABLE_ADDR DT_RELA
76# define DT_RELOC_TABLE_SIZE DT_RELASZ
77# define DT_RELOCCOUNT DT_RELACOUNT
78# define UNSUPPORTED_RELOC_TYPE DT_REL
79# define UNSUPPORTED_RELOC_STR "REL"
80#else
81# define ELF_RELOC ElfW(Rel)
82# define DT_RELOC_TABLE_ADDR DT_REL
83# define DT_RELOC_TABLE_SIZE DT_RELSZ
84# define DT_RELOCCOUNT DT_RELCOUNT
85# define UNSUPPORTED_RELOC_TYPE DT_RELA
86# define UNSUPPORTED_RELOC_STR "RELA"
87#endif
88
89/* OS and/or GNU dynamic extensions */
90
91#define OS_NUM_BASE 1 /* for DT_RELOCCOUNT */
92
93#ifdef __LDSO_GNU_HASH_SUPPORT__
94# define OS_NUM_GNU_HASH 1 /* for DT_GNU_HASH entry */
95#else
96# define OS_NUM_GNU_HASH 0
97#endif
98
99#ifdef __LDSO_PRELINK_SUPPORT__
100# define OS_NUM_PRELINK 6 /* for DT_GNU_PRELINKED entry */
101#else
102# define OS_NUM_PRELINK 0
103#endif
104
105#define OS_NUM (OS_NUM_BASE + OS_NUM_GNU_HASH + OS_NUM_PRELINK)
106
107#ifndef ARCH_DYNAMIC_INFO
108 /* define in arch specific code, if needed */
109# define ARCH_NUM 0
110#endif
111
112#define DYNAMIC_SIZE (DT_NUM + OS_NUM + ARCH_NUM)
113/* Keep ARCH specific entries into dynamic section at the end of the array */
114#define DT_RELCONT_IDX (DYNAMIC_SIZE - OS_NUM - ARCH_NUM)
115
116#ifdef __LDSO_GNU_HASH_SUPPORT__
117/* GNU hash comes just after the relocation count */
118# define DT_GNU_HASH_IDX (DT_RELCONT_IDX + 1)
119#else
120# define DT_GNU_HASH_IDX DT_RELCONT_IDX
121#endif
122
123#ifdef __LDSO_PRELINK_SUPPORT__
124/* GNU prelink comes just after the GNU hash if present */
125#define DT_GNU_PRELINKED_IDX (DT_GNU_HASH_IDX + 1)
126#define DT_GNU_CONFLICT_IDX (DT_GNU_HASH_IDX + 2)
127#define DT_GNU_CONFLICTSZ_IDX (DT_GNU_HASH_IDX + 3)
128#define DT_GNU_LIBLIST_IDX (DT_GNU_HASH_IDX + 4)
129#define DT_GNU_LIBLISTSZ_IDX (DT_GNU_HASH_IDX + 5)
130#define DT_CHECKSUM_IDX (DT_GNU_HASH_IDX + 6)
131#endif
132
133extern unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
134 void *debug_addr, DL_LOADADDR_TYPE load_off);
135
136static __always_inline
137unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
138 void *debug_addr, DL_LOADADDR_TYPE load_off)
139{
140 unsigned int rtld_flags = 0;
141
142 for (; dpnt->d_tag; dpnt++) {
143 if (dpnt->d_tag < DT_NUM) {
144 dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
145#ifndef __mips__
146 /* we disable for mips because normally this page is readonly
147 * and modifying the value here needlessly dirties a page.
148 * see this post for more info:
149 * http://uclibc.org/lists/uclibc/2006-April/015224.html */
150 if (dpnt->d_tag == DT_DEBUG)
151 dpnt->d_un.d_val = (unsigned long)debug_addr;
152#endif
153 if (dpnt->d_tag == DT_BIND_NOW)
154 dynamic_info[DT_BIND_NOW] = 1;
155 if (dpnt->d_tag == DT_FLAGS &&
156 (dpnt->d_un.d_val & DF_BIND_NOW))
157 dynamic_info[DT_BIND_NOW] = 1;
158 if (dpnt->d_tag == DT_TEXTREL)
159 dynamic_info[DT_TEXTREL] = 1;
160#ifdef __LDSO_RUNPATH__
161 if (dpnt->d_tag == DT_RUNPATH)
162 dynamic_info[DT_RPATH] = 0;
163 if (dpnt->d_tag == DT_RPATH && dynamic_info[DT_RUNPATH])
164 dynamic_info[DT_RPATH] = 0;
165#endif
166 } else if (dpnt->d_tag < DT_LOPROC) {
167 if (dpnt->d_tag == DT_RELOCCOUNT)
168 dynamic_info[DT_RELCONT_IDX] = dpnt->d_un.d_val;
169 if (dpnt->d_tag == DT_FLAGS_1) {
170 if (dpnt->d_un.d_val & DF_1_NOW)
171 dynamic_info[DT_BIND_NOW] = 1;
172 if (dpnt->d_un.d_val & DF_1_NODELETE)
173 rtld_flags |= RTLD_NODELETE;
174 }
175#ifdef __LDSO_GNU_HASH_SUPPORT__
176 if (dpnt->d_tag == DT_GNU_HASH)
177 dynamic_info[DT_GNU_HASH_IDX] = dpnt->d_un.d_ptr;
178#endif
179#ifdef __LDSO_PRELINK_SUPPORT__
180 if (dpnt->d_tag == DT_GNU_PRELINKED)
181 dynamic_info[DT_GNU_PRELINKED_IDX] = dpnt->d_un.d_val;
182 if (dpnt->d_tag == DT_GNU_CONFLICT)
183 dynamic_info[DT_GNU_CONFLICT_IDX] = dpnt->d_un.d_ptr;
184 if (dpnt->d_tag == DT_GNU_CONFLICTSZ)
185 dynamic_info[DT_GNU_CONFLICTSZ_IDX] = dpnt->d_un.d_val;
186 if (dpnt->d_tag == DT_GNU_LIBLIST)
187 dynamic_info[DT_GNU_LIBLIST_IDX] = dpnt->d_un.d_ptr;
188 if (dpnt->d_tag == DT_GNU_LIBLISTSZ)
189 dynamic_info[DT_GNU_LIBLISTSZ_IDX] = dpnt->d_un.d_val;
190 if (dpnt->d_tag == DT_CHECKSUM)
191 dynamic_info[DT_CHECKSUM_IDX] = dpnt->d_un.d_val;
192#endif
193 }
194#ifdef ARCH_DYNAMIC_INFO
195 else {
196 ARCH_DYNAMIC_INFO(dpnt, dynamic_info, debug_addr);
197 }
198#endif
199 }
200#define ADJUST_DYN_INFO(tag, load_off) \
201 do { \
202 if (dynamic_info[tag]) \
203 dynamic_info[tag] = (unsigned long) DL_RELOC_ADDR(load_off, dynamic_info[tag]); \
204 } while (0)
205 /* Don't adjust .dynamic unnecessarily. For FDPIC targets,
206 we'd have to walk all the loadsegs to find out if it was
207 actually unnecessary, so skip this optimization. */
208#if !defined __FDPIC__ && !defined __DSBT__
209 if (load_off != 0)
210#endif
211 {
212 ADJUST_DYN_INFO(DT_HASH, load_off);
213 ADJUST_DYN_INFO(DT_PLTGOT, load_off);
214 ADJUST_DYN_INFO(DT_STRTAB, load_off);
215 ADJUST_DYN_INFO(DT_SYMTAB, load_off);
216 ADJUST_DYN_INFO(DT_RELOC_TABLE_ADDR, load_off);
217 ADJUST_DYN_INFO(DT_JMPREL, load_off);
218#ifdef __LDSO_GNU_HASH_SUPPORT__
219 ADJUST_DYN_INFO(DT_GNU_HASH_IDX, load_off);
220#endif
221 }
222#ifdef __DSBT__
223 /* Get the mapped address of the DSBT base. */
224 ADJUST_DYN_INFO(DT_DSBT_BASE_IDX, load_off);
225
226 /* Initialize loadmap dsbt info. */
227 load_off.map->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX];
228 load_off.map->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX];
229 load_off.map->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX];
230#endif
231#undef ADJUST_DYN_INFO
232 return rtld_flags;
233}
234
235/* Reloc type classes as returned by elf_machine_type_class().
236 ELF_RTYPE_CLASS_PLT means this reloc should not be satisfied by
237 some PLT symbol, ELF_RTYPE_CLASS_COPY means this reloc should not be
238 satisfied by any symbol in the executable. Some architectures do
239 not support copy relocations. In this case we define the macro to
240 zero so that the code for handling them gets automatically optimized
241 out. */
242#ifdef DL_NO_COPY_RELOCS
243# define ELF_RTYPE_CLASS_COPY (0x0)
244#else
245# define ELF_RTYPE_CLASS_COPY (0x2)
246#endif
247#define ELF_RTYPE_CLASS_PLT (0x1)
248
249/* dlsym() calls _dl_find_hash with this value, that enables
250 DL_FIND_HASH_VALUE to return something different than the symbol
251 itself, e.g., a function descriptor. */
252#define ELF_RTYPE_CLASS_DLSYM 0x80000000
253
254
255/* Convert between the Linux flags for page protections and the
256 ones specified in the ELF standard. */
257#define LXFLAGS(X) ( (((X) & PF_R) ? PROT_READ : 0) | \
258 (((X) & PF_W) ? PROT_WRITE : 0) | \
259 (((X) & PF_X) ? PROT_EXEC : 0))
260
261
262#endif /* LINUXELF_H */