#ifndef __ELFBASE_H__
#define __ELFBASE_H__

//=========================================================================
//typedef void far *      Elf32_Addr;     // program address
typedef unsigned long   Elf32_Addr;    //force normal =
#ifdef __BORLANDC__
#if sizeof(Elf32_Addr) != sizeof(void *)
#error
#endif
#endif
typedef unsigned short  Elf32_Half;
typedef unsigned long   Elf32_Off;      // file offset
typedef signed long     Elf32_Sword;
typedef unsigned long   Elf32_Word;
//=========================================================================
#define     EI_MAG0     0
#define       ELFMAG0      0x7f
#define     EI_MAG1     1
#define       ELFMAG1      'E'
#define     EI_MAG2     2
#define       ELFMAG2      'L'
#define     EI_MAG3     3
#define       ELFMAG3      'F'
#define     EI_CLASS    4
#define       ELFCLASSNONE  0   // Invalid class
#define       ELFCLASS32    1   // 32bit object
#define       ELFCLASS64    2   // 64bit object
#define     EI_DATA     5
#define       ELFDATANONE    0   // Invalid data encoding
#define       ELFDATA2LSB    1   // low byte first
#define       ELFDATA2MSB    2   // high byte first
#define     EI_VERSION  6        // file version
#define     EI_PAD      7        // start of padding bytes
#define EI_NIDENT 16             // sizeof


typedef struct {
  unsigned char   e_ident[EI_NIDENT];   // see above
  Elf32_Half      e_type;               // enum ET
  Elf32_Half      e_machine;            // enum EM
  Elf32_Word      e_version;            // enum EV
  Elf32_Addr      e_entry;              // virtual start address
  Elf32_Off       e_phoff;              // off to program header table's (pht)
  Elf32_Off       e_shoff;              // off to section header table's (sht)
  Elf32_Word      e_flags;              // EF_machine_flag
  Elf32_Half      e_ehsize;             // header's size
  Elf32_Half      e_phentsize;          // size of pht element
  Elf32_Half      e_phnum;              // entry counter in pht
  Elf32_Half      e_shentsize;          // size of sht element
  Elf32_Half      e_shnum;              // entry count in sht
  Elf32_Half      e_shstrndx;           // sht index in name table
} Elf32_Ehdr;


enum elf_ET {
  ET_NONE = 0,    // No file type
  ET_REL  = 1,    // Relocatable file
  ET_EXEC = 2,    // Executable file
  ET_DYN  = 3,    // Share object file
  ET_CORE = 4,    // Core file
  ET_LOPROC = 0xff00u, // Processor specific
  ET_HIPROC = 0xffffu  // Processor specific
};

enum elf_EM {
  EM_NONE  = 0,   // No machine
  EM_M32   = 1,   // AT & T WE 32100
  EM_SPARC = 2,   // Sparc
  EM_386   = 3,   // Intel 80386
  EM_68K   = 4,   // Motorola 68000
  EM_88K   = 5,   // Motorola 88000
  EM_486   = 6,
//ATTENTION!!! in documentation present next values
//  EM_860   = 6,   // Intel 80860
//  EM_MIPS  = 7,    // MIPS RS3000
//in linux RS3000 = 8, !!!
// дальше взято из linux
    EM_860	   =  7,
    EM_MIPS	   =  8,  // Mips 3000 (officialy, big-endian only)
//  EM_MIPS_RS4_BE = 10,  //MIPS RS4000 Big Endian
//  EM_SPARC_64    = 11,  // SPARC v9
  EM_PARISC      = 15,  // HPPA
  EM_SPARC32PLUS = 18,  // Sun's v8plus
  EM_I960  = 19,  // Intel 960
  EM_PPC   = 20,  // Power PC
  EM_ARM   = 40,  // ARM
  EM_SH    = 42,  // Hitachi SH
  EM_SPARC64= 43,  // Sparc 64
  EM_ARC   = 45,  // ARC
  EM_H8300  = 46,  // Hitachi H8/300
  EM_H8300H = 47,  // Hitachi H8/300H
  EM_H8S    = 48,  // Hitachi H8S
  EM_H8500  = 49,  // Hitachi H8/500
  EM_IA64  = 50,  // Intel Itanium IA64
  EM_6812  = 53,  // Motorla MC68HC12
  EM_X86_64= 62,  // Advanced Micro Devices X86-64 processor
  EM_ST9   = 67,  // ST9+
  EM_6811  = 70,  // Motorla MC68HC11
  EM_FR    = 84,  // Fujitsu FR Family
  EM_M32R  = 88,  // Mitsubishi 32bit RISC
  EM_ALPHA = 0x9026 // DEC Alpha
};

enum elf_EV {
  EV_NONE    = 0, // None version
  EV_CURRENT = 1  // Current version
// in linux header
// EV_NUM      = 2
};

// special section indexed
enum elh_SHN {
  SHN_UNDEF     = 0,       // undefined/missing/...
#ifndef __DOS16__
  SHN_LORESERVE = 0xff00,
  SHN_LOPROC    = 0xff00,
  SHN_HIPROC    = 0xff1f,
  SHN_ABS       = 0xfff1,  // absolute value
  SHN_COMMON    = 0xfff2,  //common values (fortran/c)
  SHN_HIRESERVE = 0xffff
#else
#define  SHN_LORESERVE  0xff00ul
#define  SHN_LOPROC     0xff00ul
#define  SHN_HIPROC     0xff1ful
#define  SHN_ABS        0xfff1ul  // absolute value
#define  SHN_COMMON     0xfff2ul  //common values (fortran/c)
#define  SHN_HIRESERVE  0xfffful
#endif
};
//==========

typedef struct {
  Elf32_Word    sh_name;      // index in string table
  Elf32_Word    sh_type;      // enum SHT
  Elf32_Word    sh_flags;     // enum SHF
  Elf32_Addr    sh_addr;      // address in memmory (or 0)
  Elf32_Off     sh_offset;    // offset in file
  Elf32_Word    sh_size;      // section size in bytes
  Elf32_Word    sh_link;      // index in symbol table
  Elf32_Word    sh_info;      // extra information
  Elf32_Word    sh_addralign; // 0 & 1 => no alignment
  Elf32_Word    sh_entsize;   // size symbol table or eq.
} Elf32_Shdr;


enum elf_SHT {
  SHT_NULL      = 0,    // inactive - no assoc. section
  SHT_PROGBITS  = 1,    // internal program information
  SHT_SYMTAB    = 2,    // symbol table (static)
  SHT_STRTAB    = 3,    // string table
  SHT_RELA      = 4,    // relocation entries
  SHT_HASH      = 5,    // symbol hash table
  SHT_DYNAMIC   = 6,    // inf. for dynamic linking
  SHT_NOTE      = 7,    // additional info
  SHT_NOBITS    = 8,    // no placed in file
  SHT_REL       = 9,    // relocation entries without explicit address
  SHT_SHLIB     = 10,   // RESERVED
  SHT_DYNSYM    = 11,   // Dynamic Symbol Table
// define in linux header
//  SHT_NUM       = 12,

#ifndef __DOS16__
  SHT_LOPROC    = 0x70000000ul,
  SHT_HIPROC    = 0x7ffffffful,
  SHT_LOUSER    = 0x80000000ul,
  SHT_HIUSER    = 0xfffffffful
#endif
};

// section by index 0 ==
// { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };

enum elf_SHF {
  SHF_WRITE     = (1 << 0),     // writable data
  SHF_ALLOC     = (1 << 1),     // occupies memory
  SHF_EXECINSTR = (1 << 2),     // machine instruction

  SHF_MERGE     = (1 << 4),     // can be merged
  SHF_STRINGS   = (1 << 5),     // contains nul-terminated strings
  SHF_INFO_LINK = (1 << 6),     // sh_info contains SHT index
  SHF_LINK_ORDER= (1 << 7),     // preserve order after combining
  SHF_OS_NONCONFORMING = (1 << 8), // non-standard os specific handling required
  SHF_GROUP     = (1 << 9),     // section is memory of a group
  SHF_TLS       = (1 << 10),    // section holds thread-local data

  SHF_MASKOS    = 0x0ff00000,   // os specific
  SHF_MASKPROC  = 0xf0000000,   // processor specific
};

typedef struct {
  Elf32_Word    st_name;        //index in string table
  Elf32_Addr    st_value;       //absolute value or addr
  Elf32_Word    st_size;        //0-unknow or no, elsewere symbol size in bytes
  unsigned char st_info;        //type and attribute (thee below)
  unsigned char st_other;       //==0
  Elf32_Half    st_shndx;       //index in section header table
} Elf32_Sym;

#define ELF32_ST_BIND(i)    ((i)>>4)
#define ELF32_ST_TYPE(i)    ((i)&0xf)
#define ELF32_ST_INFO(b,t)  (((b)<<4)+((t)&0xf))

enum elf_ST_BIND {
  STB_LOCAL  = 0,
  STB_GLOBAL = 1,
  STB_WEAK   = 2,
  STB_LOPROC = 13,              //processor-
  STB_HIPROC = 15               //          specific
};

enum elf_ST_TYPE {
  STT_NOTYPE    = 0,
  STT_OBJECT  = 1,              // associated with data object
  STT_FUNC    = 2,              // associated with function or execut. code
  STT_SECTION = 3,
  STT_FILE    = 4,              // name of source file
  STT_LOPROC = 13,              //processor-
  STT_HIPROC = 15               //          specific
};

// relocation
typedef struct {
  Elf32_Addr    r_offset;       //virtual address
  Elf32_Word    r_info;         //type of relocation
}Elf32_Rel;

#define ELF32_R_SYM(i)    ((i)>>8)
#define ELF32_R_TYPE(i)   ((unsigned char)(i))
#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))

typedef struct {
  Elf32_Addr    r_offset;
  Elf32_Word    r_info;
  Elf32_Sword   r_addend;       //constant to compute
}Elf32_Rela;

//=================Loading & dynamic linking========================
// program header
typedef struct {
  Elf32_Word    p_type;         //Segment type. see below
  Elf32_Off     p_offset;       //from beginning of file at 1 byte of segment resides
  Elf32_Addr    p_vaddr;        //virtual addr of 1 byte
  Elf32_Addr    p_paddr;        //reserved for system
  Elf32_Word    p_filesz;       //may be 0
  Elf32_Word    p_memsz;        //my be 0
  Elf32_Word    p_flags;        // for PT_LOAD access mask (PF_
#define PF_R 4
#define PF_W 2
#define PF_X 1
  Elf32_Word    p_align;        //0/1-no,
}Elf32_Phdr;

enum elf_SEGTYPE {
  PT_NULL    = 0,               //ignore entries in program table
  PT_LOAD    = 1,               //loadable segmen described in _filesz & _memsz
  PT_DYNAMIC = 2,               //dynamic linking information
  PT_INTERP  = 3,               //path name to interpreter (loadable)
  PT_NOTE    = 4,               //auxilarry information
  PT_SHLIB   = 5,               //reserved. Has no specified semantics
  PT_PHDR    = 6,               //location & size program header table
#ifndef __DOS16__
  PT_LOPROC  = 0x70000000ul,    // processor-
  PT_HIPROC  = 0x7ffffffful     //           specific
#endif
};

//=================Dynamic section===============================
typedef struct {
  Elf32_Sword   d_tag;          //see below
  union {
    Elf32_Word  d_val;          //integer value with various interpretation
    Elf32_Addr  d_ptr;          //programm virtual adress
  } d_un;
}Elf32_Dyn;
//extern Elf32_Dyn _DYNAMIC[];

enum elf_DTAG {
  DT_NULL     = 0,              //(-) end ofd _DYNAMIC array
  DT_NEEDED   = 1,              //(v) str-table offset name to needed library
  DT_PLTRELSZ = 2,              //(v) tot.size in bytes of relocation entries
  DT_PLTGOT   = 3,              //(p) see below
  DT_HASH     = 4,              //(p) addr. of symbol hash teble
  DT_STRTAB   = 5,              //(p) addr of string table
  DT_SYMTAB   = 6,              //(p) addr of symbol table
  DT_RELA     = 7,              //(p) addr of relocation table
  DT_RELASZ   = 8,              //(v) size in bytes of DT_RELA table
  DT_RELAENT  = 9,              //(v) size in bytes of DT_RELA entry
  DT_STRSZ    = 10,             //(v) size in bytes of string table
  DT_SYMENT   = 11,             //(v) size in byte of symbol table entry
  DT_INIT     = 12,             //(p) addr. of initialization function
  DT_FINI     = 13,             //(p) addr. of termination function
  DT_SONAME   = 14,             //(v) offs in str.-table - name of shared object
  DT_RPATH    = 15,             //(v) offs in str-table - search patch
  DT_SYMBOLIC = 16,             //(-) start search of shared object
  DT_REL      = 17,             //(p) similar to DT_RELA
  DT_RELSZ    = 18,             //(v) tot.size in bytes of DT_REL
  DT_RELENT   = 19,             //(v) size in bytes of DT_REL entry
  DT_PLTREL   = 20,             //(v) type of relocation (DT_REL or DT_RELA)
  DT_DEBUG    = 21,             //(p) not specified
  DT_TEXTREL  = 22,             //(-) segment permisson
  DT_JMPREL   = 23,             //(p) addr of dlt procedure (if present)
#ifndef __DOS16__
  DT_LOPROC   = 0x70000000ul,   //(?) processor-
  DT_HIPROC   = 0x7ffffffful    //(?)           specific
#endif
};

//===============================elf64 types=============================
typedef struct {
  uint8     e_ident[EI_NIDENT]; // see above
  int16     e_type;
  uint16    e_machine;
  int32     e_version;
  uint64    e_entry;          // Entry point virtual address
  uint64    e_phoff;          // Program header table file offset
  uint64    e_shoff;          // Section header table file offset
  int32     e_flags;
  int16     e_ehsize;
  int16     e_phentsize;
  int16     e_phnum;
  int16     e_shentsize;
  int16     e_shnum;
  int16     e_shstrndx;
} Elf64_Ehdr;


typedef struct {
  uint32    sh_name;      // Section name, index in string tbl
  uint32    sh_type;      // Type of section
  uint64    sh_flags;     // Miscellaneous section attributes
  uint64    sh_addr;      // Section virtual addr at execution
  uint64    sh_offset;    // Section file offset
  uint64    sh_size;      // Size of section in bytes
  uint32    sh_link;      // Index of another section
  uint32    sh_info;      // Additional section information
  uint64    sh_addralign; // Section alignment
  uint64    sh_entsize;   // Entry size if section holds table
} Elf64_Shdr;

//
typedef struct {
  uint32    st_name;    // Symbol name, index in string tbl
  uint8     st_info;    // Type and binding attributes
  uint8     st_other;   // No defined meaning, 0
  uint16    st_shndx;   // Associated section index
  uint64    st_value;   // Value of the symbol
  uint64    st_size;    // Associated symbol size
} Elf64_Sym;


typedef struct {
  uint64    r_offset;  // Location at which to apply the action
  uint64    r_info;    // index and type of relocation
} Elf64_Rel;


typedef struct {
  uint64    r_offset;    // Location at which to apply the action
  uint64    r_info;      // index and type of relocation
   int64    r_addend;    // Constant addend used to compute value
} Elf64_Rela;


//#define ELF64_R_SYM(i)	   ((i) >> 32)
//#define ELF64_R_TYPE(i)    ((i) & 0xffffffff)
//#define ELF64_R_INFO(s,t)  (((bfd_vma) (s) << 32) + (bfd_vma) (t))
#define ELF64_R_SYM(i)     high(i)
#define ELF64_R_TYPE(i)    low(i)


typedef struct {
  int32     p_type;
  int32     p_flags;
  uint64    p_offset;   // Segment file offset
  uint64    p_vaddr;    // Segment virtual address
  uint64    p_paddr;    // Segment physical address
  uint64    p_filesz;   // Segment size in file
  uint64    p_memsz;    // Segment size in memory
  uint64    p_align;    // Segment alignment, file & memory
} Elf64_Phdr;

typedef struct
{
  uint64 d_tag;   // entry tag value
  uint64 d_un;
} Elf64_Dyn;
//extern Elf64_Dyn _DYNAMIC[];

#endif // __ELFBASE_H__
