/* p_elf.h --

   This file is part of the UPX executable compressor.

   Copyright (C) 1996-2024 Markus Franz Xaver Johannes Oberhumer
   Copyright (C) 1996-2024 Laszlo Molnar
   All Rights Reserved.

   UPX and the UCL library are free software; you can redistribute them
   and/or modify them under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.
   If not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   Markus F.X.J. Oberhumer              Laszlo Molnar
   <markus@oberhumer.com>               <ezerotven+github@gmail.com>
 */

#pragma once

/*************************************************************************
// N_Elf
**************************************************************************/

namespace N_Elf {

// integral types
template <class THalf, class TWord, class TXword, class TAddr, class TOff>
struct ElfITypes {
    typedef THalf Half;
    typedef TWord Word;
    typedef TXword Xword;
    typedef TAddr Addr;
    typedef TOff Off;
    typedef THalf Section;
    typedef THalf Versym;
};

// The ELF file header. This appears at the start of every ELF file.
template <class TElfITypes>
packed_struct(Ehdr) {
    typedef typename TElfITypes::Half Half;
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Off Off;

    unsigned char e_ident[16]; /* Magic number and other info */
    Half e_type;               /* Object file type */
    Half e_machine;            /* Architecture */
    Word e_version;            /* Object file version */
    Addr e_entry;              /* Entry point virtual address */
    Off e_phoff;               /* Program header table file offset */
    Off e_shoff;               /* Section header table file offset */
    Word e_flags;              /* Processor-specific flags */
    Half e_ehsize;             /* ELF header size in bytes */
    Half e_phentsize;          /* Program header table entry size */
    Half e_phnum;              /* Program header table entry count */
    Half e_shentsize;          /* Section header table entry size */
    Half e_shnum;              /* Section header table entry count */
    Half e_shstrndx;           /* Section header string table index */

#define WANT_EHDR_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Dyn) {
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;

    Xword d_tag;
    Addr d_val;

#define WANT_DYN_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Rel) {
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;

    Addr r_offset;
    Xword r_info;
};

template <class TElfITypes>
packed_struct(Rela) {
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;

    Addr r_offset;
    Xword r_info;
    Xword r_addend;
};

template <class TElfITypes>
packed_struct(External_Note) {
    typedef typename TElfITypes::Word Word;

    Word xn_namesz; // includes terminating '\0'
    Word xn_datasz;
    Word xn_type;
    // char xn_name[N];  // terminate with '\0'
    // char xn_data[M];  // aligned to 0 mod 4
};

} // namespace N_Elf

/*************************************************************************
// N_Elf32
**************************************************************************/

namespace N_Elf32 {

template <class TElfITypes>
packed_struct(Phdr) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Off Off;

    Word p_type;   /* Segment type */
    Off p_offset;  /* Segment file offset */
    Addr p_vaddr;  /* Segment virtual address */
    Addr p_paddr;  /* Segment physical address */
    Word p_filesz; /* Segment size in file */
    Word p_memsz;  /* Segment size in memory */
    Word p_flags;  /* Segment flags */
    Word p_align;  /* Segment alignment */

#define WANT_PHDR_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Shdr) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Off Off;

    Word sh_name;      /* Section name (string tbl index) */
    Word sh_type;      /* Section type */
    Word sh_flags;     /* Section flags */
    Addr sh_addr;      /* Section virtual addr at execution */
    Off sh_offset;     /* Section file offset */
    Word sh_size;      /* Section size in bytes */
    Word sh_link;      /* Link to another section */
    Word sh_info;      /* Additional section information */
    Word sh_addralign; /* Section alignment */
    Word sh_entsize;   /* Entry size if section holds table */

#define WANT_SHDR_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Sym) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Section Section;

    Word st_name;           /* symbol name (index into string table) */
    Addr st_value;          /* symbol value */
    Word st_size;           /* symbol size */
    unsigned char st_info;  /* symbol type and binding */
    unsigned char st_other; /* symbol visibility */
    Section st_shndx;       /* section index */

#define WANT_SYM_ENUM 1
#include "p_elf_enum.h"

    static unsigned int get_st_bind(unsigned x) { return 0xf & (x >> 4); }
    static unsigned int get_st_type(unsigned x) { return 0xf & x; }
    static unsigned char make_st_info(unsigned bind, unsigned type) {
        return (unsigned char) (((bind << 4) + (0xf & type)) & 0xff);
    }
};

} // namespace N_Elf32

/*************************************************************************
// N_Elf64
**************************************************************************/

namespace N_Elf64 {

template <class TElfITypes>
packed_struct(Phdr) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Off Off;

    Word p_type;    /* Segment type */
    Word p_flags;   /* Segment flags */
    Off p_offset;   /* Segment file offset */
    Addr p_vaddr;   /* Segment virtual address */
    Addr p_paddr;   /* Segment physical address */
    Xword p_filesz; /* Segment size in file */
    Xword p_memsz;  /* Segment size in memory */
    Xword p_align;  /* Segment alignment */

#define WANT_PHDR_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Shdr) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Off Off;

    Word sh_name;       /* Section name (string tbl index) */
    Word sh_type;       /* Section type */
    Xword sh_flags;     /* Section flags */
    Addr sh_addr;       /* Section virtual addr at execution */
    Off sh_offset;      /* Section file offset */
    Xword sh_size;      /* Section size in bytes */
    Word sh_link;       /* Link to another section */
    Word sh_info;       /* Additional section information */
    Xword sh_addralign; /* Section alignment */
    Xword sh_entsize;   /* Entry size if section holds table */

#define WANT_SHDR_ENUM 1
#include "p_elf_enum.h"
};

template <class TElfITypes>
packed_struct(Sym) {
    typedef typename TElfITypes::Word Word;
    typedef typename TElfITypes::Xword Xword;
    typedef typename TElfITypes::Addr Addr;
    typedef typename TElfITypes::Section Section;

    Word st_name;           /* symbol name (index into string table) */
    unsigned char st_info;  /* symbol type and binding */
    unsigned char st_other; /* symbol visibility */
    Section st_shndx;       /* section index */
    Addr st_value;          /* symbol value */
    Xword st_size;          /* symbol size */

#define WANT_SYM_ENUM 1
#include "p_elf_enum.h"

    static unsigned int get_st_bind(unsigned x) { return 0xf & (x >> 4); }
    static unsigned int get_st_type(unsigned x) { return 0xf & x; }
    static unsigned char make_st_info(unsigned bind, unsigned type) {
        return (unsigned char) (((bind << 4) + (0xf & type)) & 0xff);
    }
};

} // namespace N_Elf64

/*************************************************************************
// aggregate types into an ElfClass
**************************************************************************/

namespace N_Elf {

template <class TP>
struct ElfClass_32 {
    typedef TP BeLePolicy;

    // integral types (target endianness)
    typedef typename TP::U16 TE16;
    typedef typename TP::U32 TE32;
    typedef typename TP::U64 TE64;
    typedef N_Elf::ElfITypes<TE16, TE32, TE32, TE32, TE32> ElfITypes;

    // ELF types
    typedef N_Elf ::Ehdr<ElfITypes> Ehdr;
    typedef N_Elf32::Phdr<ElfITypes> Phdr;
    typedef N_Elf32::Shdr<ElfITypes> Shdr;
    typedef N_Elf ::Dyn<ElfITypes> Dyn;
    typedef N_Elf ::Rel<ElfITypes> Rel;
    typedef N_Elf ::Rela<ElfITypes> Rela;
    typedef N_Elf32::Sym<ElfITypes> Sym;
    typedef N_Elf ::External_Note<ElfITypes> External_Note;

    static void compileTimeAssertions() {
        BeLePolicy::compileTimeAssertions();
        COMPILE_TIME_ASSERT(sizeof(Ehdr) == 52)
        COMPILE_TIME_ASSERT(sizeof(Phdr) == 32)
        COMPILE_TIME_ASSERT(sizeof(Shdr) == 40)
        COMPILE_TIME_ASSERT(sizeof(Dyn) == 8)
        COMPILE_TIME_ASSERT(sizeof(Rel) == 8)
        COMPILE_TIME_ASSERT(sizeof(Rela) == 12)
        COMPILE_TIME_ASSERT(sizeof(Sym) == 16)
        COMPILE_TIME_ASSERT(sizeof(External_Note) == 12)
        COMPILE_TIME_ASSERT_ALIGNED1(Ehdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Phdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Shdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Dyn)
        COMPILE_TIME_ASSERT_ALIGNED1(Rel)
        COMPILE_TIME_ASSERT_ALIGNED1(Rela)
        COMPILE_TIME_ASSERT_ALIGNED1(Sym)
        COMPILE_TIME_ASSERT_ALIGNED1(External_Note)
    }
};

template <class TP>
struct ElfClass_64 {
    typedef TP BeLePolicy;

    // integral types (target endianness)
    typedef typename TP::U16 TE16;
    typedef typename TP::U32 TE32;
    typedef typename TP::U64 TE64;
    typedef N_Elf::ElfITypes<TE16, TE32, TE64, TE64, TE64> ElfITypes;

    // ELF types
    typedef N_Elf ::Ehdr<ElfITypes> Ehdr;
    typedef N_Elf64::Phdr<ElfITypes> Phdr;
    typedef N_Elf64::Shdr<ElfITypes> Shdr;
    typedef N_Elf ::Dyn<ElfITypes> Dyn;
    typedef N_Elf ::Rel<ElfITypes> Rel;
    typedef N_Elf ::Rela<ElfITypes> Rela;
    typedef N_Elf64::Sym<ElfITypes> Sym;
    typedef N_Elf ::External_Note<ElfITypes> External_Note;

    static void compileTimeAssertions() {
        BeLePolicy::compileTimeAssertions();
        COMPILE_TIME_ASSERT(sizeof(Ehdr) == 64)
        COMPILE_TIME_ASSERT(sizeof(Phdr) == 56)
        COMPILE_TIME_ASSERT(sizeof(Shdr) == 64)
        COMPILE_TIME_ASSERT(sizeof(Dyn) == 16)
        COMPILE_TIME_ASSERT(sizeof(Rel) == 16)
        COMPILE_TIME_ASSERT(sizeof(Rela) == 24)
        COMPILE_TIME_ASSERT(sizeof(Sym) == 24)
        COMPILE_TIME_ASSERT(sizeof(External_Note) == 12)
        COMPILE_TIME_ASSERT_ALIGNED1(Ehdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Phdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Shdr)
        COMPILE_TIME_ASSERT_ALIGNED1(Dyn)
        COMPILE_TIME_ASSERT_ALIGNED1(Rel)
        COMPILE_TIME_ASSERT_ALIGNED1(Rela)
        COMPILE_TIME_ASSERT_ALIGNED1(Sym)
        COMPILE_TIME_ASSERT_ALIGNED1(External_Note)
    }
};

} // namespace N_Elf

typedef N_Elf::ElfClass_32<N_BELE_CTP::HostPolicy> ElfClass_Host32;
typedef N_Elf::ElfClass_64<N_BELE_CTP::HostPolicy> ElfClass_Host64;
typedef N_Elf::ElfClass_32<N_BELE_CTP::BEPolicy> ElfClass_BE32;
typedef N_Elf::ElfClass_64<N_BELE_CTP::BEPolicy> ElfClass_BE64;
typedef N_Elf::ElfClass_32<N_BELE_CTP::LEPolicy> ElfClass_LE32;
typedef N_Elf::ElfClass_64<N_BELE_CTP::LEPolicy> ElfClass_LE64;

/*************************************************************************
// shortcuts
**************************************************************************/

typedef ElfClass_Host32::Ehdr Elf32_Ehdr;
typedef ElfClass_Host32::Phdr Elf32_Phdr;
typedef ElfClass_Host32::Shdr Elf32_Shdr;
typedef ElfClass_Host32::Dyn Elf32_Dyn;
typedef ElfClass_Host32::Rel Elf32_Rel;
typedef ElfClass_Host32::Rela Elf32_Rela;
typedef ElfClass_Host32::Sym Elf32_Sym;
typedef ElfClass_Host32::External_Note Elf32_External_Note;

typedef ElfClass_Host64::Ehdr Elf64_Ehdr;
typedef ElfClass_Host64::Phdr Elf64_Phdr;
typedef ElfClass_Host64::Shdr Elf64_Shdr;
typedef ElfClass_Host64::Dyn Elf64_Dyn;
typedef ElfClass_Host64::Rel Elf64_Rel;
typedef ElfClass_Host64::Rela Elf64_Rela;
typedef ElfClass_Host64::Sym Elf64_Sym;
typedef ElfClass_Host64::External_Note Elf64_External_Note;

typedef ElfClass_BE32::Ehdr Elf_BE32_Ehdr;
typedef ElfClass_BE32::Phdr Elf_BE32_Phdr;
typedef ElfClass_BE32::Shdr Elf_BE32_Shdr;
typedef ElfClass_BE32::Dyn Elf_BE32_Dyn;
typedef ElfClass_BE32::Rel Elf_BE32_Rel;
typedef ElfClass_BE32::Rela Elf_BE32_Rela;
typedef ElfClass_BE32::Sym Elf_BE32_Sym;
typedef ElfClass_BE32::External_Note Elf_BE32_External_Note;

typedef ElfClass_BE64::Ehdr Elf_BE64_Ehdr;
typedef ElfClass_BE64::Phdr Elf_BE64_Phdr;
typedef ElfClass_BE64::Shdr Elf_BE64_Shdr;
typedef ElfClass_BE64::Dyn Elf_BE64_Dyn;
typedef ElfClass_BE64::Rel Elf_BE64_Rel;
typedef ElfClass_BE64::Rela Elf_BE64_Rela;
typedef ElfClass_BE64::Sym Elf_BE64_Sym;
typedef ElfClass_BE64::External_Note Elf_BE64_External_Note;

typedef ElfClass_LE32::Ehdr Elf_LE32_Ehdr;
typedef ElfClass_LE32::Phdr Elf_LE32_Phdr;
typedef ElfClass_LE32::Shdr Elf_LE32_Shdr;
typedef ElfClass_LE32::Dyn Elf_LE32_Dyn;
typedef ElfClass_LE32::Rel Elf_LE32_Rel;
typedef ElfClass_LE32::Rela Elf_LE32_Rela;
typedef ElfClass_LE32::Sym Elf_LE32_Sym;
typedef ElfClass_LE32::External_Note Elf_LE32_External_Note;

typedef ElfClass_LE64::Ehdr Elf_LE64_Ehdr;
typedef ElfClass_LE64::Phdr Elf_LE64_Phdr;
typedef ElfClass_LE64::Shdr Elf_LE64_Shdr;
typedef ElfClass_LE64::Dyn Elf_LE64_Dyn;
typedef ElfClass_LE64::Rel Elf_LE64_Rel;
typedef ElfClass_LE64::Rela Elf_LE64_Rela;
typedef ElfClass_LE64::Sym Elf_LE64_Sym;
typedef ElfClass_LE64::External_Note Elf_LE64_External_Note;

/* vim:set ts=4 sw=4 et: */
