OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [elf.cpp] - Rev 106

Go to most recent revision | Compare with Previous | Blame | View Log

/****************************    elf.cpp    *********************************
* Author:        Agner Fog
* Date created:  2006-07-18
* Last modified: 2021-05-28
* Version:       1.11
* Project:       Binary tools for ForwardCom instruction set
* Module:        elf.cpp
* Description:
* Module for manipulating ForwardCom ELF files
*
* Class CELF is used for manipulating ELF files.
* It includes functions for reading, interpreting, dumping files,
* splitting into containers or joining containers into an ELF file
*
* This code is based on the ForwardCom ELF specification in elf_forwardcom.h.
* I have included limited support for x86-64 ELF (e_machine == EM_X86_64) for 
* testing purposes. This may be removed.
*
* Copyright 2006-2021 GNU General Public License v. 3 http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
 
// File class names
SIntTxt ELFFileClassNames[] = {
    {ELFCLASSNONE,      "None"},
    {ELFCLASS32,        "32-bit object"},
    {ELFCLASS64,        "64-bit object"}
};
 
// Data encoding names
SIntTxt ELFDataEncodeNames[] = {
    {ELFDATANONE,       "None"},
    {ELFDATA2LSB,       "Little Endian"},
    {ELFDATA2MSB,       "Big Endian"}
};
 
// ABI names
SIntTxt ELFABINames[] = {
    {ELFOSABI_SYSV,      "System V"},
    {ELFOSABI_HPUX,      "HP-UX"},
    {ELFOSABI_ARM,       "ARM"},
    {ELFOSABI_STANDALONE,"Embedded"},
    {ELFOSABI_FORWARDCOM,"ForwardCom"}
};
 
// File type names
SIntTxt ELFFileTypeNames[] = {
    {ET_NONE,           "None"},
    {ET_REL,            "Relocatable"},
    {ET_EXEC,           "Executable"},
    {ET_DYN,            "Shared object"},
    {ET_CORE,           "Core file"}
};
 
// File header flag names
SIntTxt ELFFileFlagNames[] = {
    {EF_INCOMPLETE,     "Has unresolved references"},
    {EF_RELINKABLE,     "Relinkable"},
    {EF_RELOCATE,       "Relocate when loading"},
    {EF_POSITION_DEPENDENT, "Position dependent"}
};
 
 
// Section type names
SIntTxt ELFSectionTypeNames[] = {
    {SHT_NULL,          "None"},
    {SHT_PROGBITS,      "Program data"},
    {SHT_SYMTAB,        "Symbol table"},
    {SHT_STRTAB,        "String table"},
    {SHT_RELA,          "Relocation w addends"},
    {SHT_NOTE,          "Notes"},
    {SHT_NOBITS,        "uinitialized"},
    {SHT_COMDAT,        "Communal section"},    
    {SHT_LIST,          "List"}    
//    {SHT_HASH,          "Symbol hash table"},
//    {SHT_DYNAMIC,       "Dynamic linking info"},
//    {SHT_REL,           "Relocation entries"},
//    {SHT_SHLIB,         "Reserved"},
//    {SHT_DYNSYM,        "Dynamic linker symbol table"},
//    {SHT_GROUP,         "Section group"},
};
 
// Program header type names
SIntTxt ELFPTypeNames[] = {
     {PT_NULL,        "Unused"},
     {PT_LOAD,        "Loadable program segment"},
     {PT_DYNAMIC,     "Dynamic linking information"},
     {PT_INTERP,      "Program interpreter"},
     {PT_NOTE,        "Auxiliary information"},
     {PT_SHLIB,       "Reserved"},
     {PT_PHDR,        "Entry for header table itself"}
};
 
// Section flag names
SIntTxt ELFSectionFlagNames[] = {
    {SHF_EXEC,          "executable"},
    {SHF_WRITE,         "writeable"},
    {SHF_READ,          "readable"},
    {SHF_ALLOC,         "allocate"},
    {SHF_IP,            "IP"},
    {SHF_DATAP,         "DATAP"},
    {SHF_THREADP,       "THREADP"},
    {SHF_MERGE,         "merge"},
    {SHF_STRINGS,       "strings"},
    {SHF_INFO_LINK,     "sh_info"},
    {SHF_EVENT_HND,     "event handler"},
    {SHF_DEBUG_INFO,    "debug info"},
    {SHF_COMMENT,       "comment"},
    {SHF_RELINK,        "relinkable"},
    {SHF_AUTOGEN,       "auto-generated"}
};
 
// Symbol binding names
SIntTxt ELFSymbolBindingNames[] = {
    {STB_LOCAL,         "local"},
    {STB_GLOBAL,        "global"},
    {STB_WEAK,          "weak"},
    {STB_WEAK2,         "weak2"},
    {STB_UNRESOLVED,    "unresolved"}
};
 
// Symbol Type names
SIntTxt ELFSymbolTypeNames[] = {
    {STT_NOTYPE,        "None"},
    {STT_OBJECT,        "Object"},
    {STT_FUNC,          "Function"},
    {STT_SECTION,       "Section"},
    {STT_FILE,          "File"},
    {STT_CONSTANT,      "Constant"}
};
 
// Symbol st_other info names
SIntTxt ELFSymbolInfoNames[] = {
    {STV_EXEC,          "executable"},
    {STV_READ,          "read"},
    {STV_WRITE,         "write"},
    {STV_IP,            "ip"},
    {STV_DATAP,         "datap"},
    {STV_THREADP,       "threadp"},
    {STV_REGUSE,        "reguse"},
    {STV_FLOAT,         "float"},
    {STV_STRING,        "string"}, 
    {STV_UNWIND,        "unwind"},
    {STV_DEBUG,         "debug"},
    {STV_COMMON,        "communal"},
    {STV_RELINK,        "relinkable"},
    {STV_MAIN,          "main"},
    {STV_EXPORTED,      "exported"},
    {STV_THREAD,        "thread"}
};
 
// Relocation type names x86 64 bit
SIntTxt ELF64RelocationNames[] = {
    {R_X86_64_NONE,      "None"},
    {R_X86_64_64,        "Direct 64 bit"},
    {R_X86_64_PC32,      "Self relative 32 bit signed"},
    {R_X86_64_GOT32,     "32 bit GOT entry"},
    {R_X86_64_PLT32,     "32 bit PLT address"},
    {R_X86_64_COPY,      "Copy symbol at runtime"},
    {R_X86_64_GLOB_DAT,  "Create GOT entry"},
    {R_X86_64_JUMP_SLOT, "Create PLT entry"},
    {R_X86_64_RELATIVE,  "Adjust by program base"},
    {R_X86_64_GOTPCREL,  "32 bit signed pc relative offset to GOT"},
    {R_X86_64_32,        "Direct 32 bit zero extended"},
    {R_X86_64_32S,       "Direct 32 bit sign extended"},
    {R_X86_64_16,        "Direct 16 bit zero extended"},
    {R_X86_64_PC16,      "16 bit sign extended pc relative"},
    {R_X86_64_8,         "Direct 8 bit sign extended"},
    {R_X86_64_PC8,       "8 bit sign extended pc relative"},
    {R_X86_64_IRELATIVE, "32 bit ref. to indirect function PLT"}
};
 
// Relocation type names for ForwardCom
SIntTxt ELFFwcRelocationTypes[] = {
    {R_FORW_ABS,        "Absolute address"},
    {R_FORW_SELFREL,    "Self relative"},
    {R_FORW_IP_BASE,    "Relative to __ip_base"},
    {R_FORW_DATAP,      "Relative to __datap_base"},
    {R_FORW_THREADP,    "Relative to __threadp_base"},
    {R_FORW_REFP,       "Relative to arbitrary reference point"},
    {R_FORW_SYSFUNC,    "System function ID"},
    {R_FORW_SYSMODUL,   "System module ID"},
    {R_FORW_SYSCALL,    "System module and function ID"},
    {R_FORW_DATASTACK,  "Size of data stack"},
    {R_FORW_CALLSTACK,  "Size of call stack"},
    {R_FORW_REGUSE,     "Register use"}
};
 
// Relocation sizes for ForwardCom
SIntTxt ELFFwcRelocationSizes[] = {
    {R_FORW_NONE,       "None"},
    {R_FORW_8,          "8 bit"},
    {R_FORW_16,         "16 bit"},
    {R_FORW_24,         "24 bit"},
    {R_FORW_32,         "32 bit"},
    {R_FORW_64,         "64 bit"},
    {R_FORW_32LO,       "Low 16 of 32 bits"},
    {R_FORW_32HI,       "High 16 of 32 bits"},
    {R_FORW_64LO,       "Low 32 of 64 bits"},
    {R_FORW_64HI,       "High 32 of 64 bits"}
};
 
// Machine names
SIntTxt ELFMachineNames[] = {
    {EM_NONE,         "None"},     // No machine
    {EM_FORWARDCOM,   "ForwardCom"},
    {EM_M32,          "AT&T WE 32100"},
    {EM_SPARC,        "SPARC"},
    {EM_386,          "Intel x86"},
    {EM_68K,          "Motorola m68k"},
    {EM_88K,          "Motorola m88k"},
    {EM_860,          "MIPS R3000 big-endian"},
    {EM_MIPS,         "MIPS R3000 big-endian"},
    {EM_S370,         "IBM System/370"},
    {EM_MIPS_RS3_LE,  "NMIPS R3000 little-endianone"},
    {EM_PARISC,       "HPPA"},
    {EM_VPP500,       "Fujitsu VPP500"},
    {EM_SPARC32PLUS,  "Sun v8plus"},
    {EM_960,          "Intel 80960"},
    {EM_PPC,          "PowerPC"},
    {EM_PPC64,        "PowerPC 64-bit"},
    {EM_S390,         "IBM S390"},
    {EM_V800,         "NEC V800"},
    {EM_FR20,         "Fujitsu FR20"},
    {EM_RH32,         "TRW RH-32"},
    {EM_RCE,          "Motorola RCE"},
    {EM_ARM,          "ARM"},
    {EM_FAKE_ALPHA,   "Digital Alpha"},
    {EM_SH,           "Hitachi SH"},
    {EM_SPARCV9,      "SPARC v9 64-bit"},
    {EM_TRICORE,      "Siemens Tricore"},
    {EM_ARC,          "Argonaut RISC"},
    {EM_H8_300,       "Hitachi H8/300"},
    {EM_H8_300H,      "Hitachi H8/300H"},
    {EM_H8S,          "Hitachi H8S"},
    {EM_H8_500,       "EM_H8_500"},
    {EM_IA_64,        "Intel IA64"},
    {EM_MIPS_X,       "Stanford MIPS-X"},
    {EM_COLDFIRE,     "Motorola Coldfire"},
    {EM_68HC12,       "Motorola M68HC12"},
    {EM_MMA,          "Fujitsu MMA"},
    {EM_PCP,          "Siemens PCP"},
    {EM_NCPU,         "Sony nCPU"},
    {EM_NDR1,         "Denso NDR1"},
    {EM_STARCORE,     "Motorola Start*Core"},
    {EM_ME16,         "Toyota ME16"},
    {EM_ST100,        "ST100"},
    {EM_TINYJ,        "Tinyj"},
    {EM_X86_64,       "x86-64"},
    {EM_PDSP,         "Sony DSP"},
    {EM_FX66,         "Siemens FX66"},
    {EM_ST9PLUS,      "ST9+ 8/16"},
    {EM_ST7,          "ST7 8"},
    {EM_68HC16,       "MC68HC16"},
    {EM_68HC11,       "MC68HC11"},
    {EM_68HC08,       "MC68HC08"},
    {EM_68HC05,       "MC68HC05"},
    {EM_SVX,          "SVx"},
    {EM_AT19,         "ST19"},
    {EM_VAX,          "VAX"},
    {EM_CRIS,         "Axis"},
    {EM_JAVELIN,      "Infineon"},
    {EM_FIREPATH,     "Element 14"},
    {EM_ZSP,          "LSI Logic"},
    {EM_HUANY,        "Harvard"},
    {EM_PRISM,        "SiTera Prism"},
    {EM_AVR,          "Atmel AVR"},
    {EM_FR30,         "FR30"},
    {EM_D10V,         "D10V"},
    {EM_D30V,         "D30V"},
    {EM_V850,         "NEC v850"},
    {EM_M32R,         "M32R"},
    {EM_MN10300,      "MN10300"},
    {EM_MN10200,      "MN10200"},
    {EM_PJ,           "picoJava"},
    {EM_ALPHA,        "Alpha"}
};
 
 
// Class CELF members:
// Constructor
CELF::CELF() {
    zeroAllMembers(*this);
}
 
// ParseFile
void CELF::parseFile() {
    // Load and parse file buffer
    uint32_t i;
    if (dataSize() == 0) {
        nSections = 0;
        return;
    }
    fileHeader = *(ElfFwcEhdr*)buf();             // Copy file header
    nSections = fileHeader.e_shnum;
    sectionHeaders.setNum(nSections);            // Allocate space for section headers
    uint32_t symtabi = 0;                         // Index to symbol table
 
    // Find section headers
    sectionHeaderSize = fileHeader.e_shentsize;
    if (sectionHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
    uint32_t SectionOffset = uint32_t(fileHeader.e_shoff);
    // check header integrity
    if (fileHeader.e_phoff >= dataSize() || fileHeader.e_phoff + (uint32_t)fileHeader.e_phentsize * fileHeader.e_phnum > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
    if (fileHeader.e_shoff >= dataSize() || fileHeader.e_shoff + (uint32_t)fileHeader.e_shentsize * fileHeader.e_shnum > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
    if (fileHeader.e_shstrndx >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
    if (err.number()) 
        return;
 
    for (i = 0; i < nSections; i++) {
        sectionHeaders[i] = get<ElfFwcShdr>(SectionOffset);
        // check section header integrity
        if (sectionHeaders[i].sh_offset > dataSize() 
            || (sectionHeaders[i].sh_offset + sectionHeaders[i].sh_size > dataSize() && sectionHeaders[i].sh_type != SHT_NOBITS)
            || sectionHeaders[i].sh_offset + sectionHeaders[i].sh_entsize > dataSize()) {
            err.submit(ERR_ELF_INDEX_RANGE);
        }
        SectionOffset += sectionHeaderSize;
        if (sectionHeaders[i].sh_type == SHT_SYMTAB) {
            // Symbol table found
            symtabi = i;
        }
    }
    if (SectionOffset > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);     // Section table points to outside file
 
    if (buf() && dataSize()) {  // string table
        uint64_t offset = sectionHeaders[fileHeader.e_shstrndx].sh_offset;
        secStringTable = (char*)buf() + uint32_t(offset);
        secStringTableLen = uint32_t(sectionHeaders[fileHeader.e_shstrndx].sh_size);
        if (offset > dataSize() || offset + secStringTableLen > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
    }
    // check section names
    for (i = 0; i < nSections; i++) {
        if (sectionHeaders[i].sh_name >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); break; }
    }
 
    if (symtabi) {
        // Save offset to symbol table
        uint64_t offset = sectionHeaders[symtabi].sh_offset;
        symbolTableOffset = (uint32_t)offset;
        symbolTableEntrySize = (uint32_t)(sectionHeaders[symtabi].sh_entsize); // Entry size of symbol table
        if (symbolTableEntrySize == 0) { err.submit(ERR_ELF_SYMTAB_MISSING); return; } // Avoid division by zero
        symbolTableEntries = uint32_t(sectionHeaders[symtabi].sh_size) / symbolTableEntrySize;
        if (offset > dataSize() || offset > 0xFFFFFFFFU || offset + sectionHeaders[symtabi].sh_entsize > dataSize()
            || offset + sectionHeaders[symtabi].sh_size > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
 
        // Find associated string table
        uint32_t stringtabi = sectionHeaders[symtabi].sh_link;
        if (stringtabi >= nSections) {
            err.submit(ERR_ELF_INDEX_RANGE);
            return;
        }
        offset = sectionHeaders[stringtabi].sh_offset;
        symbolStringTableOffset = (uint32_t)offset;
        symbolStringTableSize = (uint32_t)(sectionHeaders[stringtabi].sh_size);
        if (offset > dataSize() || offset > 0xFFFFFFFFU || offset + sectionHeaders[stringtabi].sh_size > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
        // check all symbol names
        int8_t * symtab = buf() + symbolTableOffset;
        uint32_t symname = 0;
        for (uint32_t symi = 0; symi < symbolTableEntries; symi++) {
            // Copy ElfFwcSym symbol or convert Elf64_Sym symbol
            if (fileHeader.e_machine == EM_FORWARDCOM) {
                symname = ((ElfFwcSym*)symtab)[symi].st_name;
            }
            else {
                // x64 type symbol table entry
                symname = ((Elf64_Sym*)symtab)[symi].st_name;
            }
            if (symname >= symbolStringTableSize) err.submit(ERR_ELF_STRING_TABLE);
        } 
    }
}
 
// Dump
void CELF::dump(int options) {
    printf("\nDump of ELF file %s", cmd.getFilename(cmd.inputFile));
 
    if (options == 0) options = DUMP_FILEHDR;
 
    if (options & DUMP_FILEHDR) {
        // File header
        printf("\n-----------------------------------------------");
        printf("\nFile size: %i", dataSize());
        printf("\nFile header:");
        printf("\nFile class: %s, Data encoding: %s, ELF version %i, ABI: %s, ABI version %i",
            Lookup(ELFFileClassNames, fileHeader.e_ident[EI_CLASS]),
            Lookup(ELFDataEncodeNames, fileHeader.e_ident[EI_DATA]),
            fileHeader.e_ident[EI_VERSION],
            Lookup(ELFABINames, fileHeader.e_ident[EI_OSABI]),
            fileHeader.e_ident[EI_ABIVERSION]);
 
        printf("\nFile type: %s, Machine: %s, version: %i",
            Lookup(ELFFileTypeNames, fileHeader.e_type),
            Lookup(ELFMachineNames, fileHeader.e_machine),
            fileHeader.e_version);
 
        printf("\nNumber of sections: %2i", nSections);
 
        if (fileHeader.e_machine == EM_FORWARDCOM) {
            printf("\nip_base: 0x%X, datap_base: 0x%X, threadp_base: 0x%X, entry_point: 0x%X", 
                (uint32_t)fileHeader.e_ip_base, (uint32_t)fileHeader.e_datap_base, (uint32_t)fileHeader.e_threadp_base, (uint32_t)fileHeader.e_entry);
        }
    }
    // Always show flags
    if (fileHeader.e_flags) {
        printf("\nFlags:");
        for (int i = 0; i < 32; i++) {
            if (fileHeader.e_flags & (1 << i)) {
                printf(" %s,", Lookup(ELFFileFlagNames, 1 << i));
            }
        }
    }
 
    if (options & DUMP_LINKMAP) {
        fprintf(stdout, "\nLink map:\n");
        makeLinkMap(stdout);
    } 
 
    if (options & DUMP_RELINKABLE) {
        // Show names of relinkable modules and libraries
        CDynamicArray<SLCommand> mnames;  // list of relinkable modules
        CDynamicArray<SLCommand> lnames;  // list of relinkable libraries
        SLCommand nameRec;                // record containing name
        uint32_t r;                       // record index
        uint32_t sec;                     // section index
        const char * modName;             // module name
        const char * libName;             // library name
        // loop through sections
        for (sec = 0; sec < sectionHeaders.numEntries(); sec++) {
            ElfFwcShdr & secHdr = sectionHeaders[sec];
            if (secHdr.sh_type == 0) continue;
 
            if (secHdr.sh_flags & SHF_RELINK) {
                // section is relinkable
                if (secHdr.sh_library && secHdr.sh_library < secStringTableLen) {
                    libName = secStringTable + secHdr.sh_library;             // library name
                    nameRec.value = cmd.fileNameBuffer.pushString(libName);
                    lnames.addUnique(nameRec);                                // add only one instance to lnames
                }
                if (secHdr.sh_module && secHdr.sh_module < secStringTableLen) {
                    modName = secStringTable + secHdr.sh_module;              // module name
                    nameRec.value = cmd.fileNameBuffer.pushString(modName);
                    mnames.addUnique(nameRec);                                // add only one instance to mnames
                }
            }
        }
        if (lnames.numEntries()) {
            printf("\n\nRelinkable libraries:");
            for (r = 0; r < lnames.numEntries(); r++) {
                printf("\n   %s", cmd.getFilename((uint32_t)lnames[r].value));
            }
        }
        if (mnames.numEntries()) {
            printf("\n\nRelinkable modules:");
            for (r = 0; r < mnames.numEntries(); r++) {
                printf("\n   %s", cmd.getFilename((uint32_t)mnames[r].value));
            }
        }
    }
 
    if ((options & DUMP_SECTHDR) && fileHeader.e_phnum) {
        // Dump program headers
        printf("\n\nProgram headers:");
        uint32_t nProgramHeaders = fileHeader.e_phnum;
        uint32_t programHeaderSize = fileHeader.e_phentsize;
        if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
        uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
        ElfFwcPhdr pHeader;
        for (uint32_t i = 0; i < nProgramHeaders; i++) {
            pHeader = get<ElfFwcPhdr>(programHeaderOffset);
            printf("\nProgram header Type: %s, flags 0x%X",
                Lookup(ELFPTypeNames, (uint32_t)pHeader.p_type), (uint32_t)pHeader.p_flags);
            printf("\noffset = 0x%X, vaddr = 0x%X, paddr = 0x%X, filesize = 0x%X, memsize = 0x%X, align = 0x%X",
                (uint32_t)pHeader.p_offset, (uint32_t)pHeader.p_vaddr, (uint32_t)pHeader.p_paddr, (uint32_t)pHeader.p_filesz, (uint32_t)pHeader.p_memsz, 1 << pHeader.p_align);
            programHeaderOffset += programHeaderSize;
            if (pHeader.p_filesz < 0x100 && (uint32_t)pHeader.p_offset < dataSize() && (pHeader.p_flags & SHF_STRINGS)) {
                printf("\nContents: %s", buf() + (int)pHeader.p_offset);
            }
        }
    }
 
    if (options & DUMP_SECTHDR) {
        // Dump section headers
        printf("\n\nSection headers:");
        for (uint32_t sc = 0; sc < nSections; sc++) {
            // Get copy of 32-bit header or converted 64-bit header
            ElfFwcShdr sheader = sectionHeaders[sc];
            uint32_t entrysize = (uint32_t)(sheader.sh_entsize);
            uint32_t namei = sheader.sh_name;
            if (namei >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); break; }
            printf("\n%2i Name: %-18s Type: %s", sc, secStringTable + namei,
                Lookup(ELFSectionTypeNames, sheader.sh_type));
            if (sheader.sh_flags) {
                printf("\n  Flags: 0x%X:", uint32_t(sheader.sh_flags));
                for (uint32_t fi = 1; fi != 0; fi <<= 1) {
                    if (uint32_t(sheader.sh_flags) & fi) {
                        printf(" %s", Lookup(ELFSectionFlagNames, fi));
                    }
                }
            }
            //if (sheader.sh_addr) 
                printf("\n  Address: 0x%X", uint32_t(sheader.sh_addr));
            if (sheader.sh_offset || sheader.sh_size) {
                printf("\n  FileOffset: 0x%X, Size: 0x%X",
                    uint32_t(sheader.sh_offset), uint32_t(sheader.sh_size));
            }
            if (sheader.sh_align) {
                printf("\n  Alignment: 0x%X", 1 << sheader.sh_align);
            }
            if (sheader.sh_entsize) {
                printf("\n  Entry size: 0x%X", uint32_t(sheader.sh_entsize));
                switch (sheader.sh_type) {
                /*
                case SHT_DYNAMIC:
                    printf("\n  String table: %i", sheader.sh_link);
                    break;
                case SHT_HASH:
                    printf("\n  Symbol table: %i", sheader.sh_link);
                    break; */
                case SHT_RELA: // case SHT_REL:
                    printf("\n  Symbol table: %i",
                        sheader.sh_link);
                    break;
                case SHT_SYMTAB: //case SHT_DYNSYM:
                    printf("\n  Symbol string table: %i, First global symbol: %i",
                        sheader.sh_link, sheader.sh_module);
                    break;
                default:
                    if (sheader.sh_link) {
                        printf("\n  Link: %i", sheader.sh_link);
                    }
                    if (sheader.sh_module) {
                        printf("\n  Info: %i", sheader.sh_module);
                    }
                }
            }
            if (sheader.sh_module && sheader.sh_module < secStringTableLen) {
                printf("\n  Module: %s", secStringTable + sheader.sh_module);
                if (sheader.sh_library) printf(", Library: %s", secStringTable + sheader.sh_library);
            }
 
            if (sheader.sh_type == SHT_STRTAB && (options & DUMP_STRINGTB)) {
                // Print string table
                printf("\n  String table:");
                char * p = (char*)buf() + uint32_t(sheader.sh_offset) + 1;
                uint32_t nread = 1, len;
                while (nread < uint32_t(sheader.sh_size)) {
                    len = (uint32_t)strlen(p);
                    printf(" >>%s<<", p);
                    nread += len + 1;
                    p += len + 1;
                }
            }
            if ((sheader.sh_type == SHT_SYMTAB) && (options & DUMP_SYMTAB)) {
                // Dump symbol table
 
                // Find associated string table
                if (sheader.sh_link >= (uint32_t)nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
                uint64_t strtabOffset = sectionHeaders[sheader.sh_link].sh_offset;
                if (strtabOffset >= dataSize()) {
                    err.submit(ERR_ELF_INDEX_RANGE); return;
                }
                int8_t * strtab = buf() + strtabOffset;
 
                // Find symbol table
                uint32_t symtabsize = (uint32_t)(sheader.sh_size);
                int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
                int8_t * symtabend = symtab + symtabsize;
                if (entrysize < sizeof(Elf64_Sym)) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = sizeof(Elf64_Sym); }
 
                printf("\n  Symbols:");
                // Loop through symbol table
                int symi;  // Symbol number
                for (symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
                    // Copy ElfFwcSym symbol or convert Elf64_Sym symbol
                    ElfFwcSym sym;
                    if (fileHeader.e_machine == EM_FORWARDCOM) {
                        sym = *(ElfFwcSym*)symtab;
                    }
                    else {
                        // Translate x64 type symbol table entry
                        Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
                        sym.st_name = sym64.st_name;
                        sym.st_type = sym64.st_type;
                        sym.st_bind = sym64.st_bind;
                        sym.st_other = sym64.st_other;
                        sym.st_section = sym64.st_section;
                        sym.st_value = sym64.st_value;
                        sym.st_unitsize = (uint32_t)sym64.st_size;
                        sym.st_unitnum = 1;
                        sym.st_reguse1 = sym.st_reguse2 = 0;
                    }
                    int type = sym.st_type;
                    int binding = sym.st_bind;
                    if (strtabOffset + sym.st_name >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
                    else if (*(strtab + sym.st_name)) {
                        printf("\n  %2i Name: %s,", symi, strtab + sym.st_name);
                    }
                    else {
                        printf("\n  %2i Unnamed,", symi);
                    }
                    if (sym.st_value || type == STT_OBJECT || type == STT_FUNC || (int16_t)sym.st_section == SHN_ABS_X86) {
                        printf(" Value: 0x%X", uint32_t(sym.st_value));
                    }
                    if (sym.st_unitsize)  printf(" size: %X*%X", sym.st_unitsize, sym.st_unitnum);
                    if (sym.st_other) {
                        for (int i = 0; i < 32; i++) {
                            if (sym.st_other & 1 << i) {
                                printf(" %s", Lookup(ELFSymbolInfoNames, 1 << i));
                            }
                        }
                    }
                    if (sym.st_reguse1 | sym.st_reguse2) {
                        printf(", register use 0x%X, 0x%X", sym.st_reguse1, sym.st_reguse2);
                    }
                    //if (int32_t(sym.st_section) > 0) printf(", section: %i", sym.st_section);
                    //else { // Special segment values
                    if (sym.st_section == 0) {
                        printf(" extern,");
                    }
                    else if (sym.st_type == STT_CONSTANT) {
                        printf(", absolute,");
                    }
                    else {
                        printf(", section: 0x%X", sym.st_section);
                    }
                    if (sym.st_type || sym.st_bind) {
                        printf(" type: %s, binding: %s",
                            Lookup(ELFSymbolTypeNames, type),
                            Lookup(ELFSymbolBindingNames, binding));
                    }
                }
            }
            // Dump relocation table
            if ((sheader.sh_type == SHT_RELA) && (options & DUMP_RELTAB)) {
                printf("\n  Relocations:");
                int8_t * reltab = buf() + uint32_t(sheader.sh_offset);
                int8_t * reltabend = reltab + uint32_t(sheader.sh_size);
                /*
                uint32_t expectedentrysize = sheader.sh_type == SHT_RELA ?
                    sizeof(Elf64_Rela) :                // Elf32_Rela, Elf64_Rela
                    sizeof(Elf64_Rela) - wordSize / 8;  // Elf32_Rel,  Elf64_Rel
                    */
                uint32_t expectedentrysize = sizeof(Elf64_Rela);
                if (entrysize < expectedentrysize) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = expectedentrysize; }
 
                // Loop through entries
                for (; reltab < reltabend; reltab += entrysize) {
                    // Copy relocation table entry with or without addend
                    ElfFwcReloc rel = *(ElfFwcReloc*)reltab;
                    const char * relocationName, *relocationSize;
                    char text[128];
                    if (machineType == EM_X86_64) {
                        relocationName = Lookup(ELF64RelocationNames, rel.r_type);
                    }
                    else if (machineType == EM_FORWARDCOM) {
                        relocationName = Lookup(ELFFwcRelocationTypes, rel.r_type & R_FORW_RELTYPEMASK);
                        relocationSize = Lookup(ELFFwcRelocationSizes, rel.r_type & R_FORW_RELSIZEMASK);
                        sprintf(text, "%s, %s, scale by %i", relocationName, relocationSize,
                            1 << (rel.r_type & 0xFF));
                        relocationName = text;
                    }
                    else {
                        relocationName = "unknown";
                    }
 
                    memcpy(&rel, reltab, entrysize);
                    printf("\n  Section: %i, Offset: 0x%X, Symbol: %i, Name: %s\n   Type: %s", rel.r_section,
                        uint32_t(rel.r_offset), rel.r_sym, symbolName(rel.r_sym), relocationName);
                    if (machineType == EM_FORWARDCOM && rel.r_type >> 16 == 8) {
                        printf(", ref. point %i", rel.r_refsym);
                    }
                    if (uint32_t(rel.r_addend)) {
                        printf(", Addend: 0x%X", uint32_t(rel.r_addend));
                    }
 
                    /* Inline addend not used by ForwardCom
                    // Find inline addend
                    ElfFwcShdr relsheader = sectionHeaders[rel.r_section];
                    uint32_t relsoffset = uint32_t(relsheader.sh_offset);
                    if (relsoffset + rel.r_offset < dataSize() && relsheader.sh_type != SHT_NOBITS) {
                        int32_t * piaddend = (int32_t*)(buf() + relsoffset + rel.r_offset);
                        if (*piaddend) printf(", Inline value: 0x%X", *piaddend);
                    }*/
                }
            }
        }
    }
}
 
 
// PublicNames
void CELF::listSymbols(CMemoryBuffer * strings, CDynamicArray<SSymbolEntry> * index, uint32_t m, uint32_t l, int scope) {
    // Make list of public and external symbols, including weak symbols
    // SStringEntry::member is set to m and library is set to l;
    // scope: 1: exported, 
    //        2: imported (includes STB_WEAK2),
    //        3: both
 
    // Interpret header:
    parseFile();
    if (err.number()) return;
 
    // Loop through section headers
    for (uint32_t sc = 0; sc < nSections; sc++) {
        // Get copy of 32-bit header or converted 64-bit header
        ElfFwcShdr sheader = sectionHeaders[sc];
        uint32_t entrysize = uint32_t(sheader.sh_entsize);
 
        if (sheader.sh_type == SHT_SYMTAB) {
            // Find associated string table
            if (sheader.sh_link >= (uint32_t)nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
            int8_t * strtab = buf() + uint32_t(sectionHeaders[sheader.sh_link].sh_offset);
 
            // Find symbol table
            uint32_t symtabsize = uint32_t(sheader.sh_size);
            int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
            int8_t * symtabend = symtab + symtabsize;
            if (entrysize < sizeof(Elf64_Sym)) { err.submit(ERR_ELF_RECORD_SIZE); entrysize = sizeof(Elf64_Sym); }
 
            // Loop through symbol table
            for (int symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
                // Copy ElfFwcSym symbol table entry or convert Elf64_Sym bit entry
                ElfFwcSym sym;
                if (fileHeader.e_machine == EM_FORWARDCOM) {
                    sym = *(ElfFwcSym*)symtab;
                }
                else {
                    // Translate x64 type symbol table entry
                    Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
                    sym.st_name = sym64.st_name;
                    sym.st_type = sym64.st_type;
                    sym.st_bind = sym64.st_bind;
                    sym.st_other = sym64.st_other;
                    sym.st_section = sym64.st_section;
                    sym.st_value = sym64.st_value;
                    sym.st_unitsize = (uint32_t)sym64.st_size;
                    sym.st_unitnum = 1;
                    sym.st_reguse1 = sym.st_reguse2 = 0;
                }
                int type = sym.st_type;
                int binding = sym.st_bind;
                if (type != STT_SECTION && type != STT_FILE && (binding & (STB_GLOBAL | STB_WEAK))) {
                    // Public or external symbol found
                    if (((scope & 1) && (sym.st_section != 0))      // scope 1: public
                    || ((scope & 2) && (sym.st_section == 0 || binding == STB_WEAK2))) {  // scope 2: external
                        SSymbolEntry se;
                        se.member = m;
                        se.library = l;
                        se.st_type = type;
                        se.st_bind = binding;
                        se.symindex = symi;
                        se.sectioni = sym.st_section;
                        se.st_other = (uint16_t)sym.st_other;
                        se.status = (scope & 1) << 1;
                        // Store name
                        const char * name = (char*)strtab + sym.st_name;
                        se.name = strings->pushString(name);
                        // Store name index
                        index->push(se);
                    }
                }
            }
        }
    }
}
 
// get a symbol record
ElfFwcSym * CELF::getSymbol(uint32_t symindex) {
    if (symbolTableOffset) {
        uint32_t symi = symbolTableOffset + symindex * symbolTableEntrySize;
        if (symi < dataSize()) {
            return &get<ElfFwcSym>(symi);
        }
    }
    return 0;
}
 
// SymbolName
const char * CELF::symbolName(uint32_t index) {
    // Get name of symbol. (ParseFile() must be called first)
    const char * symname = 0;  // Symbol name
    uint32_t symi;           // Symbol index
    uint32_t stri;           // String index
    if (symbolTableOffset) {
        symi = symbolTableOffset + index * symbolTableEntrySize;
        if (symi < dataSize()) {
            stri = get<Elf64_Sym>(symi).st_name;
            if (stri < symbolStringTableSize) {
                symname = (char*)buf() + symbolStringTableOffset + stri;
            }
        }
    }
    return symname;
}
 
// split ELF file into container classes
int CELF::split() {
    uint32_t sc;                                 // Section index
    uint32_t type;                               // Section type
    if (dataSize() == 0) return 0;
    parseFile();                                 // Parse file, get section headers, check integrity
    CDynamicArray<ElfFwcShdr> newSectionHeaders; // Remake list of section headers
    newSectionHeaders.setSize(nSections*(uint32_t)sizeof(ElfFwcShdr)); // Reserve space but leave getNumEntries() zero
    CDynamicArray<uint32_t> sectionIndexTrans;   // Translate old section indices to new indices
    sectionIndexTrans.setNum(nSections + 2);
 
    // Make program headers list
    uint32_t nProgramHeaders = fileHeader.e_phnum;
    uint32_t programHeaderSize = fileHeader.e_phentsize;
    if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
    ElfFwcPhdr pHeader;
    for (uint32_t i = 0; i < nProgramHeaders; i++) {
        pHeader = get<ElfFwcPhdr>(programHeaderOffset + i * programHeaderSize);
        if (pHeader.p_filesz > 0 && (uint32_t)pHeader.p_offset < dataSize()) {
            uint32_t phOffset = dataBuffer.push(buf() + (uint32_t)pHeader.p_offset, (uint32_t)pHeader.p_filesz);
            pHeader.p_offset = phOffset;         // New offset refers to dataBuffer
        }
        programHeaders.push(pHeader);            // Save in programHeaders list
    }
 
    // Make section list
    // Make dummy empty section
    ElfFwcShdr sheader2;
    zeroAllMembers(sheader2);
    newSectionHeaders.push(sheader2);
 
    for (sc = 0; sc < nSections; sc++) {
        // Copy section header
        sheader2 = sectionHeaders[sc];                     // sectionHeaders[] was filled by ParseFile()
        type = sheader2.sh_type;                           // Section type
        if (type == SHT_NULL /* && sc == 0 */) continue;   // skip first/all empty section headers
        // Skip symbol, relocation, and string tables. They are converted to containers:
        if (type == SHT_SYMTAB || type == SHT_STRTAB || type == SHT_RELA) continue;
 
        // Get section name
        uint32_t namei = sheader2.sh_name;
        if (namei >= secStringTableLen) { err.submit(ERR_ELF_STRING_TABLE); return ERR_ELF_STRING_TABLE; }
        const char * Name = secStringTableLen ? secStringTable + namei : "???";
        // Copy name to sectionNameBuffer 
        uint32_t nameo = stringBuffer.pushString(Name);
        sheader2.sh_name = nameo;                           // New name index refers to sectionNameBuffer
 
        // Get section data
        int8_t  * sectionData = buf() + sheader2.sh_offset;
        uint32_t  InitSize = (sheader2.sh_type == SHT_NOBITS) ? 0 : (uint32_t)sheader2.sh_size;
 
        if (InitSize) {
            // Copy data to dataBuffer
            uint32_t newOffset = dataBuffer.push(sectionData, InitSize);
            sheader2.sh_offset = newOffset;       // New offset refers to dataBuffer
        }
        else {
            sheader2.sh_offset = dataBuffer.dataSize();
        }
 
        // Save modified header and new index
        sectionIndexTrans[sc] = newSectionHeaders.numEntries();
        newSectionHeaders.push(sheader2);
    }
 
    // Make symbol list
 
    // Allocate array for translating symbol indices for multiple symbol tables
    // in source file to a single symbol table in the symbols container
    CDynamicArray<uint32_t> SymbolTableOffset;   // Offset of new symbol table indices relative to old indices
    SymbolTableOffset.setNum(nSections + 1);
    uint32_t NumSymbols = 0;
 
    for (sc = 0; sc < nSections; sc++) {
        ElfFwcShdr & sheader = sectionHeaders[sc];
        uint32_t entrysize = (uint32_t)(sheader.sh_entsize);
 
        if (sheader.sh_type == SHT_SYMTAB) {
            // This is a symbol table
 
            // Offset for symbols in this symbol table = number of preceding symbols from other symbol tables
            // Symbol number in joined table = symi1 + number of symbols in preceding tables
            SymbolTableOffset[sc] = NumSymbols;
 
            // Find associated string table
            if (sheader.sh_link >= nSections) { err.submit(ERR_ELF_INDEX_RANGE); sheader.sh_link = 0; }
            uint32_t strtabOffset = (uint32_t)sectionHeaders[sheader.sh_link].sh_offset;
            if (sectionHeaders[sheader.sh_link].sh_offset >= dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
 
            // Find symbol table
            uint32_t symtabsize = (uint32_t)(sheader.sh_size);
            int8_t * symtab = buf() + uint32_t(sheader.sh_offset);
            int8_t * symtabend = symtab + symtabsize;
            if (entrysize < (uint32_t)sizeof(Elf64_Sym)) { 
                err.submit(ERR_ELF_RECORD_SIZE); entrysize = (uint32_t)sizeof(ElfFwcSym); 
            }
 
            // Loop through symbol table
            uint32_t symi1;                           // Symbol number in this table
            ElfFwcSym sym;                           // copy of symbol table entry
            for (symi1 = 0; symtab < symtabend; symtab += entrysize, symi1++) {
 
                // Copy or convert symbol table entry
                if (fileHeader.e_machine == EM_FORWARDCOM) {
                    sym = *(ElfFwcSym*)symtab;
                }
                else {
                    // Translate x64 type symbol table entry
                    Elf64_Sym sym64 = *(Elf64_Sym*)symtab;
                    sym.st_name = sym64.st_name;
                    sym.st_type = sym64.st_type;
                    sym.st_bind = sym64.st_bind;
                    sym.st_other = sym64.st_other;
                    sym.st_section = sym64.st_section;
                    sym.st_value = sym64.st_value;
                    sym.st_unitsize = (uint32_t)sym64.st_size;
                    sym.st_unitnum = 1;
                    sym.st_reguse1 = sym.st_reguse2 = 0;
                }
                // if (sym.st_type == STT_NOTYPE && symi1 == 0) continue; // Include empty symbols to avoid changing indexes
 
                // Translate section index in symbol record
                if (sym.st_section < sectionIndexTrans.numEntries()) {
                    sym.st_section = sectionIndexTrans[sym.st_section];
                }
 
                // Get name
                if (sym.st_name) {
                    if ((uint64_t)strtabOffset + sym.st_name > dataSize()) err.submit(ERR_ELF_INDEX_RANGE);
                    else {
                        const char * symName = (char*)buf() + strtabOffset + sym.st_name;
                        sym.st_name = stringBuffer.pushString(symName);
                    }
                }
 
                // Put name in symbolNameBuffer and update string index
                symbols.push(sym);
 
                // Count symbols
                NumSymbols++;
            }
        }
    }
 
    // Make relocation list
    union {
        Elf64_Rela   a;
        ElfFwcReloc r2;
    } rel;
 
    // Loop through sections
    for (sc = 0; sc < nSections; sc++) {
        // Get section header
        ElfFwcShdr & sheader = sectionHeaders[sc];
 
        if (sheader.sh_type == SHT_RELA) {
            // Relocations section
            int8_t * reltab = buf() + uint32_t(sheader.sh_offset);
            int8_t * reltabend = reltab + uint32_t(sheader.sh_size);
            int entrysize = (uint32_t)(sheader.sh_entsize);
            //int expectedentrysize = sheader.sh_type == SHT_RELA ? sizeof(Elf64_Rela) : 16;  // Elf64_Rela : Elf64_Rel
            int expectedentrysize = sizeof(Elf64_Rela);
            if (entrysize < expectedentrysize) {
                err.submit(ERR_ELF_RECORD_SIZE); entrysize = expectedentrysize;
            }
 
            int32_t symbolSection = (int32_t)sheader.sh_link; // Symbol section, old index
            if (symbolSection <= 0 || (uint32_t)symbolSection >= nSections) {
                err.submit(ERR_ELF_SYMTAB_MISSING); return ERR_ELF_SYMTAB_MISSING;
            }
            // Symbol offset is zero if there is only one symbol section, which is the normal case
            uint32_t symbolOffset = SymbolTableOffset[symbolSection];
 
            // Loop through entries
            for (; reltab < reltabend; reltab += entrysize) {
                // Copy or translate relocation table entry 
                if (fileHeader.e_machine == EM_X86_64) {
                    // Translate relocation type
                    rel.a = *(Elf64_Rela*)reltab;
                    //if (sheader.sh_type == SHT_REL) rel.a.r_addend = 0;
                    switch (rel.a.r_type) {
                    case R_X86_64_64:    // Direct 64 bit 
                        rel.a.r_type = R_FORW_ABS | R_FORW_64;
                        break;
                    case R_X86_64_PC32:  // Self relative 32 bit signed (not RIP relative in the sense used in COFF files)
                        rel.a.r_type = R_FORW_SELFREL | R_FORW_32;
                        break;
                    case R_X86_64_32:    // Direct 32 bit zero extended
                    case R_X86_64_32S:   // Direct 32 bit sign extended
                        rel.a.r_type = R_FORW_ABS | R_FORW_32;
                        break;
                    }
                    rel.r2.r_refsym = 0;
                    rel.r2.r_section = sheader.sh_module; // sh_module = sh_info in x86
                }
                else {
                    rel.r2 = *(ElfFwcReloc*)reltab;
                }
 
                // Target symbol
                rel.r2.r_sym += symbolOffset;
                if (rel.r2.r_refsym) rel.r2.r_refsym += symbolOffset;
 
                // Save relocation
                relocations.push(rel.r2);
            }
        }
    }
    // Replace old section header list by new one
    sectionHeaders << newSectionHeaders;
    nSections = sectionHeaders.numEntries();
    return 0;
}
 
// Join containers into ELF file
int CELF::join(ElfFwcEhdr * header) {
    uint32_t sc;                                 // Section index
    uint64_t os;                                 // Offset of data in file
    uint32_t size;                               // Size of section data
    uint32_t shtype;                             // Section header type
    uint32_t ph;                                 // Program header index
    const char * name;                           // Name of a symbol
    uint32_t progheadi = 0;                      // program header index
    uint32_t pHfistSection = 0;                  // first section covered by current program header
    uint32_t pHnumSections = 0;                  // number of sections covered by current program header
    bool hasProgHead = false;                    // current section is covered by a program header
 
    CDynamicArray<ElfFwcShdr> newSectionHeaders;// Modify list of section headers
    CDynamicArray<uint32_t> sectionIndexTrans;   // Translate old section indices to new indices
    CMemoryBuffer newStrtab;                     // Temporary symbol string table
    CMemoryBuffer newShStrtab;                   // Temporary section string table
    nSections = sectionHeaders.numEntries();     // Number of sections
    if (nSections == 0) return 0;
    newSectionHeaders.setSize(nSections*sizeof(ElfFwcShdr)); // Allocate space for section headers, but don't set number
    sectionIndexTrans.setNum(nSections + 1);     // Indices are initialized to zero
 
    // Clear any previous file
    setSize(0);
 
    // Make file header
    ElfFwcEhdr fileheader;
    if (header) fileheader = *header;
    else zeroAllMembers(fileheader);
    uint8_t * eident = fileheader.e_ident;
    *(uint32_t*)eident = ELFMAG; // Put file type magic number in
    fileheader.e_ident[EI_CLASS] = ELFCLASS64; // file class        
    fileheader.e_ident[EI_DATA] = ELFDATA2LSB; //  2's complement, little endian
    fileheader.e_ident[EI_VERSION] = EV_CURRENT; //  current ELF version
    fileheader.e_ident[EI_OSABI] = ELFOSABI_FORWARDCOM; // ForwardCom ABI
    fileheader.e_ident[EI_ABIVERSION] = EI_ABIVERSION_FORWARDCOM; // ForwardCom ABI version
    if (fileheader.e_type == 0) fileheader.e_type = ET_REL; // File type: object or executable
    fileheader.e_machine = EM_FORWARDCOM; // Machine type: ForwardCom 
    fileheader.e_ehsize = sizeof(fileheader);
    push(&fileheader, sizeof(fileheader));       // Insert file header into new file
 
    // Prepare string tables to be put in last
    ElfFwcShdr strtabHeader;
    zeroAllMembers(strtabHeader);
    strtabHeader.sh_type = SHT_STRTAB;
    strtabHeader.sh_align = 0;
    strtabHeader.sh_entsize = 1;
    ElfFwcShdr shstrtabHeader = strtabHeader;
    newStrtab.pushString("");                   // Dummy empty string at start to avoid zero offset
    newShStrtab.pushString("");
 
    if (fileheader.e_type == ET_EXEC) {
        // Executable file. Insert program headers
        uint32_t ph;  // Program header index
        fileheader.e_phoff = dataSize();
        fileheader.e_phentsize = (uint16_t)sizeof(ElfFwcPhdr);
        fileheader.e_phnum = programHeaders.numEntries();
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
            push(&programHeaders[ph], sizeof(ElfFwcPhdr));
        }
        // Insert program header data only if they are not the same as section data
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
            if ((programHeaders[ph].p_type == PT_INTERP || programHeaders[ph].p_type == PT_NOTE) && programHeaders[ph].p_filesz) {
                os = push(dataBuffer.buf() + programHeaders[ph].p_offset, (uint32_t)programHeaders[ph].p_filesz);
                get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph * sizeof(ElfFwcPhdr))).p_offset = os;
            }
        }
        // translate dataBuffer offset to file offset
        os = dataSize();
        os = (os + (1<<FILE_DATA_ALIGN)-1) & -(1<<FILE_DATA_ALIGN);         // align
        for (ph = 0; ph < programHeaders.numEntries(); ph++) {
            if (programHeaders[ph].p_filesz) {
                //programHeaders[ph].p_offset += dataSize();
                get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph * sizeof(ElfFwcPhdr))).p_offset = os;
                os += (uint32_t)programHeaders[ph].p_filesz;
            }
        }
        // sections covered by first program header
        progheadi = 0;
        pHfistSection = pHnumSections = 0;
        if (programHeaders.numEntries()) {
            pHfistSection = (uint32_t)programHeaders[progheadi].p_paddr;
            pHnumSections = (uint32_t)(programHeaders[progheadi].p_paddr >> 32);
        }
    }
 
    // Put section data into file
    for (sc = 0; sc < sectionHeaders.numEntries(); sc++) {
        ElfFwcShdr sectionHeader = sectionHeaders[sc];  // Copy section header
        shtype = sectionHeader.sh_type;  // Section type
        // Skip sections with no data        
        // Skip relocation sections, they are reconstructed later.
        // Skip string tables, they are reconstructed later.
        if (shtype == SHT_NULL || shtype == SHT_RELA || shtype == SHT_STRTAB) {
            continue;
        }
        else if (shtype != SHT_NOBITS && sectionHeader.sh_size != 0) {
            // Section contains data
            if (fileheader.e_type == ET_EXEC) {
                // find correcponding program header, if any
                while (sc >= pHfistSection + pHnumSections && progheadi+1 < programHeaders.numEntries()) {
                    progheadi++;
                    pHfistSection = (uint32_t)programHeaders[progheadi].p_paddr;
                    pHnumSections = (uint32_t)(programHeaders[progheadi].p_paddr >> 32);
                }
                // is this section covered by a program header?
                hasProgHead = sc >= pHfistSection && sc < pHfistSection + pHnumSections;
            }
            if (hasProgHead) {
                // check if there is filler space between this section and any previous 
                // section under the same program header
                uint64_t lastSecEnd = 0;
                if (sc > pHfistSection && sectionHeaders[sc-1].sh_type != SHT_NOBITS) {
                    // end of previous section in dataBuffer:
                    lastSecEnd = sectionHeaders[sc-1].sh_offset + sectionHeaders[sc-1].sh_size;
                    if (sectionHeader.sh_offset > lastSecEnd) {
                        // number of bytes to insert as filler
                        uint64_t fill = sectionHeader.sh_offset - lastSecEnd;
                        if (fill > MAX_ALIGN) err.submit(ERR_LINK_OVERFLOW, "","",""); // should not occur
                        uint64_t fillValue = 0;
                        if (sectionHeader.sh_flags & SHF_EXEC) {   // use filler instruction
                            fillValue = fillerInstruction | ((uint64_t)fillerInstruction << 32);
                        }
                        while (fill >= 8) {                           // loop to insert fillers
                            push(&fillValue, 8);
                            fill -= 8;
                        }
                        if (fill) push(&fillValue, (uint32_t)fill);
                    }
                }
            }
            // error check
            os = sectionHeader.sh_offset;
            size = (uint32_t)sectionHeader.sh_size;
            if (os + size > dataBuffer.dataSize()) {
                err.submit(ERR_ELF_INDEX_RANGE); return ERR_ELF_INDEX_RANGE;
            }
            // Put raw data into file and save the new offset
            align(1<<FILE_DATA_ALIGN);                               // align file data
            os = push(dataBuffer.buf() + os, size);
            sectionHeader.sh_offset = os;
        }
        else {
            sectionHeader.sh_offset = dataSize();
        }
        // Get section name
        if (sectionHeader.sh_name >= stringBuffer.dataSize()) {
            err.submit(ERR_ELF_INDEX_RANGE); sectionHeader.sh_name = 0;
        }
        else {
            const char * name = (char*)stringBuffer.buf() + sectionHeader.sh_name;
            if (*name) {
                sectionHeader.sh_name = newShStrtab.pushString(name);
            }
        }
        // Save modified header and index
        //sectionIndexTrans[sc] = newSectionHeaders.numEntries() + 1;
        sectionIndexTrans[sc] = newSectionHeaders.numEntries();
        newSectionHeaders.push(sectionHeader);
    }
    // Number of sections with program code and data:
    uint32_t numDataSections = newSectionHeaders.numEntries();
 
    // put module names and library names into shstrtab for relinkable sections
    updateModuleNames(newSectionHeaders, newShStrtab);
 
    // Update program segments that cover the same data as sections
    for (ph = 0; ph < programHeaders.numEntries(); ph++) {
        // reference to program header in binary file
        ElfFwcPhdr & pHeader = get<ElfFwcPhdr>(uint32_t(fileheader.e_phoff + ph*sizeof(ElfFwcPhdr)));
        // sections covered by this program header
        uint32_t fistSection = (uint32_t)programHeaders[ph].p_paddr;
        uint32_t numSections = (uint32_t)(programHeaders[ph].p_paddr >> 32);
        uint32_t lastSection = fistSection + numSections - 1;
        // update file offset
        if (fistSection < sectionIndexTrans.numEntries()) {
            uint32_t sc1 = sectionIndexTrans[fistSection];
            if (sc1 < newSectionHeaders.numEntries()) {
                os = newSectionHeaders[sc1].sh_offset;
                pHeader.p_offset = os;
            }
            if (lastSection < sectionIndexTrans.numEntries()) {
                uint32_t sc2 = sectionIndexTrans[lastSection];
                if (sc2 < newSectionHeaders.numEntries()) {
                    // update segment size (it may have been increased by alignment fillers)
                    os = newSectionHeaders[sc2].sh_offset;
                    if (newSectionHeaders[sc2].sh_type != SHT_NOBITS) {
                        os += newSectionHeaders[sc2].sh_size;
                    }
                    pHeader.p_filesz = os - pHeader.p_offset;
 
                    //!! set p_memsz
                }
            }
        }
    }
    uint32_t numRelocationSections = 1;  // ForwardCom needs only one relocation section
 
    // Now we know how many headers the new file will contain. Assign indexes:
    // one empty header at start
    // numDataSections: code and data
    // one section: symbols
    // numRelocationSections sections with relocations
    // one symbol names strtab
    // one section names shstrtab
    uint32_t symbolSection = numDataSections + 1;
    uint32_t firstRelSection = symbolSection + 1;
    uint32_t shstrtabSection = firstRelSection + numRelocationSections;
    uint32_t strtabSection = shstrtabSection + 1;
    uint32_t numSections = strtabSection + 1;
 
    // Insert symbol table and make temporary string table
    align(1 << FILE_DATA_ALIGN);
    ElfFwcShdr symtabHeader;
    zeroAllMembers(symtabHeader);
    symtabHeader.sh_type = SHT_SYMTAB;
    symtabHeader.sh_link = strtabSection;
    symtabHeader.sh_entsize = sizeof(ElfFwcSym);
    symtabHeader.sh_align = 3;
    symtabHeader.sh_offset = dataSize();
 
    // Loop through symbol table
    for (uint32_t sym = 0; sym < symbols.numEntries(); sym++) {
        ElfFwcSym ss = symbols[sym];
        uint32_t nameOffset = ss.st_name;
        ss.st_name = 0;
        if (nameOffset >= stringBuffer.dataSize()) {
            err.submit(ERR_INDEX_OUT_OF_RANGE);
        }
        else {
            name = (char*)stringBuffer.buf() + nameOffset;
            if (*name) { // Put name string into file and save new offset                
                ss.st_name = newStrtab.pushString(name);
            }
        }
        push(&ss, sizeof(ElfFwcSym));
    }
    // Calculate size of symtab
    symtabHeader.sh_size = dataSize() - symtabHeader.sh_offset;
    symtabHeader.sh_name = newShStrtab.pushString("symtab"); // Assign name
 
   // Insert relocation table   
    ElfFwcShdr relocationHeader;
    zeroAllMembers(relocationHeader);
    relocationHeader.sh_type = SHT_RELA;
    relocationHeader.sh_flags = SHF_INFO_LINK;
    relocationHeader.sh_entsize = sizeof(ElfFwcReloc);
    relocationHeader.sh_module = 0;
    relocationHeader.sh_link = symbolSection; // Symbol table index
    relocationHeader.sh_name = newShStrtab.pushString("relocations"); // Save name
    relocationHeader.sh_offset = dataSize();              // Save offset
    // insert all relocations
    push(relocations.buf(), relocations.dataSize());
    // Calculate size of this relocation section
    relocationHeader.sh_size = dataSize() - relocationHeader.sh_offset;
 
    // Make string tables
    shstrtabHeader.sh_name = newShStrtab.pushString("shstrtab");
    strtabHeader.sh_name = newShStrtab.pushString("strtab");
    shstrtabHeader.sh_offset = dataSize();
    push(newShStrtab.buf(), newShStrtab.dataSize());
    shstrtabHeader.sh_size = dataSize() - shstrtabHeader.sh_offset;
    strtabHeader.sh_offset = dataSize();
    push(newStrtab.buf(), newStrtab.dataSize());
    strtabHeader.sh_size = dataSize() - strtabHeader.sh_offset;
 
    // Insert section headers
    align(1 << FILE_DATA_ALIGN);
    fileheader.e_shoff = dataSize();
    fileheader.e_shentsize = sizeof(ElfFwcShdr);
    fileheader.e_shstrndx = shstrtabSection;
    ElfFwcShdr nullhdr;            // First section header must be empty
    zeroAllMembers(nullhdr);
    push(&nullhdr, sizeof(ElfFwcShdr));
    push(newSectionHeaders.buf(), newSectionHeaders.numEntries() * sizeof(ElfFwcShdr));
    push(&symtabHeader, sizeof(ElfFwcShdr));
    push(&relocationHeader, sizeof(ElfFwcShdr));
    push(&shstrtabHeader, sizeof(ElfFwcShdr));
    push(&strtabHeader, sizeof(ElfFwcShdr));
 
    // Update file header
    fileheader.e_shnum = numSections;
    get<ElfFwcEhdr>(0) = fileheader;
    return 0;
}
 
// Add section header and section data
uint32_t CELF::addSection(ElfFwcShdr & section, CMemoryBuffer const & strings, CMemoryBuffer const & data) {
    ElfFwcShdr section2 = section;             // copy section header
    int nul = 0;
    section2.sh_name = stringBuffer.pushString((const char*)strings.buf() + section.sh_name); // copy string
    if (dataBuffer.dataSize() == 0) dataBuffer.push(&nul, 4);     // add a zero to avoid offset beginning at zero
    dataBuffer.align(1 << FILE_DATA_ALIGN);                       // align in source file
    if (section.sh_type != SHT_NOBITS) {        
        section2.sh_offset = dataBuffer.push(data.buf() + section.sh_offset, (uint32_t)section.sh_size); // copy data
    }
    else {
        section2.sh_offset = dataBuffer.dataSize() + section.sh_offset; // BSS section
    }
    if (sectionHeaders.dataSize() == 0) {    // make empty section 0
        ElfFwcShdr section0;
        zeroAllMembers(section0);
        sectionHeaders.push(section0);
    }
    sectionHeaders.push(section2);         // save section header
    nSections = sectionHeaders.numEntries();
    return nSections - 1;  // return section number
}
 
// Extend previously added section
void CELF::extendSection(ElfFwcShdr & section, CMemoryBuffer const & data) {
    if (sectionHeaders.numEntries() == 0) {
        err.submit(ERR_LINK_OVERFLOW, "","","");
        return;
    }
    uint32_t pre = sectionHeaders.numEntries() - 1;  // previously added section
    dataBuffer.align(1 << FILE_DATA_ALIGN);          // align in source file
 
    // insert new data
    if (section.sh_type != SHT_NOBITS) {            
        dataBuffer.push(data.buf() + section.sh_offset, (uint32_t)section.sh_size); 
        sectionHeaders[pre].sh_size = dataBuffer.dataSize() - sectionHeaders[pre].sh_offset;
    }
    else {
        // adjust header
        sectionHeaders[pre].sh_size += section.sh_size;
    }
}
 
// Insert alignment fillers between sections
void CELF::insertFiller(uint64_t numBytes) {
    if (sectionHeaders.numEntries() == 0) {
        err.submit(ERR_LINK_OVERFLOW, "","","");
        return;
    }
    uint32_t pre = sectionHeaders.numEntries() - 1;        // previously added section
    uint64_t fillValue = 0;
    if (sectionHeaders[pre].sh_flags & SHF_EXEC) {         // use filler instruction
        fillValue = fillerInstruction | ((uint64_t)fillerInstruction << 32);
    }
    uint64_t f = numBytes;                                 // loop counter
    while (f >= 8) {                                       // loop to insert fillers
        dataBuffer.push(&fillValue, 8);  
        f -= 8;
    }
    if (f) dataBuffer.push(&fillValue, (uint32_t)f);
}
 
 
// Add module name and library name to relinkable sections
void CELF::addModuleNames(CDynamicArray<uint32_t> &moduleNames1, CDynamicArray<uint32_t> &libraryNames1) {
    // moduleNames and libraryNames contain indexes into cmd.fileNameBuffer
    moduleNames << moduleNames1;
    libraryNames << libraryNames1;
}
 
// Put module names and library names into section string table for relinkable sections
void CELF::updateModuleNames(CDynamicArray<ElfFwcShdr> &newSectionHeaders, CMemoryBuffer &newShStrtab) {
    uint32_t sec;                                // section number
    uint32_t mod;                                // module number
    uint32_t lib;                                // library number
    const char * name;                           // module or library name
 
    CDynamicArray<uint32_t> moduleNames2;        // module names as index into stringBuffer
    CDynamicArray<uint32_t> libraryNames2;       // library names as index into stringBuffer
    moduleNames2.setNum(moduleNames.numEntries());
    libraryNames2.setNum(libraryNames.numEntries());
 
    // avoid storing same name multiple times by first checking which names are needed
    for (sec = 1; sec < newSectionHeaders.numEntries(); sec++) {
        if ((newSectionHeaders[sec].sh_flags & SHF_RELINK) | cmd.debugOptions) {
            mod = newSectionHeaders[sec].sh_module;
            if (mod < moduleNames.numEntries() && moduleNames[mod]) moduleNames2[mod] = 1;
            lib = newSectionHeaders[sec].sh_library;
            if (lib && lib < libraryNames.numEntries()) libraryNames2[lib] = 1;
        }
    }
    // store needed names in shstrtab
    for (mod = 0; mod < moduleNames.numEntries(); mod++) {
        if (moduleNames2[mod]) {
            name = cmd.getFilename(moduleNames[mod]);
            moduleNames2[mod] = newShStrtab.pushString(name);
        }
    }
    for (lib = 0; lib < libraryNames.numEntries(); lib++) {
        if (libraryNames2[lib]) {
            name = cmd.getFilename(libraryNames[lib]);
            libraryNames2[lib] = newShStrtab.pushString(name);
        }
    }
    // insert updated name indexes
    for (sec = 1; sec < newSectionHeaders.numEntries(); sec++) {
        if ((newSectionHeaders[sec].sh_flags & SHF_RELINK) | cmd.debugOptions) {
            mod = newSectionHeaders[sec].sh_module;
            if (mod < moduleNames2.numEntries() && moduleNames2[mod]) {
                newSectionHeaders[sec].sh_module = moduleNames2[mod];
            }
            lib = newSectionHeaders[sec].sh_library;
            if (lib && lib < libraryNames2.numEntries()) {
                newSectionHeaders[sec].sh_library = libraryNames2[lib];
            }
        }
        else {
            newSectionHeaders[sec].sh_module = 0;
            newSectionHeaders[sec].sh_library = 0;
        }
    }
}
 
 
// Add program header
void CELF::addProgHeader(ElfFwcPhdr & header) {
    programHeaders.push(header);
}
 
 
// Add a symbol
uint32_t CELF::addSymbol(ElfFwcSym & symbol, CMemoryBuffer const & strings) {
    ElfFwcSym symbol2 = symbol;   // copy symbol
    if (symbol2.st_unitnum == 0) symbol2.st_unitnum = 1;
    if (stringBuffer.numEntries() == 0) stringBuffer.pushString(""); // put empty string at position zero to avoid zero index
    symbol2.st_name = stringBuffer.pushString((const char*)strings.buf() + symbol.st_name);  // copy name
    symbols.push(symbol2);          // save symbol record
    return symbols.numEntries() - 1;  // return new symbol index
}
 
// Add a relocation
void CELF::addRelocation(ElfFwcReloc & relocation) {
    relocations.push(relocation);
}
 
 
// structure used by removePrivateSymbols()
struct SSymbolCleanup {
    uint32_t preserve;                 // symbol must be preserved in output file
    uint32_t newIndex;                 // new index of symbol after local symbols have been removed
};
 
// remove local symbols and adjust relocation records with new symbol indexes
void CELF::removePrivateSymbols(int debugOptions) {
    CDynamicArray<SSymbolCleanup> symbolTranslate;         // list for translating symbol indexes
    symbolTranslate.setNum(symbols.numEntries());
    uint32_t symi;                                         // symbol index
    uint32_t reli;                                         // relocation index
                                                           // loop through symbols
    for (symi = 1; symi < symbols.numEntries(); symi++) {
        if (symbols[symi].st_bind != STB_LOCAL             // skip local symbols
        && symbols[symi].st_section                        // skip external symbols
        && !(symbols[symi].st_other & STV_HIDDEN)) {       // skip hidden symbols
            symbolTranslate[symi].preserve = 1;            // mark public symbols
        }
        if (debugOptions > 0 && symbols[symi].st_section) {// preserve local symbol names if debugOptions
            // (external unreferenced symbols are still discarded to avoid linking unused library functions)
            symbolTranslate[symi].preserve = 1;            
        }
    }
    // loop through relocations. preserve any symbols that relocations refer to
    for (reli = 0; reli < relocations.numEntries(); reli++) {
        symi = relocations[reli].r_sym;
        if (symi) {
            symbolTranslate[symi].preserve = 1;
        }
        symi = relocations[reli].r_refsym;
        if (symi) {
            symbolTranslate[symi].preserve = 1;
        }
    }
 
    // make new symbol list
    CDynamicArray<ElfFwcSym> symbols2;
    symbols2.setNum(1);                        // make first symbol empty
    for (symi = 1; symi < symbols.numEntries(); symi++) {
        if (symbolTranslate[symi].preserve) {
            symbolTranslate[symi].newIndex = symbols2.push(symbols[symi]);
        }
    }
 
    // update relocations with new symbol indexes
    for (reli = 0; reli < relocations.numEntries(); reli++) {
        if (relocations[reli].r_sym) {
            relocations[reli].r_sym = symbolTranslate[relocations[reli].r_sym].newIndex;
        }
        if (relocations[reli].r_refsym) {
            relocations[reli].r_refsym = symbolTranslate[relocations[reli].r_refsym].newIndex;
        }
    }
    // replace symbol table
    symbols << symbols2;
}
 
// make hexadecimal code file
CFileBuffer & CELF::makeHexBuffer() {
    CFileBuffer hexbuf;                          // temporary output buffer
    CMemoryBuffer databuffer;                    // temporary buffer with binary data
    char string[64];                             // temporary text string
    // Write date and time. 
    time_t time1 = time(0);
    char * timestring = ctime(&time1);
    if (timestring) {
        for (char *c = timestring; *c; c++) {    // Remove terminating '\n' in timestring
            if (*c < ' ') *c = 0;
        }
    } 
    sprintf(string, "// Hexfile %s, date %s\n", cmd.getFilename(cmd.inputFile), timestring);    hexbuf.push(string, (uint32_t)strlen(string));
    uint32_t wordsPerLine = cmd.maxLines;        // number of 32-bit words per line in hex file
    int32_t bytesPerLine = wordsPerLine * 4;     // number of bytes per line in hex file
 
    // Find program headers
    ElfFwcEhdr fileHeader = get<ElfFwcEhdr>(0);
    uint32_t nProgramHeaders = fileHeader.e_phnum;
    uint32_t programHeaderSize = fileHeader.e_phentsize;
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
    ElfFwcPhdr pHeader;
    for (uint32_t ph = 0; ph < nProgramHeaders; ph++) {         // loop through program headers
        pHeader = get<ElfFwcPhdr>(programHeaderOffset + ph * programHeaderSize); // program header
        uint32_t sectionSize = uint32_t(pHeader.p_filesz);      // size in file
        uint32_t sectionMemSize = uint32_t(pHeader.p_memsz);    // size in memory
        // write comment
        sprintf(string, "// Section %i, size %i\n// %i words per line\n", ph, sectionMemSize, wordsPerLine);
        hexbuf.push(string, (uint32_t)strlen(string));
 
        // get data from section
        uint32_t os = uint32_t(pHeader.p_offset);                // file offset
        // round up size to multiple of bytesPerLine
        sectionMemSize = (sectionMemSize + bytesPerLine - 1) & -bytesPerLine;
        // copy section data to databuffer
        databuffer.clear();
        databuffer.push(buf() + os, sectionMemSize);
        databuffer.setDataSize(sectionMemSize);
        // line loop
        for (uint32_t L = 0; L < sectionSize; L += bytesPerLine) {
            // word loop backwords for big endian order
            for (int32_t W = wordsPerLine-1; W >= 0; W--) {
                uint32_t data = databuffer.get<uint32_t>(L + W * 4);
                sprintf(string, "%08X", data);
                hexbuf.push(string, (uint32_t)strlen(string));
            }
            hexbuf.push("\n", 1); // end of line
        }
    }
    hexbuf >> *this;  // replace parent buffer (ELF file is lost)
    return *this;
}
 
// Write a link map
void CELF::makeLinkMap(FILE * stream) {
    // Find program headers
    //fprintf(stream, "\n\nLink map:");
    uint32_t nProgramHeaders = fileHeader.e_phnum;
    uint32_t programHeaderSize = fileHeader.e_phentsize;
    if (nProgramHeaders && programHeaderSize <= 0) err.submit(ERR_ELF_RECORD_SIZE);
    uint32_t programHeaderOffset = (uint32_t)fileHeader.e_phoff;
    ElfFwcPhdr pHeader;           // program header
    ElfFwcShdr sheader;           // section header
    const char * basename = "";   // name of base pointer
    const char * secname = "";    // name of section
    const char * modname = "";    // name of module
    uint64_t codesize = 0;        // size of code and const data
    uint64_t datasize = 0;        // max distance of data from datap
 
    // print table header
    fprintf(stream, "\n%-9s %-20s %-20s %-10s %-10s %-8s %s", "base", "section", "module", "start", "size", "align", "attributes");
 
    for (uint32_t i = 0; i < nProgramHeaders; i++) {
        pHeader = get<ElfFwcPhdr>(programHeaderOffset);
        if (pHeader.p_type & PT_LOAD) {
            // get base pointer
            switch (pHeader.p_flags & SHF_BASEPOINTER) {
            case SHF_IP: basename = "ip"; break;
            case SHF_DATAP: basename = "datap"; break;
            case SHF_THREADP: basename = "threadp"; break;
            default: basename = "?"; break;
            }
            // get name of first section
            secname = "";
            uint32_t sc = (uint32_t)pHeader.p_paddr;
            if (sc < nSections) {
                sheader = sectionHeaders[sc];
                if (sheader.sh_flags == pHeader.p_flags && sheader.sh_name < secStringTableLen) {
                    secname = secStringTable + sheader.sh_name;
                }
            }
            // loop through sections under this program header
            for (; sc < nSections; sc++) {
                sheader = sectionHeaders[sc];
                if (sheader.sh_flags != pHeader.p_flags) break; // stop when section does not belong to this program header
 
                // section name
                if (sheader.sh_name < secStringTableLen) secname = secStringTable + sheader.sh_name;
                else secname = "";
 
                // module name
                if (sheader.sh_module < secStringTableLen) modname = secStringTable + sheader.sh_module;
                else modname = ""; 
                // write line for section header
                fprintf(stream, "\n%-9s %-20s %-20s 0x%-8X 0x%-8X 0x%-6X ", basename, secname, modname, (uint32_t)sheader.sh_addr, (uint32_t)sheader.sh_size, 1 << sheader.sh_align);
                if (pHeader.p_flags & SHF_READ)  fprintf(stream, "read ");
                if (pHeader.p_flags & SHF_WRITE) fprintf(stream, "write ");
                if (pHeader.p_flags & SHF_EXEC)  fprintf(stream, "execute "); 
                if (sheader.sh_type == SHT_NOBITS) fprintf(stream, "uninititalized");
            }
            // write total
            fprintf(stream, "\n%-9s %-20s %-20s 0x%-8X 0x%-8X 0x%-6X ", basename, "total:", "", 
                (uint32_t)pHeader.p_vaddr, (uint32_t)pHeader.p_memsz, 1 << pHeader.p_align);
            if (pHeader.p_flags & SHF_READ)  fprintf(stream, "read ");
            if (pHeader.p_flags & SHF_WRITE) fprintf(stream, "write ");
            if (pHeader.p_flags & SHF_EXEC)  fprintf(stream, "execute "); 
            fprintf(stream, "\n");
 
            // find required codesize and datasize
            if (pHeader.p_flags & SHF_IP) {
                uint64_t s = pHeader.p_vaddr + pHeader.p_memsz;
                if (s > codesize) codesize = s;
            }
            else if (pHeader.p_flags & SHF_DATAP) {
                int64_t t = fileHeader.e_datap_base - pHeader.p_vaddr;
                if (t > (int64_t)datasize) datasize = t;
                int64_t u = pHeader.p_vaddr + pHeader.p_memsz - fileHeader.e_datap_base;
                if (u > (int64_t)datasize) datasize = u;
            }
            else if (pHeader.p_flags & SHF_THREADP) {
                int64_t t = fileHeader.e_threadp_base - pHeader.p_vaddr;
                if (t > (int64_t)datasize) datasize = t;
                int64_t u = pHeader.p_vaddr + pHeader.p_memsz - fileHeader.e_threadp_base;
                if (u > (int64_t)datasize) datasize = u;
            }
        }
        programHeaderOffset += programHeaderSize;
    }
    fprintf(stream, "\nip_base:  0x%X, datap_base: 0x%X, threadp_base: 0x%X, entry_point: 0x%X", 
        (uint32_t)fileHeader.e_ip_base, (uint32_t)fileHeader.e_datap_base, (uint32_t)fileHeader.e_threadp_base, (uint32_t)fileHeader.e_entry);
    fprintf(stream, "\ncodesize: 0x%llX, datasize: 0x%llX", codesize, datasize);
}
 
// Reset everything
void CELF::reset() {
    nSections = 0;
    moduleName = 0;
    library = 0;
    relinkable = false;
    symbols.setSize(0);
    sectionHeaders.setSize(0);
    programHeaders.setSize(0);
    relocations.setSize(0);
    stringBuffer.setSize(0);
    dataBuffer.setSize(0);
    moduleNames.setSize(0);
    libraryNames.setSize(0);
    setSize(0);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.