Ejemplo n.º 1
0
// Load the program image into the memory
std::pair<MemAddr, bool>
LoadProgram(const std::string& msg_prefix, vector<ActiveROM::LoadableRange>& ranges, IMemoryAdmin& memory, char* data, MemSize size, bool verbose)
{
    Verify(size >= sizeof(Elf_Ehdr), "ELF file too short or truncated");

    Elf_Ehdr& ehdr = *static_cast<Elf_Ehdr*>(static_cast<void*>(data));

    // Unmarshall header
    ehdr.e_type      = elftohh(ehdr.e_type);
    ehdr.e_machine   = elftohh(ehdr.e_machine);
    ehdr.e_version   = elftohw(ehdr.e_version);
    ehdr.e_entry     = elftoha(ehdr.e_entry);
    ehdr.e_phoff     = elftoho(ehdr.e_phoff);
    ehdr.e_shoff     = elftoho(ehdr.e_shoff);
    ehdr.e_flags     = elftohw(ehdr.e_flags);
    ehdr.e_ehsize    = elftohh(ehdr.e_ehsize);
    ehdr.e_phentsize = elftohh(ehdr.e_phentsize);
    ehdr.e_phnum     = elftohh(ehdr.e_phnum);
    ehdr.e_shentsize = elftohh(ehdr.e_shentsize);
    ehdr.e_shnum     = elftohh(ehdr.e_shnum);
    ehdr.e_shstrndx  = elftohh(ehdr.e_shstrndx);

    // Check file signature
    Verify(ehdr.e_ident[EI_MAG0] == ELFMAG0 && ehdr.e_ident[EI_MAG1] == ELFMAG1 &&
           ehdr.e_ident[EI_MAG2] == ELFMAG2 && ehdr.e_ident[EI_MAG3] == ELFMAG3,
           "invalid ELF file signature");

    // Check that this file is for our 'architecture'
    Verify(ehdr.e_ident[EI_VERSION] == EV_CURRENT,  "ELF version mismatch");
    Verify(ehdr.e_ident[EI_CLASS]   == ELFCLASS,    "file is not of proper bitsize");
    Verify(ehdr.e_ident[EI_DATA]    == ELFDATA,     "file is not of proper endianness");
    Verify(ehdr.e_machine == MACHINE_NORMAL ||
           ehdr.e_machine == MACHINE_LEGACY,       "target architecture is not supported");
    Verify(ehdr.e_type              == ET_EXEC,    "file is not an executable file");
    Verify(ehdr.e_phoff != 0 && ehdr.e_phnum != 0, "file has no program header");
    Verify(ehdr.e_phentsize == sizeof(Elf_Phdr),   "file has an invalid program header");
    Verify(ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize <= size, "file has an invalid program header");
    Verify(ehdr.e_shentsize == sizeof(Elf_Shdr),   "file has an invalid section header");
    Verify(ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize <= size, "file has an invalid section header");

    Elf_Shdr* shdr = static_cast<Elf_Shdr*>(static_cast<void*>(data + ehdr.e_shoff));

    // Load section information
    for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
    {
        shdr[i].sh_name      = elftohw (shdr[i].sh_name);
        shdr[i].sh_type      = elftohw (shdr[i].sh_type);
        shdr[i].sh_addr      = elftoha (shdr[i].sh_addr);
        shdr[i].sh_offset    = elftoho (shdr[i].sh_offset);
        shdr[i].sh_link      = elftohw (shdr[i].sh_link);
        shdr[i].sh_info      = elftohw (shdr[i].sh_info);
#if ELFCLASS == ELFCLASS64
        shdr[i].sh_flags     = elftohxw(shdr[i].sh_flags);
        shdr[i].sh_size      = elftohxw(shdr[i].sh_size);
        shdr[i].sh_addralign = elftohxw(shdr[i].sh_addralign);
        shdr[i].sh_entsize   = elftohxw(shdr[i].sh_entsize);
#else
        shdr[i].sh_flags     = elftohw (shdr[i].sh_flags);
        shdr[i].sh_size      = elftohw (shdr[i].sh_size);
        shdr[i].sh_addralign = elftohw (shdr[i].sh_addralign);
        shdr[i].sh_entsize   = elftohw (shdr[i].sh_entsize);
#endif
    }


    // Find symbol table & corresponding string table
    Elf_Sym* elf_sym_table = 0;
    size_t elf_sym_table_len = 0;
    const char *str_table = 0;
    size_t str_table_len = 0;

    for (Elf_Half i = 0; i < ehdr.e_shnum; ++i)
    {
        if (shdr[i].sh_type == SHT_SYMTAB)
        {
            Verify(shdr[i].sh_entsize == sizeof(Elf_Sym), "file has an invalid symtable");
            Verify(shdr[i].sh_offset + shdr[i].sh_size <= size, "file has an invalid symtable");

            elf_sym_table = static_cast<Elf_Sym*>(static_cast<void*>(data + shdr[i].sh_offset));
            elf_sym_table_len = shdr[i].sh_size / sizeof(Elf_Sym);

            Verify(shdr[i].sh_link != 0 /*SHN_UNDEF*/, "symtable has no string table");
            Verify(shdr[i].sh_link < ehdr.e_shnum, "symtable has an invalid string table");

            Elf_Shdr& strsh = shdr[shdr[i].sh_link];

            Verify(strsh.sh_type == SHT_STRTAB, "file has an invalid string table");
            Verify(strsh.sh_offset + strsh.sh_size <= size, "file has an invalid string table");

            str_table = data + strsh.sh_offset;
            str_table_len = strsh.sh_size;

            break;
        }
    }

    SymbolTable& symtable = memory.GetSymbolTable();
    for (size_t i = 1 /* first entry is unused */; i < elf_sym_table_len; ++i)
    {
        elf_sym_table[i].st_name = elftohw(elf_sym_table[i].st_name);
        elf_sym_table[i].st_value = elftoha(elf_sym_table[i].st_value);
#if ELFCLASS == ELFCLASS64
        elf_sym_table[i].st_size = elftohxw(elf_sym_table[i].st_size);
#else
        elf_sym_table[i].st_size = elftohw(elf_sym_table[i].st_size);
#endif

        Verify(elf_sym_table[i].st_name < str_table_len, "file specifies an invalid symbol");

        const char* name = str_table + elf_sym_table[i].st_name;
        MemAddr addr = elf_sym_table[i].st_value;
        if (addr != 0 && strlen(name) > 0)
        {
            symtable.AddSymbol(addr, name, elf_sym_table[i].st_size);
        }
    }

    Elf_Phdr* phdr = static_cast<Elf_Phdr*>(static_cast<void*>(data + ehdr.e_phoff));

    // Determine base address and check for loadable segments
    bool     hasLoadable = false;
    Elf_Addr base = 0;
    for (Elf_Half i = 0; i < ehdr.e_phnum; ++i)
    {
        phdr[i].p_type   = elftohw (phdr[i].p_type);
        phdr[i].p_flags  = elftohw (phdr[i].p_flags);
        phdr[i].p_offset = elftoho (phdr[i].p_offset);
        phdr[i].p_vaddr  = elftoha (phdr[i].p_vaddr);
        phdr[i].p_paddr  = elftoha (phdr[i].p_paddr);
        phdr[i].p_filesz = elftohxw(phdr[i].p_filesz);
        phdr[i].p_memsz  = elftohxw(phdr[i].p_memsz);
        phdr[i].p_align  = elftohxw(phdr[i].p_align);

        if (phdr[i].p_type == PT_LOAD)
        {
            if (!hasLoadable || phdr[i].p_vaddr < base) {
                base = phdr[i].p_vaddr;
            }
            hasLoadable = true;
        }
    }
    // Verify(hasLoadable, "file has no loadable segments");
    base = base & -PAGE_SIZE;

    // Then copy the LOAD segments into their right locations
    for (Elf_Half i = 0; i < ehdr.e_phnum; ++i)
    {
        if (phdr[i].p_type == PT_LOAD && phdr[i].p_memsz > 0)
        {
            Verify(phdr[i].p_memsz >= phdr[i].p_filesz, "file has an invalid segment");

            int perm = 0;
            if (phdr[i].p_flags & PF_R) perm |= IMemory::PERM_READ|IMemory::PERM_DCA_READ;
            if (phdr[i].p_flags & PF_W) perm |= IMemory::PERM_WRITE|IMemory::PERM_DCA_WRITE;
            if (phdr[i].p_flags & PF_X) perm |= IMemory::PERM_EXECUTE;

            if (phdr[i].p_filesz > 0)
            {
                Verify(phdr[i].p_offset + phdr[i].p_filesz <= size, "file has an invalid segment");

                ActiveROM::LoadableRange r;
                r.rom_offset = phdr[i].p_offset;
                r.rom_size = phdr[i].p_filesz;
                r.vaddr = phdr[i].p_vaddr;
                r.vsize = phdr[i].p_memsz;
                r.perm = (IMemory::Permissions)perm;
                ranges.push_back(r);

                // We do not reserve here because this
                // will be taken care of by the ActiveROM during loading.
                if (verbose)
                {
                    clog << msg_prefix << ": " << dec << phdr[i].p_filesz << " bytes loadable at virtual address 0x" << hex << phdr[i].p_vaddr << endl;
                }
            }
            else
            {
                memory.Reserve(phdr[i].p_vaddr, phdr[i].p_memsz, 0, perm);
                if (verbose)
                {
                    clog << msg_prefix << ": " << dec << phdr[i].p_memsz << " bytes reserved at virtual address 0x" << hex << phdr[i].p_vaddr << endl;
                }
            }
        }
    }

    if (verbose)
    {
        const char* type = (ehdr.e_machine == MACHINE_LEGACY)
            ? "legacy"
            : "microthreaded";

        clog << msg_prefix << ": loaded " << type << " ELF binary with virtual base address 0x" << hex << base
             << ", entry point at 0x" << hex << ehdr.e_entry << endl;
    }
    return make_pair(ehdr.e_entry, ehdr.e_machine == MACHINE_LEGACY);
}