00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00046 #include <stdio.h>
00047 #include <sys/types.h>
00048 #include <align.h>
00049 #include <assert.h>
00050 #include <as.h>
00051 #include <unistd.h>
00052 #include <fcntl.h>
00053 #include <smc.h>
00054 #include <loader/pcb.h>
00055 #include <entry_point.h>
00056
00057 #include "elf.h"
00058 #include "elf_load.h"
00059
00060 #define DPRINTF(...)
00061
00062 static const char *error_codes[] = {
00063 "no error",
00064 "invalid image",
00065 "address space error",
00066 "incompatible image",
00067 "unsupported image type",
00068 "irrecoverable error"
00069 };
00070
00071 static unsigned int elf_load(elf_ld_t *elf, size_t so_bias);
00072 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry);
00073 static int section_header(elf_ld_t *elf, elf_section_header_t *entry);
00074 static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry);
00075
00077 static int my_read(int fd, void *buf, size_t len)
00078 {
00079 int cnt = 0;
00080 do {
00081 buf += cnt;
00082 len -= cnt;
00083 cnt = read(fd, buf, len);
00084 } while ((cnt > 0) && ((len - cnt) > 0));
00085
00086 return cnt;
00087 }
00088
00105 int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
00106 elf_info_t *info)
00107 {
00108 elf_ld_t elf;
00109
00110 int fd;
00111 int rc;
00112
00113 fd = open(file_name, O_RDONLY);
00114 if (fd < 0) {
00115 DPRINTF("failed opening file\n");
00116 return -1;
00117 }
00118
00119 elf.fd = fd;
00120 elf.info = info;
00121 elf.flags = flags;
00122
00123 rc = elf_load(&elf, so_bias);
00124
00125 close(fd);
00126
00127 return rc;
00128 }
00129
00138 void elf_create_pcb(elf_info_t *info, pcb_t *pcb)
00139 {
00140 pcb->entry = info->entry;
00141 pcb->dynamic = info->dynamic;
00142 pcb->rtld_runtime = NULL;
00143 }
00144
00145
00156 static unsigned int elf_load(elf_ld_t *elf, size_t so_bias)
00157 {
00158 elf_header_t header_buf;
00159 elf_header_t *header = &header_buf;
00160 int i, rc;
00161
00162 rc = my_read(elf->fd, header, sizeof(elf_header_t));
00163 if (rc < 0) {
00164 DPRINTF("Read error.\n");
00165 return EE_INVALID;
00166 }
00167
00168 elf->header = header;
00169
00170
00171 if (header->e_ident[EI_MAG0] != ELFMAG0 ||
00172 header->e_ident[EI_MAG1] != ELFMAG1 ||
00173 header->e_ident[EI_MAG2] != ELFMAG2 ||
00174 header->e_ident[EI_MAG3] != ELFMAG3) {
00175 DPRINTF("Invalid header.\n");
00176 return EE_INVALID;
00177 }
00178
00179
00180 if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
00181 header->e_machine != ELF_MACHINE ||
00182 header->e_ident[EI_VERSION] != EV_CURRENT ||
00183 header->e_version != EV_CURRENT ||
00184 header->e_ident[EI_CLASS] != ELF_CLASS) {
00185 DPRINTF("Incompatible data/version/class.\n");
00186 return EE_INCOMPATIBLE;
00187 }
00188
00189 if (header->e_phentsize != sizeof(elf_segment_header_t)) {
00190 DPRINTF("e_phentsize:%d != %d\n", header->e_phentsize,
00191 sizeof(elf_segment_header_t));
00192 return EE_INCOMPATIBLE;
00193 }
00194
00195 if (header->e_shentsize != sizeof(elf_section_header_t)) {
00196 DPRINTF("e_shentsize:%d != %d\n", header->e_shentsize,
00197 sizeof(elf_section_header_t));
00198 return EE_INCOMPATIBLE;
00199 }
00200
00201
00202 if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
00203 DPRINTF("Object type %d is not supported\n", header->e_type);
00204 return EE_UNSUPPORTED;
00205 }
00206
00207
00208 if (header->e_type == ET_DYN)
00209 elf->bias = so_bias;
00210 else
00211 elf->bias = 0;
00212
00213 elf->info->interp = NULL;
00214 elf->info->dynamic = NULL;
00215
00216
00217 for (i = 0; i < header->e_phnum; i++) {
00218 elf_segment_header_t segment_hdr;
00219
00220
00221 lseek(elf->fd, header->e_phoff
00222 + i * sizeof(elf_segment_header_t), SEEK_SET);
00223
00224 rc = my_read(elf->fd, &segment_hdr,
00225 sizeof(elf_segment_header_t));
00226 if (rc < 0) {
00227 DPRINTF("Read error.\n");
00228 return EE_INVALID;
00229 }
00230
00231 rc = segment_header(elf, &segment_hdr);
00232 if (rc != EE_OK)
00233 return rc;
00234 }
00235
00236 DPRINTF("Parse sections.\n");
00237
00238
00239 for (i = 0; i < header->e_shnum; i++) {
00240 elf_section_header_t section_hdr;
00241
00242
00243 lseek(elf->fd, header->e_shoff
00244 + i * sizeof(elf_section_header_t), SEEK_SET);
00245
00246 rc = my_read(elf->fd, §ion_hdr,
00247 sizeof(elf_section_header_t));
00248 if (rc < 0) {
00249 DPRINTF("Read error.\n");
00250 return EE_INVALID;
00251 }
00252
00253 rc = section_header(elf, §ion_hdr);
00254 if (rc != EE_OK)
00255 return rc;
00256 }
00257
00258 elf->info->entry =
00259 (entry_point_t)((uint8_t *)header->e_entry + elf->bias);
00260
00261 DPRINTF("Done.\n");
00262
00263 return EE_OK;
00264 }
00265
00272 const char *elf_error(unsigned int rc)
00273 {
00274 assert(rc < sizeof(error_codes) / sizeof(char *));
00275
00276 return error_codes[rc];
00277 }
00278
00285 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry)
00286 {
00287 switch (entry->p_type) {
00288 case PT_NULL:
00289 case PT_PHDR:
00290 case PT_NOTE:
00291 break;
00292 case PT_LOAD:
00293 return load_segment(elf, entry);
00294 break;
00295 case PT_INTERP:
00296
00297 elf->info->interp = "/app/dload";
00298 break;
00299 case PT_DYNAMIC:
00300
00301 elf->info->dynamic =
00302 (void *)((uint8_t *)entry->p_vaddr + elf->bias);
00303 DPRINTF("dynamic section found at 0x%x\n",
00304 (uintptr_t)elf->info->dynamic);
00305 break;
00306 case 0x70000000:
00307
00308 break;
00309 case PT_SHLIB:
00310
00311
00312 default:
00313 DPRINTF("Segment p_type %d unknown.\n", entry->p_type);
00314 return EE_UNSUPPORTED;
00315 break;
00316 }
00317 return EE_OK;
00318 }
00319
00327 int load_segment(elf_ld_t *elf, elf_segment_header_t *entry)
00328 {
00329 void *a;
00330 int flags = 0;
00331 uintptr_t bias;
00332 uintptr_t base;
00333 void *seg_ptr;
00334 uintptr_t seg_addr;
00335 size_t mem_sz;
00336 int rc;
00337
00338 bias = elf->bias;
00339
00340 seg_addr = entry->p_vaddr + bias;
00341 seg_ptr = (void *) seg_addr;
00342
00343 DPRINTF("Load segment at addr %p, size 0x%x\n", (void *) seg_addr,
00344 entry->p_memsz);
00345
00346 if (entry->p_align > 1) {
00347 if ((entry->p_offset % entry->p_align) !=
00348 (seg_addr % entry->p_align)) {
00349 DPRINTF("Align check 1 failed offset%%align=%d, "
00350 "vaddr%%align=%d\n",
00351 entry->p_offset % entry->p_align,
00352 seg_addr % entry->p_align
00353 );
00354 return EE_INVALID;
00355 }
00356 }
00357
00358
00359
00360 if (entry->p_flags & PF_X)
00361 flags |= AS_AREA_EXEC;
00362 if (entry->p_flags & PF_W)
00363 flags |= AS_AREA_WRITE;
00364 if (entry->p_flags & PF_R)
00365 flags |= AS_AREA_READ;
00366 flags |= AS_AREA_CACHEABLE;
00367
00368 base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
00369 mem_sz = entry->p_memsz + (entry->p_vaddr - base);
00370
00371 DPRINTF("Map to seg_addr=%p-%p.\n", (void *) seg_addr,
00372 (void *) (entry->p_vaddr + bias +
00373 ALIGN_UP(entry->p_memsz, PAGE_SIZE)));
00374
00375
00376
00377
00378
00379 a = as_area_create((uint8_t *)base + bias, mem_sz,
00380 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
00381 if (a == (void *)(-1)) {
00382 DPRINTF("memory mapping failed (0x%x, %d)\n",
00383 base+bias, mem_sz);
00384 return EE_MEMORY;
00385 }
00386
00387 DPRINTF("as_area_create(%p, %#zx, %d) -> %p\n",
00388 (void *) (base + bias), mem_sz, flags, (void *) a);
00389
00390
00391
00392
00393 rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
00394 if (rc < 0) {
00395 printf("seek error\n");
00396 return EE_INVALID;
00397 }
00398
00399
00400
00401
00402
00403
00404 unsigned left, now;
00405 uint8_t *dp;
00406
00407 left = entry->p_filesz;
00408 dp = seg_ptr;
00409
00410 while (left > 0) {
00411 now = 16384;
00412 if (now > left) now = left;
00413
00414 rc = my_read(elf->fd, dp, now);
00415
00416 if (rc < 0) {
00417 DPRINTF("Read error.\n");
00418 return EE_INVALID;
00419 }
00420
00421 left -= now;
00422 dp += now;
00423 }
00424
00425
00426
00427
00428
00429 if ((elf->flags & ELDF_RW) != 0) return EE_OK;
00430
00431
00432 rc = as_area_change_flags(seg_ptr, flags);
00433 if (rc != 0) {
00434 DPRINTF("Failed to set memory area flags.\n");
00435 return EE_MEMORY;
00436 }
00437
00438 if (flags & AS_AREA_EXEC) {
00439
00440 if (smc_coherence(seg_ptr, entry->p_filesz))
00441 return EE_MEMORY;
00442 }
00443
00444 return EE_OK;
00445 }
00446
00454 static int section_header(elf_ld_t *elf, elf_section_header_t *entry)
00455 {
00456 switch (entry->sh_type) {
00457 case SHT_PROGBITS:
00458 if (entry->sh_flags & SHF_TLS) {
00459
00460 }
00461 break;
00462 case SHT_NOBITS:
00463 if (entry->sh_flags & SHF_TLS) {
00464
00465 }
00466 break;
00467 case SHT_DYNAMIC:
00468
00469 elf->info->dynamic =
00470 (void *)((uint8_t *)entry->sh_addr + elf->bias);
00471 DPRINTF("Dynamic section found at %p.\n",
00472 (void *) elf->info->dynamic);
00473 break;
00474 default:
00475 break;
00476 }
00477
00478 return EE_OK;
00479 }
00480