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_MIPS:
 372        case EM_NANOMIPS:
 373            if ((ehdr.e_machine != EM_MIPS) &&
 374                (ehdr.e_machine != EM_NANOMIPS)) {
 375                ret = ELF_LOAD_WRONG_ARCH;
 376                goto fail;
 377            }
 378            break;
 379        default:
 380            if (elf_machine != ehdr.e_machine) {
 381                ret = ELF_LOAD_WRONG_ARCH;
 382                goto fail;
 383            }
 384    }
 385
 386    if (pflags) {
 387        *pflags = (elf_word)ehdr.e_flags;
 388    }
 389    if (pentry)
 390        *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
 391
 392    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
 393
 394    size = ehdr.e_phnum * sizeof(phdr[0]);
 395    if (lseek(fd, ehdr.e_phoff, SEEK_SET) != ehdr.e_phoff) {
 396        goto fail;
 397    }
 398    phdr = g_malloc0(size);
 399    if (!phdr)
 400        goto fail;
 401    if (read(fd, phdr, size) != size)
 402        goto fail;
 403    if (must_swab) {
 404        for(i = 0; i < ehdr.e_phnum; i++) {
 405            ph = &phdr[i];
 406            glue(bswap_phdr, SZ)(ph);
 407        }
 408    }
 409
 410    /*
 411     * Since we want to be able to modify the mapped buffer, we set the
 412     * 'writable' parameter to 'true'. Modifications to the buffer are not
 413     * written back to the file.
 414     */
 415    mapped_file = g_mapped_file_new_from_fd(fd, true, NULL);
 416    if (!mapped_file) {
 417        goto fail;
 418    }
 419
 420    total_size = 0;
 421    for(i = 0; i < ehdr.e_phnum; i++) {
 422        ph = &phdr[i];
 423        if (ph->p_type == PT_LOAD) {
 424            mem_size = ph->p_memsz; /* Size of the ROM */
 425            file_size = ph->p_filesz; /* Size of the allocated data */
 426            data_offset = ph->p_offset; /* Offset where the data is located */
 427
 428            if (file_size > 0) {
 429                if (g_mapped_file_get_length(mapped_file) <
 430                    file_size + data_offset) {
 431                    goto fail;
 432                }
 433
 434                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 435                data += data_offset;
 436            }
 437
 438            /* The ELF spec is somewhat vague about the purpose of the
 439             * physical address field. One common use in the embedded world
 440             * is that physical address field specifies the load address
 441             * and the virtual address field specifies the execution address.
 442             * Segments are packed into ROM or flash, and the relocation
 443             * and zero-initialization of data is done at runtime. This
 444             * means that the memsz header represents the runtime size of the
 445             * segment, but the filesz represents the loadtime size. If
 446             * we try to honour the memsz value for an ELF file like this
 447             * we will end up with overlapping segments (which the
 448             * loader.c code will later reject).
 449             * We support ELF files using this scheme by by checking whether
 450             * paddr + memsz for this segment would overlap with any other
 451             * segment. If so, then we assume it's using this scheme and
 452             * truncate the loaded segment to the filesz size.
 453             * If the segment considered as being memsz size doesn't overlap
 454             * then we use memsz for the segment length, to handle ELF files
 455             * which assume that the loader will do the zero-initialization.
 456             */
 457            if (mem_size > file_size) {
 458                /* If this segment's zero-init portion overlaps another
 459                 * segment's data or zero-init portion, then truncate this one.
 460                 * Invalid ELF files where the segments overlap even when
 461                 * only file_size bytes are loaded will be rejected by
 462                 * the ROM overlap check in loader.c, so we don't try to
 463                 * explicitly detect those here.
 464                 */
 465                int j;
 466                elf_word zero_start = ph->p_paddr + file_size;
 467                elf_word zero_end = ph->p_paddr + mem_size;
 468
 469                for (j = 0; j < ehdr.e_phnum; j++) {
 470                    struct elf_phdr *jph = &phdr[j];
 471
 472                    if (i != j && jph->p_type == PT_LOAD) {
 473                        elf_word other_start = jph->p_paddr;
 474                        elf_word other_end = jph->p_paddr + jph->p_memsz;
 475
 476                        if (!(other_start >= zero_end ||
 477                              zero_start >= other_end)) {
 478                            mem_size = file_size;
 479                            break;
 480                        }
 481                    }
 482                }
 483            }
 484
 485            if (mem_size > INT_MAX - total_size) {
 486                ret = ELF_LOAD_TOO_BIG;
 487                goto fail;
 488            }
 489
 490            /* address_offset is hack for kernel images that are
 491               linked at the wrong physical address.  */
 492            if (translate_fn) {
 493                addr = translate_fn(translate_opaque, ph->p_paddr);
 494                glue(elf_reloc, SZ)(&ehdr, fd, must_swab,  translate_fn,
 495                                    translate_opaque, data, ph, elf_machine);
 496            } else {
 497                addr = ph->p_paddr;
 498            }
 499
 500            if (data_swab) {
 501                int j;
 502                for (j = 0; j < file_size; j += (1 << data_swab)) {
 503                    uint8_t *dp = data + j;
 504                    switch (data_swab) {
 505                    case (1):
 506                        *(uint16_t *)dp = bswap16(*(uint16_t *)dp);
 507                        break;
 508                    case (2):
 509                        *(uint32_t *)dp = bswap32(*(uint32_t *)dp);
 510                        break;
 511                    case (3):
 512                        *(uint64_t *)dp = bswap64(*(uint64_t *)dp);
 513                        break;
 514                    default:
 515                        g_assert_not_reached();
 516                    }
 517                }
 518            }
 519
 520            /* the entry pointer in the ELF header is a virtual
 521             * address, if the text segments paddr and vaddr differ
 522             * we need to adjust the entry */
 523            if (pentry && !translate_fn &&
 524                    ph->p_vaddr != ph->p_paddr &&
 525                    ehdr.e_entry >= ph->p_vaddr &&
 526                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
 527                    ph->p_flags & PF_X) {
 528                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
 529            }
 530
 531            /* Some ELF files really do have segments of zero size;
 532             * just ignore them rather than trying to create empty
 533             * ROM blobs, because the zero-length blob can falsely
 534             * trigger the overlapping-ROM-blobs check.
 535             */
 536            if (mem_size != 0) {
 537                if (load_rom) {
 538                    g_autofree char *label =
 539                        g_strdup_printf("%s ELF program header segment %d",
 540                                        name, i);
 541
 542                    /*
 543                     * rom_add_elf_program() takes its own reference to
 544                     * 'mapped_file'.
 545                     */
 546                    rom_add_elf_program(label, mapped_file, data, file_size,
 547                                        mem_size, addr, as);
 548                } else {
 549                    MemTxResult res;
 550
 551                    res = address_space_write(as ? as : &address_space_memory,
 552                                              addr, MEMTXATTRS_UNSPECIFIED,
 553                                              data, file_size);
 554                    if (res != MEMTX_OK) {
 555                        goto fail;
 556                    }
 557                }
 558            }
 559
 560            total_size += mem_size;
 561            if (addr < low)
 562                low = addr;
 563            if ((addr + mem_size) > high)
 564                high = addr + mem_size;
 565
 566            data = NULL;
 567
 568        } else if (ph->p_type == PT_NOTE && elf_note_fn) {
 569            struct elf_note *nhdr = NULL;
 570
 571            file_size = ph->p_filesz; /* Size of the range of ELF notes */
 572            data_offset = ph->p_offset; /* Offset where the notes are located */
 573
 574            if (file_size > 0) {
 575                if (g_mapped_file_get_length(mapped_file) <
 576                    file_size + data_offset) {
 577                    goto fail;
 578                }
 579
 580                data = (uint8_t *)g_mapped_file_get_contents(mapped_file);
 581                data += data_offset;
 582            }
 583
 584            /*
 585             * Search the ELF notes to find one with a type matching the
 586             * value passed in via 'translate_opaque'
 587             */
 588            nhdr = (struct elf_note *)data;
 589            assert(translate_opaque != NULL);
 590            nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
 591                                               *(uint64_t *)translate_opaque);
 592            if (nhdr != NULL) {
 593                elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
 594            }
 595            data = NULL;
 596        }
 597    }
 598
 599    if (lowaddr)
 600        *lowaddr = (uint64_t)(elf_sword)low;
 601    if (highaddr)
 602        *highaddr = (uint64_t)(elf_sword)high;
 603    ret = total_size;
 604 fail:
 605    if (mapped_file) {
 606        g_mapped_file_unref(mapped_file);
 607    }
 608    g_free(phdr);
 609    return ret;
 610}
 611