/*
 * Copyright (c) 2013-14, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#if !defined(_ELF_h_)
#define _ELF_h_

//! \name ELF types
//! Types used in ELF file structures.
//@{
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef /*off_t*/ uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
//@}

// All ELF structures are byte aligned. Any alignment padding is explicit.
#pragma pack(1)

//! \name File header
//@{

/*!
 * Constants for the various fields of Elf32_Ehdr.e_ident.
 */
enum
{
    EI_MAG0 = 0,
    EI_MAG1,
    EI_MAG2,
    EI_MAG3,
    EI_CLASS,
    EI_DATA,
    EI_VERSION,
    EI_PAD,
    EI_NIDENT = 16,

    // Magic number.
    ELFMAG0 = 0x7f,
    ELFMAG1 = 'E',
    ELFMAG2 = 'L',
    ELFMAG3 = 'F',

    // EI_CLASS
    ELFCLASSNONE = 0,
    ELFCLASS32 = 1,
    ELFCLASS64 = 2,

    // EI_DATA
    ELFDATANONE = 0,
    ELFDATA2LSB = 1,
    ELFDATA2MSB = 2
};

/*!
 * \brief ELF file header.
 */
struct Elf32_Ehdr
{
    unsigned char e_ident[EI_NIDENT]; //!< Magic number identifying the file format.
    Elf32_Half e_type;                //!< Identifies the object file format.
    Elf32_Half e_machine;             //!< Specified the architecture for the object file.
    Elf32_Word e_version;             //!< Object file version.
    Elf32_Addr e_entry;               //!< Virtual address of the entry point, or 0.
    Elf32_Off e_phoff;                //!< Program header table offset in bytes, or 0 if no program header table.
    Elf32_Off e_shoff;                //!< Section header table offset in bytes, or 0 if no section header table.
    Elf32_Word e_flags;               //!< Processor-specific flags associated with the file.
    Elf32_Half e_ehsize;              //!< The ELF header's size in bytes.
    Elf32_Half e_phentsize;           //!< Size in bytes of one entry in the program header table.
    Elf32_Half e_phnum;               //!< Number of entries in the program header table.
    Elf32_Half e_shentsize;           //!< Size in bytes of an entry in the section header table.
    Elf32_Half e_shnum;               //!< Number of entries in the section header table.
    Elf32_Half e_shstrndx;            //!< Section header table index of the section name string table.
};

/*!
 * Constants for #Elf32_Ehdr.e_type.
 */
enum
{
    ET_NONE,   //!< No file type.
    ET_REL,    //!< Relocatable file.
    ET_EXEC,   //!< Executable file.
    ET_DYN,    //!< Shared object file.
    ET_CORE,   //!< Core file.
    ET_LOPROC, //!< Low bound of processor-specific file types.
    ET_HIPROC  //!< High bound of processor-specific file types.
};

/*!
 * ARM-specific #Elf32_Ehdr.e_flags
 */
enum
{
    EF_ARM_HASENTRY = 0x02,         //!< #Elf32_Ehdr.e_entry contains a program-loader entry point.
    EF_ARM_SYMSARESORTED = 0x04,    //!< Each subsection of the symbol table is sorted by symbol value.
    EF_ARM_DYNSYMSUSESEGIDX = 0x08, //!< Symbols in dynamic symbol tables that are defined in sections included in
                                    //!program segment n have #Elf32_Sym.st_shndx = n + 1.
    EF_ARM_MAPSYMSFIRST = 0x10,     //!< Mapping symbols precede other local symbols in the symbol table.
    EF_ARM_EABIMASK = 0xff000000, //!< This masks an 8-bit version number, the version of the ARM EABI to which this ELF
                                  //!file conforms. The current EABI version is #ARM_EABI_VERSION.

    ARM_EABI_VERSION = 0x02000000 //!< Current ARM EABI version.
};

//@}

//! \name Sections
//@{

/*!
 * \brief ELF section header.
 *
 * An object file's section header table lets one locate all the file's
 * sections. The section header table is an array of #Elf32_Shdr structures.
 * A section header table index is a subscript into this array. The ELF
 * header's #Elf32_Ehdr::e_shoff member gives the byte offset from the beginning of
 * the file to the section header table; #Elf32_Ehdr::e_shnum tells how many entries
 * the section header table contains; #Elf32_Ehdr::e_shentsize gives the size in bytes
 * of each entry.
 *
 * Some section header table indexes are reserved. An object file will not
 * have sections for these special indexes:
 *  - #SHN_UNDEF
 *  - #SHN_LORESERVE
 *  - #SHN_LOPROC
 *  - #SHN_HIPROC
 *  - #SHN_ABS
 *  - #SHN_COMMON
 *  - #SHN_HIRESERVE
 */
struct Elf32_Shdr
{
    Elf32_Word sh_name;      //!< The section's name. Index into the section header string table section.
    Elf32_Word sh_type;      //!< Section type, describing the contents and semantics.
    Elf32_Word sh_flags;     //!< Section flags describing various attributes.
    Elf32_Addr sh_addr;      //!< The address at which the section will appear in the memory image, or 0.
    Elf32_Off sh_offset;     //!< Offset from beginning of the file to the first byte in the section.
    Elf32_Word sh_size;      //!< The section's size in bytes.
    Elf32_Word sh_link;      //!< Section header table link index. Interpretation depends on section type.
    Elf32_Word sh_info;      //!< Extra information about the section. Depends on section type.
    Elf32_Word sh_addralign; //!< Address alignment constraint. Values are 0 and positive powers of 2.
    Elf32_Word sh_entsize; //!< Size in bytes of section entries, or 0 if the section does not have fixed-size entries.
};

/*!
 * Special section indexes.
 */
enum
{
    SHN_UNDEF = 0,
    SHN_LORESERVE = 0xff00,
    SHN_LOPROC = 0xff00,
    SHN_HIPROC = 0xff1f,
    SHN_ABS = 0xfff1,    //!< The symbol has an absolute value that will not change because of relocation.
    SHN_COMMON = 0xfff2, //!< The symbol labels a common block that has not yet been allocated.
    SHN_HIRESERVE = 0xffff
};

/*!
 * Section type constants.
 */
enum
{
    SHT_NULL = 0,
    SHT_PROGBITS = 1,
    SHT_SYMTAB = 2,
    SHT_STRTAB = 3,
    SHT_RELA = 4,
    SHT_HASH = 5,
    SHT_DYNAMIC = 6,
    SHT_NOTE = 7,
    SHT_NOBITS = 8,
    SHT_REL = 9,
    SHT_SHLIB = 10,
    SHT_DYNSYM = 11
};

/*!
 * Section flag constants.
 */
enum
{
    SHF_WRITE = 0x1,    //!< Section is writable.
    SHF_ALLOC = 0x2,    //!< Allocate section.
    SHF_EXECINSTR = 0x4 //!< Section contains executable instructions.
};

/*!
 * ARM-specific section flag constants
 */
enum
{
    SHF_ENTRYSECT = 0x10000000, //!< The section contains an entry point.
    SHF_COMDEF = 0x80000000     //!< The section may be multiply defined in the input to a link step.
};

#define BSS_SECTION_NAME ".bss"
#define DATA_SECTION_NAME ".data"
#define TEXT_SECTION_NAME ".text"
#define SHSTRTAB_SECTION_NAME ".shstrtab"
#define STRTAB_SECTION_NAME ".strtab"
#define SYMTAB_SECTION_NAME ".symtab"

//@}

//! \name Segments
//@{

/*!
 * \brief ELF program header.
 *
 * An executable or shared object file's program header table is an array of
 * structures, each describing a segment or other information the system needs
 * to prepare the program for execution. An object file segment contains one
 * or more sections. Program headers are meaningful only for executable and
 * shared object files. A file specifies its own program header size with the
 * ELF header's #Elf32_Ehdr::e_phentsize and #Elf32_Ehdr::e_phnum members.
 */
struct Elf32_Phdr
{
    Elf32_Word p_type;   //!< What type of segment this header describes.
    Elf32_Off p_offset;  //!< Offset in bytes from start of file to the first byte of the segment.
    Elf32_Addr p_vaddr;  //!< Virtual address at which the segment will reside in memory.
    Elf32_Addr p_paddr;  //!< Physical address, for systems where this is relevant.
    Elf32_Word p_filesz; //!< Number of bytes of file data the segment consumes. May be zero.
    Elf32_Word p_memsz;  //!< Size in bytes of the segment in memory. May be zero.
    Elf32_Word p_flags;  //!< Flags relevant to the segment.
    Elf32_Word p_align; //!< Alignment constraint for segment addresses. Possible values are 0 and positive powers of 2.
};

/*!
 * Segment type constants.
 */
enum
{
    PT_NULL = 0,
    PT_LOAD = 1,
    PT_DYNAMIC = 2,
    PT_INTERP = 3,
    PT_NOTE = 4,
    PT_SHLIB = 5,
    PT_PHDR = 6
};

/*!
 * Program header flag constants.
 */
enum
{
    PF_X = 0x1, //!< Segment is executable.
    PF_W = 0x2, //!< Segment is writable.
    PF_R = 0x4  //!< Segment is readable.
};

//@}

//! \name Symbol table
//@{

enum
{
    STN_UNDEF = 0 //!< Undefined symbol index.
};

/*!
 * \brief ELF symbol table entry.
 *
 * An object file's symbol table holds information needed to locate and
 * relocate a program's symbolic definitions and references. A symbol
 * table index is a subscript into this array. Index 0 both designates
 * the first entry in the table and serves as the undefined symbol index.
 */
struct Elf32_Sym
{
    Elf32_Word st_name;     //!< Index into file's string table.
    Elf32_Addr st_value;    //!< Value associated with the symbol. Depends on context.
    Elf32_Word st_size;     //!< Size associated with symbol. 0 if the symbol has no size or an unknown size.
    unsigned char st_info;  //!< Specified the symbol's type and binding attributes.
    unsigned char st_other; //!< Currently 0 (reserved).
    Elf32_Half st_shndx;    //!< Section header table index for this symbol.
};

//! \name st_info macros
//! Macros for manipulating the st_info field of Elf32_Sym struct.
//@{
#define ELF32_ST_BIND(i) ((i) >> 4) //!< Get binding attributes.
#define ELF32_ST_TYPE(i) ((i)&0x0f) //!< Get symbol type.
#define ELF32_ST_INFO(b, t) \
    (((b) << 4) + ((t)&0x0f)) //!< Construct st_info value from binding attributes and symbol type.
                              //@}

/*!
 * \brief Symbol binding attributes.
 *
 * These constants are mask values.
 */
enum
{
    STB_LOCAL = 0,  //!< Local symbol not visible outside the object file.
    STB_GLOBAL = 1, //!< Symbol is visible to all object files being linked together.
    STB_WEAK = 2,   //!< Like global symbols, but with lower precedence.

    // Processor-specific semantics.
    STB_LOPROC = 13,
    STB_HIPROC = 15
};

/*!
 * \brief Symbol types.
 */
enum
{
    STT_NOTYPE = 0,  //!< The symbol's type is not specified.
    STT_OBJECT = 1,  //!< The symbol is associated with a data object, such as a variable or array.
    STT_FUNC = 2,    //!< The symbol is associated with a function or other executable code.
    STT_SECTION = 3, //!< The synmbol is associated with a section. Primarily used for relocation.
    STT_FILE = 4,    //!< A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other
                     //!STB_LOCAL symbols for the file, if it is present.

    STT_LOPROC = 13, //!< Low bound of processor-specific symbol types.
    STT_HIPROC = 15  //!< High bound of processor-specific symbol types.
};

/*!
 * GHS-specific constants
 */
enum
{
    STO_THUMB = 1 //!< This flag is set on #Elf32_Sym.st_other if the symbol is Thumb mode code.
};

#define ARM_SEQUENCE_MAPSYM "$a"
#define DATA_SEQUENCE_MAPSYM "$d"
#define THUMB_SEQUENCE_MAPSYM "$t"

#define THUMB_BL_TAGSYM "$b"
#define FN_PTR_CONST_TAGSYM "$f"
#define INDIRECT_FN_CALL_TAGSYM "$p"
#define MAPPING_SYMBOL_COUNT_TAGSYM "$m"

//@}

#pragma pack()

#endif // _ELF_h_
