lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 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 | #define DL_RESOLVE_SECURE 0x0001 |
| 30 | #define DL_RESOLVE_NOLOAD 0x0002 |
| 31 | |
| 32 | /* Function prototypes for non-static stuff in readelflib1.c */ |
| 33 | extern void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, |
| 34 | unsigned long rel_addr, unsigned long rel_size); |
| 35 | extern int _dl_parse_relocation_information(struct dyn_elf *rpnt, |
| 36 | struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size); |
| 37 | extern 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); |
| 40 | extern struct elf_resolve * _dl_load_elf_shared_library(unsigned rflags, |
| 41 | struct dyn_elf **rpnt, const char *libname); |
| 42 | extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname, |
| 43 | int trace_loaded_objects); |
| 44 | extern int _dl_linux_resolve(void); |
| 45 | extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int flag); |
| 46 | extern 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 | |
| 133 | extern unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], |
| 134 | void *debug_addr, DL_LOADADDR_TYPE load_off); |
| 135 | |
| 136 | static __always_inline |
| 137 | unsigned 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 */ |