OSDN Git Service

Merge remote-tracking branch 'origin/master' into prelink
[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 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 */
16 struct dyn_elf;
17 struct elf_resolve;
18 struct r_scope_elem;
19
20 #include <dl-defs.h>
21 #ifdef __LDSO_CACHE_SUPPORT__
22 extern int _dl_map_cache(void);
23 extern int _dl_unmap_cache(void);
24 #else
25 static __inline__ void _dl_map_cache(void) { }
26 static __inline__ void _dl_unmap_cache(void) { }
27 #endif
28
29
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);
45
46 /*
47  * Bitsize related settings for things ElfW()
48  * does not handle already
49  */
50 #if __WORDSIZE == 64
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)
55 # ifndef ELF_CLASS
56 #  define ELF_CLASS ELFCLASS64
57 # endif
58 #else
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)
63 # ifndef ELF_CLASS
64 #  define ELF_CLASS ELFCLASS32
65 # endif
66 #endif
67
68 /*
69  * Datatype of a relocation on this platform
70  */
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"
78 #else
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"
85 #endif
86
87 /* OS and/or GNU dynamic extensions */
88
89 #define OS_NUM_BASE 1                   /* for DT_RELOCCOUNT */
90
91 #ifdef __LDSO_GNU_HASH_SUPPORT__
92 # define OS_NUM_GNU_HASH        1   /* for DT_GNU_HASH entry */
93 #else
94 # define OS_NUM_GNU_HASH        0
95 #endif
96
97 #ifdef __LDSO_PRELINK_SUPPORT__
98 # define OS_NUM_PRELINK         6   /* for DT_GNU_PRELINKED entry */
99 #else
100 # define OS_NUM_PRELINK 0
101 #endif
102
103 #define OS_NUM    (OS_NUM_BASE + OS_NUM_GNU_HASH + OS_NUM_PRELINK)
104
105 #ifndef ARCH_DYNAMIC_INFO
106   /* define in arch specific code, if needed */
107 # define ARCH_NUM 0
108 #endif
109
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)
113
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)
117 #else
118 # define DT_GNU_HASH_IDX DT_RELCONT_IDX
119 #endif
120
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)
129 #endif
130
131 extern unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[],
132                                            void *debug_addr, DL_LOADADDR_TYPE load_off);
133
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)
137 {
138         unsigned int rtld_flags = 0;
139
140         for (; dpnt->d_tag; dpnt++) {
141                 if (dpnt->d_tag < DT_NUM) {
142                         dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
143 #ifndef __mips__
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;
150 #endif
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;
163 #endif
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;
172                         }
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;
176 #endif
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;
190 #endif
191                 }
192 #ifdef ARCH_DYNAMIC_INFO
193                 else {
194                         ARCH_DYNAMIC_INFO(dpnt, dynamic_info, debug_addr);
195                 }
196 #endif
197         }
198 #define ADJUST_DYN_INFO(tag, load_off) \
199         do { \
200                 if (dynamic_info[tag]) \
201                         dynamic_info[tag] = (unsigned long) DL_RELOC_ADDR(load_off, dynamic_info[tag]); \
202         } while (0)
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__
207         if (load_off != 0)
208 #endif
209         {
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);
218 #endif
219         }
220 #ifdef __DSBT__
221         /* Get the mapped address of the DSBT base.  */
222         ADJUST_DYN_INFO(DT_DSBT_BASE_IDX, load_off);
223
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];
228 #endif
229 #undef ADJUST_DYN_INFO
230         return rtld_flags;
231 }
232
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
239    out.  */
240 #ifdef DL_NO_COPY_RELOCS
241 # define ELF_RTYPE_CLASS_COPY   (0x0)
242 #else
243 # define ELF_RTYPE_CLASS_COPY   (0x2)
244 #endif
245 #define ELF_RTYPE_CLASS_PLT     (0x1)
246
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
251
252
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))
258
259
260 #endif  /* LINUXELF_H */