Changeset 40d3604 in mainline for uspace/lib/c/generic/elf/elf_mod.c
- Timestamp:
- 2018-04-30T20:12:50Z (7 years ago)
- Parents:
- 4c5f04f (diff), 64d38cd (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-04-30 20:12:50)
- git-committer:
- GitHub <noreply@…> (2018-04-30 20:12:50)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/elf/elf_mod.c
r4c5f04f r40d3604 58 58 #include <str_error.h> 59 59 #include <stdlib.h> 60 #include <macros.h> 60 61 61 62 #include <elf/elf_load.h> … … 73 74 }; 74 75 75 static unsigned int elf_load_module(elf_ld_t *elf, size_t so_bias); 76 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry); 76 static unsigned int elf_load_module(elf_ld_t *elf); 77 77 static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry); 78 78 … … 86 86 * 87 87 * @param file ELF file. 88 * @param so_bias Bias to use if the file is a shared object.89 88 * @param info Pointer to a structure for storing information 90 89 * extracted from the binary. … … 93 92 * 94 93 */ 95 int elf_load_file(int file, size_t so_bias,eld_flags_t flags, elf_finfo_t *info)94 int elf_load_file(int file, eld_flags_t flags, elf_finfo_t *info) 96 95 { 97 96 elf_ld_t elf; … … 110 109 elf.flags = flags; 111 110 112 int ret = elf_load_module(&elf , so_bias);111 int ret = elf_load_module(&elf); 113 112 114 113 vfs_put(ofile); … … 116 115 } 117 116 118 int elf_load_file_name(const char *path, size_t so_bias, eld_flags_t flags, 119 elf_finfo_t *info) 117 int elf_load_file_name(const char *path, eld_flags_t flags, elf_finfo_t *info) 120 118 { 121 119 int file; 122 120 errno_t rc = vfs_lookup(path, 0, &file); 123 121 if (rc == EOK) { 124 int ret = elf_load_file(file, so_bias,flags, info);122 int ret = elf_load_file(file, flags, info); 125 123 vfs_put(file); 126 124 return ret; … … 130 128 } 131 129 130 /** Process TLS program header. 131 * 132 * @param elf Pointer to loader state buffer. 133 * @param hdr TLS program header 134 * @param info Place to store TLS info 135 */ 136 static void tls_program_header(void *base, elf_tls_info_t *info) 137 { 138 const elf_segment_header_t *tls = elf_get_phdr(base, PT_TLS); 139 size_t bias = elf_get_bias(base); 140 141 if (tls == NULL) { 142 /* Ensure valid TLS info even if there is no TLS header. */ 143 info->tdata = NULL; 144 info->tdata_size = 0; 145 info->tbss_size = 0; 146 info->tls_align = 1; 147 } else { 148 info->tdata = (void *) tls->p_vaddr + bias; 149 info->tdata_size = tls->p_filesz; 150 info->tbss_size = tls->p_memsz - tls->p_filesz; 151 info->tls_align = tls->p_align; 152 } 153 } 154 132 155 /** Load an ELF binary. 133 156 * … … 137 160 * 138 161 * @param elf Pointer to loader state buffer. 139 * @param so_bias Bias to use if the file is a shared object.140 162 * @return EE_OK on success or EE_xx error code. 141 163 */ 142 static unsigned int elf_load_module(elf_ld_t *elf , size_t so_bias)164 static unsigned int elf_load_module(elf_ld_t *elf) 143 165 { 144 166 elf_header_t header_buf; … … 154 176 return EE_IO; 155 177 } 156 157 elf->header = header;158 178 159 179 /* Identify ELF */ … … 188 208 } 189 209 210 if (header->e_phoff == 0) { 211 DPRINTF("Program header table is not present!\n"); 212 return EE_INCOMPATIBLE; 213 } 214 215 /* Read program header table. 216 * Normally, there is very few program headers, so don't bother 217 * with allocating memory dynamically. 218 */ 219 const int phdr_cap = 16; 220 elf_segment_header_t phdr[phdr_cap]; 221 size_t phdr_len = header->e_phnum * header->e_phentsize; 222 223 if (phdr_len > sizeof(phdr)) { 224 DPRINTF("more than %d program headers\n", phdr_cap); 225 return EE_UNSUPPORTED; 226 } 227 228 pos = header->e_phoff; 229 rc = vfs_read(elf->fd, &pos, phdr, phdr_len, &nr); 230 if (rc != EOK || nr != phdr_len) { 231 DPRINTF("Read error.\n"); 232 return EE_IO; 233 } 234 235 uintptr_t module_base = UINTPTR_MAX; 236 uintptr_t module_top = 0; 237 uintptr_t base_offset = UINTPTR_MAX; 238 239 /* Walk through PT_LOAD headers, to find out the size of the module. */ 240 for (i = 0; i < header->e_phnum; i++) { 241 if (phdr[i].p_type != PT_LOAD) 242 continue; 243 244 if (module_base > phdr[i].p_vaddr) { 245 module_base = phdr[i].p_vaddr; 246 base_offset = phdr[i].p_offset; 247 } 248 module_top = max(module_top, phdr[i].p_vaddr + phdr[i].p_memsz); 249 } 250 251 if (base_offset != 0) { 252 DPRINTF("ELF headers not present in the text segment.\n"); 253 return EE_INVALID; 254 } 255 190 256 /* Shared objects can be loaded with a bias */ 191 if (header->e_type == ET_DYN) 192 elf->bias = so_bias; 193 else 257 if (header->e_type != ET_DYN) { 194 258 elf->bias = 0; 195 196 /* Ensure valid TLS info even if there is no TLS header. */ 197 elf->info->tls.tdata = NULL; 198 elf->info->tls.tdata_size = 0; 199 elf->info->tls.tbss_size = 0; 200 elf->info->tls.tls_align = 1; 201 202 elf->info->interp = NULL; 203 elf->info->dynamic = NULL; 204 205 /* Walk through all segment headers and process them. */ 259 } else { 260 if (module_base != 0) { 261 DPRINTF("Unexpected shared object format.\n"); 262 return EE_INVALID; 263 } 264 265 /* Attempt to allocate a span of memory large enough for the 266 * shared object. 267 */ 268 // FIXME: This is not reliable when we're running 269 // multi-threaded. Even if this part succeeds, later 270 // allocation can fail because another thread took the 271 // space in the meantime. This is only relevant for 272 // dlopen() though. 273 void *area = as_area_create(AS_AREA_ANY, module_top, 274 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE | 275 AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED); 276 277 if (area == AS_MAP_FAILED) { 278 DPRINTF("Can't find suitable memory area.\n"); 279 return EE_MEMORY; 280 } 281 282 elf->bias = (uintptr_t) area; 283 as_area_destroy(area); 284 } 285 286 /* Load all loadable segments. */ 206 287 for (i = 0; i < header->e_phnum; i++) { 207 elf_segment_header_t segment_hdr; 208 209 pos = header->e_phoff + i * sizeof(elf_segment_header_t); 210 rc = vfs_read(elf->fd, &pos, &segment_hdr, 211 sizeof(elf_segment_header_t), &nr); 212 if (rc != EOK || nr != sizeof(elf_segment_header_t)) { 213 DPRINTF("Read error.\n"); 214 return EE_IO; 215 } 216 217 ret = segment_header(elf, &segment_hdr); 288 if (phdr[i].p_type != PT_LOAD) 289 continue; 290 291 ret = load_segment(elf, &phdr[i]); 218 292 if (ret != EE_OK) 219 293 return ret; 220 294 } 221 295 296 void *base = (void *) module_base + elf->bias; 297 elf->info->base = base; 298 299 /* Handle TLS. */ 300 tls_program_header(base, &elf->info->tls); 301 302 /* Handle PT_INTERP. */ 303 304 const elf_segment_header_t *interphdr = elf_get_phdr(base, PT_INTERP); 305 306 if (interphdr == NULL) { 307 interphdr = NULL; 308 } else { 309 elf->info->interp = 310 (const char *) (interphdr->p_vaddr + elf->bias); 311 if (elf->info->interp[interphdr->p_filesz - 1] != '\0') { 312 DPRINTF("Unterminated ELF interp string.\n"); 313 elf->info->interp = NULL; 314 } else { 315 DPRINTF("interpreter: \"%s\"\n", elf->info->interp); 316 } 317 } 318 319 /* Handle PT_DYNAMIC. */ 320 321 const elf_segment_header_t *dynphdr = elf_get_phdr(base, PT_DYNAMIC); 322 323 if (dynphdr == NULL) { 324 elf->info->dynamic = NULL; 325 } else { 326 /* Record pointer to dynamic section into info structure */ 327 elf->info->dynamic = (void *) (dynphdr->p_vaddr + elf->bias); 328 DPRINTF("dynamic section found at %p\n", 329 (void *)elf->info->dynamic); 330 } 331 222 332 elf->info->entry = 223 333 (entry_point_t)((uint8_t *)header->e_entry + elf->bias); … … 239 349 240 350 return error_codes[rc]; 241 }242 243 /** Process TLS program header.244 *245 * @param elf Pointer to loader state buffer.246 * @param hdr TLS program header247 * @param info Place to store TLS info248 */249 static void tls_program_header(elf_ld_t *elf, elf_segment_header_t *hdr,250 elf_tls_info_t *info)251 {252 info->tdata = (void *)((uint8_t *)hdr->p_vaddr + elf->bias);253 info->tdata_size = hdr->p_filesz;254 info->tbss_size = hdr->p_memsz - hdr->p_filesz;255 info->tls_align = hdr->p_align;256 }257 258 /** Process segment header.259 *260 * @param elf Pointer to loader state buffer.261 * @param entry Segment header.262 *263 * @return EE_OK on success, error code otherwise.264 */265 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry)266 {267 switch (entry->p_type) {268 case PT_NULL:269 case PT_PHDR:270 case PT_NOTE:271 break;272 case PT_LOAD:273 return load_segment(elf, entry);274 break;275 case PT_INTERP:276 elf->info->interp =277 (void *)((uint8_t *)entry->p_vaddr + elf->bias);278 279 // FIXME: This actually won't work, because the text segment is280 // not loaded yet.281 #if 0282 if (elf->info->interp[entry->p_filesz - 1] != '\0') {283 DPRINTF("Unterminated ELF interp string.\n");284 return EE_INVALID;285 }286 DPRINTF("interpreter: \"%s\"\n", elf->info->interp);287 #endif288 break;289 case PT_DYNAMIC:290 /* Record pointer to dynamic section into info structure */291 elf->info->dynamic =292 (void *)((uint8_t *)entry->p_vaddr + elf->bias);293 DPRINTF("dynamic section found at %p\n",294 (void *)elf->info->dynamic);295 break;296 case 0x70000000:297 case 0x70000001:298 case 0x70000002:299 case 0x70000003:300 // FIXME: Architecture-specific headers.301 /* PT_MIPS_REGINFO, PT_MIPS_ABIFLAGS, PT_ARM_UNWIND, ... */302 break;303 case PT_TLS:304 /* Parse TLS program header */305 tls_program_header(elf, entry, &elf->info->tls);306 DPRINTF("TLS header found at %p\n",307 (void *)((uint8_t *)entry->p_vaddr + elf->bias));308 break;309 case PT_SHLIB:310 default:311 DPRINTF("Segment p_type %d unknown.\n", entry->p_type);312 return EE_UNSUPPORTED;313 break;314 }315 return EE_OK;316 351 } 317 352
Note:
See TracChangeset
for help on using the changeset viewer.