OSDN Git Service

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