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