/*
 * elf.c
 *
 * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _ELF_H_
#define _ELF_H_

#include <sdk/defs.h>

#define ELF_MAGIC       0x464C457F
#define ELF_CLASS_32BIT 1

#define ELF_SEGMENT_NULL    0
#define ELF_SEGMENT_LOAD    1
#define ELF_SEGMENT_DYNAMIC 2
#define ELF_SEGMENT_INTERP  3
#define ELF_SEGMENT_NOTE    4
#define ELF_SEGMENT_SHLIB   5
#define ELF_SEGMENT_PHDR    6
#define ELF_SEGMENT_TLS     7

#define ELF_SEGMENT_EXEC  (1 << 0)
#define ELF_SEGMENT_WRITE (1 << 1)
#define ELF_SEGMENT_READ  (1 << 2)

#define ELF_SECTION_FLAG_WRITE     (1 << 0)
#define ELF_SECTION_FLAG_ALLOC     (1 << 1)
#define ELF_SECTION_FLAG_EXECINSTR (1 << 2)

#define ELF_SYMBOL_UNDEF 0

#define ELF_R_SYM(x)  ((x) >> 8)
#define ELF_R_TYPE(x) ((x) & 0xFF)

enum
{
    ELF_DYNAMIC_TAG_NULL = 0,
    ELF_DYNAMIC_TAG_NEEDED,
    ELF_DYNAMIC_TAG_PLTRELSZ,
    ELF_DYNAMIC_TAG_PLTGOT,
    ELF_DYNAMIC_TAG_HASH,
    ELF_DYNAMIC_TAG_STRTAB,
    ELF_DYNAMIC_TAG_SYMTAB,
    ELF_DYNAMIC_TAG_RELA,
    ELF_DYNAMIC_TAG_RELASZ,
    ELF_DYNAMIC_TAG_RELAENT,
    ELF_DYNAMIC_TAG_STRSZ,
    ELF_DYNAMIC_TAG_SYMENT,
    ELF_DYNAMIC_TAG_INIT,
    ELF_DYNAMIC_TAG_FINI,
    ELF_DYNAMIC_TAG_SONAME,
    ELF_DYNAMIC_TAG_RPATH,
    ELF_DYNAMIC_TAG_SYMBOLIC,
    ELF_DYNAMIC_TAG_REL,
    ELF_DYNAMIC_TAG_RELSZ,
    ELF_DYNAMIC_TAG_RELENT,
    ELF_DYNAMIC_TAG_PLTREL,
    ELF_DYNAMIC_TAG_DEBUG,
    ELF_DYNAMIC_TAG_TEXTREL,
    ELF_DYNAMIC_TAG_JMPREL,
    ELF_DYNAMIC_TAG_BIND_NOW,
    ELF_DYNAMIC_TAG_INIT_ARRAY,
    ELF_DYNAMIC_TAG_FINI_ARRAY,
    ELF_DYNAMIC_TAG_INIT_ARRAYSZ,
    ELF_DYNAMIC_TAG_FINI_ARRAYSZ,
    ELF_DYNAMIC_TAG_RUNPATH,
    ELF_DYNAMIC_TAG_FLAGS,
    ELF_DYNAMIC_TAG_UNUSED,
    ELF_DYNAMIC_TAG_ENCODING,
    ELF_DYNAMIC_TAG_PREINIT_ARRAY,
    ELF_DYNAMIC_TAG_PREINIT_ARRAYSZ,
    ELF_DYNAMIC_TAG_SYMTAB_SHNDX,
};

enum
{
    ELF_SECTION_TYPE_NULL,
    ELF_SECTION_TYPE_PROGBITS,
    ELF_SECTION_TYPE_SYMTAB,
    ELF_SECTION_TYPE_STRTAB,
    ELF_SECTION_TYPE_RELA,
    ELF_SECTION_TYPE_HASH,
    ELF_SECTION_TYPE_DYNAMIC,
    ELF_SECTION_TYPE_NOTE,
    ELF_SECTION_TYPE_NOBITS,
    ELF_SECTION_TYPE_REL,
    ELF_SECTION_TYPE_SHLIB,
    ELF_SECTION_TYPE_DYNSYM,
};

enum
{
    ELF_R_386_NONE = 0,
    ELF_R_386_32,
    ELF_R_386_PC32,
    ELF_R_386_GOT32,
    ELF_R_386_PLT32,
    ELF_R_386_COPY,
    ELF_R_386_GLOB_DAT,
    ELF_R_386_JMP_SLOT,
    ELF_R_386_RELATIVE,
    ELF_R_386_GOTOFF,
    ELF_R_386_GOTPC,
    ELF_R_386_32PLT,

    ELF_R_386_16 = 20,
    ELF_R_386_PC16,
    ELF_R_386_8,
    ELF_R_386_PC8,
};

#pragma pack(push, 1)

typedef struct
{
    dword_t magic;
    byte_t class;
    byte_t encoding;
    byte_t version;
    byte_t system_abi;
    byte_t abi_version;
} elf_ident_t;

typedef struct
{
    word_t type;
    word_t machine;
    dword_t version;
    dword_t entry;
    dword_t segment_offset;
    dword_t section_offset;
    dword_t flags;
    word_t header_size;
    word_t segment_entry_size;
    word_t segment_count;
    word_t section_entry_size;
    word_t section_count;
    word_t section_string_index;
} elf32_header_t;

typedef struct
{
    dword_t type;
    dword_t offset;
    dword_t virtual_address;
    dword_t physical_address;
    dword_t file_size;
    dword_t mem_size;
    dword_t flags;
    dword_t alignment;
} elf32_segment_t;

typedef struct
{
    dword_t sh_name;
    dword_t sh_type;
    dword_t sh_flags;
    dword_t sh_addr;
    dword_t sh_offset;
    dword_t sh_size;
    dword_t sh_link;
    dword_t sh_info;
    dword_t sh_addralign;
    dword_t sh_entsize;
} elf32_section_t;

typedef struct
{
    int32_t d_tag;
    union
    {
        dword_t d_val;
        dword_t d_ptr;
    };
} elf32_dynamic_t;

typedef struct
{
    dword_t st_name;
    dword_t st_value;
    dword_t st_size;
    byte_t st_info;
    byte_t st_other;
    word_t st_shndx;
} elf32_symbol_t;

typedef struct
{
    dword_t r_offset;
    dword_t r_info;
} elf32_rel_t;

typedef struct
{
    dword_t r_offset;
    dword_t r_info;
    int32_t r_addend;
} elf32_rela_t;

#pragma pack(pop)

#endif
