qemu/include/hw/elf_ops.h
<<
>>
Prefs
   1static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
   2{
   3    bswap16s(&ehdr->e_type);                    /* Object file type */
   4    bswap16s(&ehdr->e_machine);         /* Architecture */
   5    bswap32s(&ehdr->e_version);         /* Object file version */
   6    bswapSZs(&ehdr->e_entry);           /* Entry point virtual address */
   7    bswapSZs(&ehdr->e_phoff);           /* Program header table file offset */
   8    bswapSZs(&ehdr->e_shoff);           /* Section header table file offset */
   9    bswap32s(&ehdr->e_flags);           /* Processor-specific flags */
  10    bswap16s(&ehdr->e_ehsize);          /* ELF header size in bytes */
  11    bswap16s(&ehdr->e_phentsize);               /* Program header table entry size */
  12    bswap16s(&ehdr->e_phnum);           /* Program header table entry count */
  13    bswap16s(&ehdr->e_shentsize);               /* Section header table entry size */
  14    bswap16s(&ehdr->e_shnum);           /* Section header table entry count */
  15    bswap16s(&ehdr->e_shstrndx);                /* Section header string table index */
  16}
  17
  18static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
  19{
  20    bswap32s(&phdr->p_type);                    /* Segment type */
  21    bswapSZs(&phdr->p_offset);          /* Segment file offset */
  22    bswapSZs(&phdr->p_vaddr);           /* Segment virtual address */
  23    bswapSZs(&phdr->p_paddr);           /* Segment physical address */
  24    bswapSZs(&phdr->p_filesz);          /* Segment size in file */
  25    bswapSZs(&phdr->p_memsz);           /* Segment size in memory */
  26    bswap32s(&phdr->p_flags);           /* Segment flags */
  27    bswapSZs(&phdr->p_align);           /* Segment alignment */
  28}
  29
  30static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
  31{
  32    bswap32s(&shdr->sh_name);
  33    bswap32s(&shdr->sh_type);
  34    bswapSZs(&shdr->sh_flags);
  35    bswapSZs(&shdr->sh_addr);
  36    bswapSZs(&shdr->sh_offset);
  37    bswapSZs(&shdr->sh_size);
  38    bswap32s(&shdr->sh_link);
  39    bswap32s(&shdr->sh_info);
  40    bswapSZs(&shdr->sh_addralign);
  41    bswapSZs(&shdr->sh_entsize);
  42}
  43
  44static void glue(bswap_sym, SZ)(struct elf_sym *sym)
  45{
  46    bswap32s(&sym->st_name);
  47    bswapSZs(&sym->st_value);
  48    bswapSZs(&sym->st_size);
  49    bswap16s(&sym->st_shndx);
  50}
  51
  52static void glue(bswap_rela, SZ)(struct elf_rela *rela)
  53{
  54    bswapSZs(&rela->r_offset);
  55    bswapSZs(&rela->r_info);
  56    bswapSZs((elf_word *)&rela->r_addend);
  57}
  58
  59static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
  60                                               int n, int type)
  61{
  62    int i;
  63    for(i=0;i<n;i++) {
  64        if (shdr_table[i].sh_type == type)
  65            return shdr_table + i;
  66    }
  67    return NULL;
  68}
  69
  70static int glue(symfind, SZ)(const void *s0, const void *s1)
  71{
  72    hwaddr addr = *(hwaddr *)s0;
  73    struct elf_sym *sym = (struct elf_sym *)s1;
  74    int result = 0;
  75    if (addr < sym->st_value) {
  76        result = -1;
  77    } else if (addr >= sym->st_value + sym->st_size) {
  78        result = 1;
  79    }
  80    return result;
  81}
  82
  83static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
  84                                           hwaddr orig_addr)
  85{
  86    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
  87    struct elf_sym *sym;
  88
  89    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
  90                  glue(symfind, SZ));
  91    if (sym != NULL) {
  92        return s->disas_strtab + sym->st_name;
  93    }
  94
  95    return "";
  96}
  97
  98static int glue(symcmp, SZ)(const void *s0, const void *s1)
  99{
 100    struct elf_sym *sym0 = (struct elf_sym *)s0;
 101    struct elf_sym *sym1 = (struct elf_sym *)s1;
 102    return (sym0->st_value < sym1->st_value)
 103        ? -1
 104        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
 105}
 106
 107static void glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
 108                                   int clear_lsb, symbol_fn_t sym_cb)
 109{
 110    struct elf_shdr *symtab, *strtab;
 111    g_autofree struct elf_shdr *shdr_table = NULL;
 112    g_autofree struct elf_sym *syms = NULL;
 113    g_autofree char *str = NULL;
 114    struct syminfo *s;
 115    int nsyms, i;
 116
 117    shdr_table = load_at(fd, ehdr->e_shoff,
 118                         sizeof(struct elf_shdr) * ehdr->e_shnum);
 119    if (!shdr_table) {
 120        return ;
 121    }
 122
 123    if (must_swab) {
 124        for (i = 0; i < ehdr->e_shnum; i++) {
 125            glue(bswap_shdr, SZ)(shdr_table + i);
 126        }
 127    }
 128
 129    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
 130    if (!symtab) {
 131        return;
 132    }
 133    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
 134    if (!syms) {
 135        return;
 136    }
 137
 138    nsyms = symtab->sh_size / sizeof(struct elf_sym);
 139
 140    /* String table */
 141    if (symtab->sh_link >= ehdr->e_shnum) {
 142        return;
 143    }
 144    strtab = &shdr_table[symtab->sh_link];
 145
 146    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
 147    if (!str) {
 148        return;
 149    }
 150
 151    i = 0;
 152    while (i < nsyms) {
 153        if (must_swab) {
 154            glue(bswap_sym, SZ)(&syms[i]);
 155        }
 156        if (sym_cb) {
 157            sym_cb(str + syms[i].st_name, syms[i].st_info,
 158                   syms[i].st_value, syms[i].st_size);
 159        }
 160        /* We are only interested in function symbols.
 161           Throw everything else away.  */
 162        if (syms[i].st_shndx == SHN_UNDEF ||
 163                syms[i].st_shndx >= SHN_LORESERVE ||
 164                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
 165            nsyms--;
 166            if (i < nsyms) {
 167                syms[i] = syms[nsyms];
 168            }
 169            continue;
 170        }
 171        if (clear_lsb) {
 172            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
 173            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
 174        }
 175        i++;
 176    }
 177
 178    /* check we have symbols left */
 179    if (nsyms == 0) {
 180        return;
 181    }
 182
 183    syms = g_realloc(syms, nsyms * sizeof(*syms));
 184    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
 185    for (i = 0; i < nsyms - 1; i++) {
 186        if (syms[i].st_size == 0) {
 187            syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
 188        }
 189    }
 190
 191    /* Commit */
 192    s = g_malloc0(sizeof(*s));
 193    s->lookup_symbol = glue(lookup_symbol, SZ);
 194    glue(s->disas_symtab.elf, SZ) = g_steal_pointer(&syms);
 195    s->disas_num_syms = nsyms;
 196    s->disas_strtab = g_steal_pointer(&str);
 197    s->next = syminfos;
 198    syminfos = s;
 199}
 200
 201static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
 202                               uint64_t (*translate_fn)(void *, uint64_t),
 203                               void *translate_opaque, uint8_t *data,
 204                               struct elf_phdr *ph, int elf_machine)
 205{
 206    struct elf_shdr *reltab, *shdr_table = NULL;
 207    struct elf_rela *rels = NULL;
 208    int nrels, i, ret = -1;
 209    elf_word wordval;
 210    void *addr;
 211
 212    shdr_table = load_at(fd, ehdr->e_shoff,
 213                         sizeof(struct elf_shdr) * ehdr->e_shnum);
 214    if (!shdr_table) {
 215        return -1;
 216    }
 217    if (must_swab) {
 218        for (i = 0; i < ehdr->e_shnum; i++) {
 219            glue(bswap_shdr, SZ)(&shdr_table[i]);
 220        }
 221    }
 222
 223    reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA);
 224    if (!reltab) {
 225        goto fail;
 226    }
 227    rels = load_at(fd, reltab->sh_offset, reltab->sh_size);
 228    if (!rels) {
 229        goto fail;
 230    }
 231    nrels = reltab->sh_size / sizeof(struct elf_rela);
 232
 233    for (i = 0; i < nrels; i++) {
 234        if (must_swab) {
 235            glue(bswap_rela, SZ)(&rels[i]);
 236        }
 237        if (rels[i].r_offset < ph->p_vaddr ||
 238            rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) {
 239            continue;
 240        }
 241        addr = &data[rels[i].r_offset - ph->p_vaddr];
 242        switch (elf_machine) {
 243        case EM_S390:
 244            switch (rels[i].r_info) {
 245            case R_390_RELATIVE:
 246                wordval = *(elf_word *)addr;
 247                if (must_swab) {
 248                    bswapSZs(&wordval);
 249                }
 250                wordval = translate_fn(translate_opaque, wordval);
 251                if (must_swab) {
 252                    bswapSZs(&wordval);
 253                }
 254                *(elf_word *)addr = wordval;
 255                break;
 256            default:
 257                fprintf(stderr, "Unsupported relocation type %i!\n",
 258                        (int)rels[i].r_info);
 259            }
 260        }
 261    }
 262
 263    ret = 0;
 264fail:
 265    g_free(rels);
 266    g_free(shdr_table);
 267    return ret;
 268}
 269
 270/*
 271 * Given 'nhdr', a pointer to a range of ELF Notes, search through them
 272 * for a note matching type 'elf_note_type' and return a pointer to
 273 * the matching ELF note.
 274 */
 275static struct elf_note *glue(get_elf_note_type, SZ)(struct elf_note *nhdr,
 276                                                    elf_word note_size,
 277                                                    elf_word phdr_align,
 278                                                    elf_word elf_note_type)
 279{
 280    elf_word nhdr_size = sizeof(struct elf_note);
 281    elf_word elf_note_entry_offset = 0;
 282    elf_word note_type;
 283    elf_word nhdr_namesz;
 284    elf_word nhdr_descsz;
 285
 286    if (nhdr == NULL) {
 287        return NULL;
 288    }
 289
 290    note_type = nhdr->n_type;
 291    while (note_type != elf_note_type) {
 292        nhdr_namesz = nhdr->n_namesz;
 293        nhdr_descsz = nhdr->n_descsz;
 294
 295        elf_note_entry_offset = nhdr_size +
 296            QEMU_ALIGN_UP(nhdr_namesz, phdr_align) +
 297            QEMU_ALIGN_UP(nhdr_descsz, phdr_align);
 298
 299        /*
 300         * If the offset calculated in this iteration exceeds the
 301         * supplied size, we are done and no matching note was found.
 302         */
 303        if (elf_note_entry_offset > note_size) {
 304            return NULL;
 305        }
 306
 307        /* skip to the next ELF Note entry */
 308        nhdr = (void *)nhdr + elf_note_entry_offset;
 309        note_type = nhdr->n_type;
 310    }
 311
 312    return nhdr;
 313}
 314
 315static int glue(load_elf, SZ)(const char *name, int fd,
 316                              uint64_t (*elf_note_fn)(void *, void *, bool),
 317                              uint64_t (*translate_fn)(void *, uint64_t),
 318                              void *translate_opaque,
 319                              int must_swab, uint64_t *pentry,
 320                              uint64_t *lowaddr, uint64_t *highaddr,
 321                              uint32_t *pflags, int elf_machine,
 322                              int clear_lsb, int data_swab,
 323                              AddressSpace *as, bool load_rom,
 324                              symbol_fn_t sym_cb)
 325{
 326    struct elfhdr ehdr;
 327    struct elf_phdr *phdr = NULL, *ph;
 328    int size, i, total_size;
 329    elf_word mem_size, file_size, data_offset;
 330    uint64_t addr, low = (uint64_t)-1, high = 0;
 331    GMappedFile *mapped_file = NULL;
 332    uint8_t *data = NULL;
 333    int ret = ELF_LOAD_FAILED;
 334
 335    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
 336        goto fail;
 337    if (must_swab) {
 338        glue(bswap_ehdr, SZ)(&ehdr);
 339    }
 340
 341    if (elf_machine <= EM_NONE) {
 342        /* The caller didn't specify an ARCH, we can figure it out */
 343        elf_machine = ehdr.e_machine;
 344    }
 345
 346    switch (elf_machine) {
 347        case EM_PPC64:
 348            if (ehdr.e_machine != EM_PPC64) {
 349                if (ehdr.e_machine != EM_PPC) {
 350                    ret = ELF_LOAD_WRONG_ARCH;
 351                    goto fail;
 352                }
 353            }
 354            break;
 355        case EM_X86_64:
 356            if (ehdr.e_machine != EM_X86_64) {
 357                if (ehdr.e_machine != EM_386) {
 358                    ret = ELF_LOAD_WRONG_ARCH;
 359                    goto fail;
 360                }
 361            }
 362            break;
 363        case EM_MICROBLAZE:
 364            if (ehdr.e_machine != EM_MICROBLAZE) {
 365                if (ehdr.e_machine != EM_MICROBLAZE_OLD) {
 366                    ret = ELF_LOAD_WRONG_ARCH;
 367                    goto fail;
 368                }
 369            }
 370            break;
 371        case EM_MOXIE:
 372            if (ehdr.e_machine != EM_MOXIE) {
 373                if (ehdr.e_machine != EM_MOXIE_OLD) {
 374                    ret = ELF_LOAD_WRONG_ARCH;
 375                    goto fail;
 376                }
 377            }
 378            break;
 379        case EM_MIPS:
 380        case EM_NANOMIPS:
 381            if ((ehdr.e_machine != EM_MIPS) &&
 382                (ehdr.e_machine != EM_NANOMIPS)) {
 383                ret = ELF_LOAD_WRONG_ARCH;
 384                goto fail;
 385            }
 386            break;
 387        default:
 388            if (elf_machine != ehdr.e_machine) {
 389                ret = ELF_LOAD_WRONG_ARCH;
 390                goto fail;
 391            }
 392    }
 393
 394    if (pflags) {
 395        *pflags = (elf_word)ehdr.e_flags;
 396    }
 397    if (pentry)
 398        *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
 399
 400    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
 401
 402    size = ehdr.e_phnum * sizeof(phdr[0]);
 403    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != ehdr.e_phoff) {
 404        goto fail;
 405    }
 406    phdr = g_malloc0(size);
 407    if (!phdr)
 408        goto fail;
 409    if (read(fd, phdr, size) != size)
 410        goto fail;
 411    if (must_swab) {
 412        for(i = 0; i < ehdr.e_phnum; i++) {
 413            ph = &phdr[i];
 414            glue(bswap_phdr, SZ)(ph);
 415        }
 416    }
 417
 418    /*
 419     * Since we want to be able to modify the mapped buffer, we set the
 420     * 'writable' parameter to 'true'. Modifications to the buffer are not
 421     * written back to the file.
 422     */
 423    mapped_file = g_mapped_file_new_from_fd(fd, true, NULL);
 424    if (!mapped_file) {
 425        goto fail;
 426    }
 427
 428    total_size = 0;
 429    for(i = 0; i < ehdr.e_phnum; i++) {
 430        ph = &phdr[i];
 431        if (ph->p_type == PT_LOAD) {
 432            mem_size = ph->p_memsz; /* Size of the ROM */
 433            file_size = ph->p_filesz; /* Size of the allocated data */
 434            data_offset = ph->p_offset; /* Offset where the data is located */
 435
 436            if (file_size > 0) {
 437                if (g_mapped_file_get_length(mapped_file) <
 438                    file_size + data_offset) {
 439                    goto fail;
 440                }
 441
 442                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 443                data += data_offset;
 444            }
 445
 446            /* The ELF spec is somewhat vague about the purpose of the
 447             * physical address field. One common use in the embedded world
 448             * is that physical address field specifies the load address
 449             * and the virtual address field specifies the execution address.
 450             * Segments are packed into ROM or flash, and the relocation
 451             * and zero-initialization of data is done at runtime. This
 452             * means that the memsz header represents the runtime size of the
 453             * segment, but the filesz represents the loadtime size. If
 454             * we try to honour the memsz value for an ELF file like this
 455             * we will end up with overlapping segments (which the
 456             * loader.c code will later reject).
 457             * We support ELF files using this scheme by by checking whether
 458             * paddr + memsz for this segment would overlap with any other
 459             * segment. If so, then we assume it's using this scheme and
 460             * truncate the loaded segment to the filesz size.
 461             * If the segment considered as being memsz size doesn't overlap
 462             * then we use memsz for the segment length, to handle ELF files
 463             * which assume that the loader will do the zero-initialization.
 464             */
 465            if (mem_size > file_size) {
 466                /* If this segment's zero-init portion overlaps another
 467                 * segment's data or zero-init portion, then truncate this one.
 468                 * Invalid ELF files where the segments overlap even when
 469                 * only file_size bytes are loaded will be rejected by
 470                 * the ROM overlap check in loader.c, so we don't try to
 471                 * explicitly detect those here.
 472                 */
 473                int j;
 474                elf_word zero_start = ph->p_paddr + file_size;
 475                elf_word zero_end = ph->p_paddr + mem_size;
 476
 477                for (j = 0; j < ehdr.e_phnum; j++) {
 478                    struct elf_phdr *jph = &phdr[j];
 479
 480                    if (i != j && jph->p_type == PT_LOAD) {
 481                        elf_word other_start = jph->p_paddr;
 482                        elf_word other_end = jph->p_paddr + jph->p_memsz;
 483
 484                        if (!(other_start >= zero_end ||
 485                              zero_start >= other_end)) {
 486                            mem_size = file_size;
 487                            break;
 488                        }
 489                    }
 490                }
 491            }
 492
 493            if (mem_size > INT_MAX - total_size) {
 494                ret = ELF_LOAD_TOO_BIG;
 495                goto fail;
 496            }
 497
 498            /* address_offset is hack for kernel images that are
 499               linked at the wrong physical address.  */
 500            if (translate_fn) {
 501                addr = translate_fn(translate_opaque, ph->p_paddr);
 502                glue(elf_reloc, SZ)(&ehdr, fd, must_swab,  translate_fn,
 503                                    translate_opaque, data, ph, elf_machine);
 504            } else {
 505                addr = ph->p_paddr;
 506            }
 507
 508            if (data_swab) {
 509                int j;
 510                for (j = 0; j < file_size; j += (1 << data_swab)) {
 511                    uint8_t *dp = data + j;
 512                    switch (data_swab) {
 513                    case (1):
 514                        *(uint16_t *)dp = bswap16(*(uint16_t *)dp);
 515                        break;
 516                    case (2):
 517                        *(uint32_t *)dp = bswap32(*(uint32_t *)dp);
 518                        break;
 519                    case (3):
 520                        *(uint64_t *)dp = bswap64(*(uint64_t *)dp);
 521                        break;
 522                    default:
 523                        g_assert_not_reached();
 524                    }
 525                }
 526            }
 527
 528            /* the entry pointer in the ELF header is a virtual
 529             * address, if the text segments paddr and vaddr differ
 530             * we need to adjust the entry */
 531            if (pentry && !translate_fn &&
 532                    ph->p_vaddr != ph->p_paddr &&
 533                    ehdr.e_entry >= ph->p_vaddr &&
 534                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
 535                    ph->p_flags & PF_X) {
 536                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
 537            }
 538
 539            /* Some ELF files really do have segments of zero size;
 540             * just ignore them rather than trying to create empty
 541             * ROM blobs, because the zero-length blob can falsely
 542             * trigger the overlapping-ROM-blobs check.
 543             */
 544            if (mem_size != 0) {
 545                if (load_rom) {
 546                    g_autofree char *label =
 547                        g_strdup_printf("%s ELF program header segment %d",
 548                                        name, i);
 549
 550                    /*
 551                     * rom_add_elf_program() takes its own reference to
 552                     * 'mapped_file'.
 553                     */
 554                    rom_add_elf_program(label, mapped_file, data, file_size,
 555                                        mem_size, addr, as);
 556                } else {
 557                    MemTxResult res;
 558
 559                    res = address_space_write(as ? as : &address_space_memory,
 560                                              addr, MEMTXATTRS_UNSPECIFIED,
 561                                              data, file_size);
 562                    if (res != MEMTX_OK) {
 563                        goto fail;
 564                    }
 565                }
 566            }
 567
 568            total_size += mem_size;
 569            if (addr < low)
 570                low = addr;
 571            if ((addr + mem_size) > high)
 572                high = addr + mem_size;
 573
 574            data = NULL;
 575
 576        } else if (ph->p_type == PT_NOTE && elf_note_fn) {
 577            struct elf_note *nhdr = NULL;
 578
 579            file_size = ph->p_filesz; /* Size of the range of ELF notes */
 580            data_offset = ph->p_offset; /* Offset where the notes are located */
 581
 582            if (file_size > 0) {
 583                if (g_mapped_file_get_length(mapped_file) <
 584                    file_size + data_offset) {
 585                    goto fail;
 586                }
 587
 588                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 589                data += data_offset;
 590            }
 591
 592            /*
 593             * Search the ELF notes to find one with a type matching the
 594             * value passed in via 'translate_opaque'
 595             */
 596            nhdr = (struct elf_note *)data;
 597            assert(translate_opaque != NULL);
 598            nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
 599                                               *(uint64_t *)translate_opaque);
 600            if (nhdr != NULL) {
 601                elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
 602            }
 603            data = NULL;
 604        }
 605    }
 606
 607    if (lowaddr)
 608        *lowaddr = (uint64_t)(elf_sword)low;
 609    if (highaddr)
 610        *highaddr = (uint64_t)(elf_sword)high;
 611    ret = total_size;
 612 fail:
 613    if (mapped_file) {
 614        g_mapped_file_unref(mapped_file);
 615    }
 616    g_free(phdr);
 617    return ret;
 618}
 619