unit elf64;

{$mode objfpc}{$H+}

interface

uses ctypes;

{
 /--------------------------------------\--\
 |SELF Header Structure(t_self_header)  |  |
 +--------------------------------------+--|-\
 |SELF Segment Structure(t_self_segment)|  |  | <- t_self_header.Num_Segments * SizeOf(t_self_segment)
 +--------------------------------------+--|-/
 |ELF Segment Structure(elf64_hdr)      |  |
 +--------------------------------------+--|-\
 |ELF Program header(elf64_phdr)        |  |  | <- elf64_hdr.e_phnum * SizeOf(elf64_phdr)
 +--------------------------------------+--|-/
 |Align(addr,16)                        |  |
 +--------------------------------------+  |
 |SELF authinfo(t_self_authinfo)        |  | <- t_self_header.Header_Size
 +--------------------------------------+  |
 |Content_ID/Digest_SHA_256             |  |
 +--------------------------------------+-/--\
 |Metadata/Segment Certification        |     | <- t_self_header.Meta_size
 +--------------------------------------+----/
 |ELF segments data                     |
 \--------------------------------------/
}

Const
 ET_NONE           =0;
 ET_REL            =1;
 ET_EXEC           =2;
 ET_DYN            =3;
 ET_CORE           =4;
 ET_SCE_EXEC       =$FE00;
 ET_SCE_REPLAY_EXEC=$FE01;
 ET_SCE_RELEXEC    =$FE04;
 ET_SCE_STUBLIB    =$FE0C;
 ET_SCE_DYNEXEC    =$FE10;
 ET_SCE_DYNAMIC    =$FE18;

 EI_MAG0       = 0;     // e_ident[] indexes
 EI_MAG1       = 1;
 EI_MAG2       = 2;
 EI_MAG3       = 3;
 EI_CLASS      = 4;
 EI_DATA       = 5;
 EI_VERSION    = 6;
 EI_OSABI      = 7;
 EI_ABIVERSION = 8;

 EI_NIDENT=16;

 ELFMAG =$464C457F;
 SELFMAG=4;

 EM_NONE       =0;
 EM_X86_64     =62; // AMD x86-64

 PT_NULL             = 0;
 PT_LOAD             = 1;
 PT_DYNAMIC          = 2;
 PT_INTERP           = 3;
 PT_NOTE             = 4;
 PT_SHLIB            = 5;
 PT_PHDR             = 6;
 PT_TLS              = 7;        // Thread local storage segment
 PT_SCE_RELA         = $60000000;
 PT_SCE_DYNLIBDATA   = $61000000;
 PT_SCE_PROCPARAM    = $61000001;
 PT_SCE_MODULE_PARAM = $61000002;
 PT_SCE_RELRO        = $61000010;
 PT_GNU_EH_FRAME     = $6474e550;
 PT_GNU_STACK        = $6474E551;
 PT_SCE_COMMENT      = $6FFFFF00;
 PT_SCE_VERSION      = $6FFFFF01;
 PT_SCE_SEGSYM       = $700000A8;

 // This is the info that is needed to parse the dynamic section of the file
 DT_NULL                     = 0;
 DT_NEEDED                   = 1;
 DT_PLTRELSZ                 = 2;
 DT_PLTGOT                   = 3;
 DT_HASH                     = 4;
 DT_STRTAB                   = 5;
 DT_SYMTAB                   = 6;
 DT_RELA                     = 7;
 DT_RELASZ                   = 8;
 DT_RELAENT                  = 9;
 DT_STRSZ                    =10;
 DT_SYMENT                   =11;
 DT_INIT                     =12;
 DT_FINI                     =13;
 DT_SONAME                   =14;
 DT_RPATH                    =15;
 DT_SYMBOLIC                 =16;
 DT_REL                      =17;
 DT_RELSZ                    =18;
 DT_RELENT                   =19;
 DT_PLTREL                   =20;
 DT_DEBUG                    =21;
 DT_TEXTREL                  =22;
 DT_JMPREL                   =23;
 DT_BIND_NOW                 =24;
 DT_INIT_ARRAY               =25;
 DT_FINI_ARRAY               =26;
 DT_INIT_ARRAYSZ             =27;
 DT_FINI_ARRAYSZ             =28;
 DT_RUNPATH                  =29;
 DT_FLAGS                    =30;
 DT_ENCODING                 =31;
 DT_PREINIT_ARRAY            =32;
 DT_PREINIT_ARRAYSZ          =33;
 DT_SCE_IDTABENTSZ           =$61000005;
 DT_SCE_FINGERPRINT          =$61000007;
 DT_SCE_ORIGINAL_FILENAME    =$61000009;
 DT_SCE_MODULE_INFO          =$6100000D;
 DT_SCE_NEEDED_MODULE        =$6100000F;
 DT_SCE_MODULE_ATTR          =$61000011;
 DT_SCE_EXPORT_LIB           =$61000013;
 DT_SCE_IMPORT_LIB           =$61000015;
 DT_SCE_EXPORT_LIB_ATTR      =$61000017;
 DT_SCE_IMPORT_LIB_ATTR      =$61000019;
 DT_SCE_STUB_MODULE_NAME     =$6100001D;
 DT_SCE_STUB_MODULE_VERSION  =$6100001F;
 DT_SCE_STUB_LIBRARY_NAME    =$61000021;
 DT_SCE_STUB_LIBRARY_VERSION =$61000023;
 DT_SCE_HASH                 =$61000025;
 DT_SCE_PLTGOT               =$61000027;
 DT_SCE_JMPREL               =$61000029;
 DT_SCE_PLTREL               =$6100002B;
 DT_SCE_PLTRELSZ             =$6100002D;
 DT_SCE_RELA                 =$6100002F;
 DT_SCE_RELASZ               =$61000031;
 DT_SCE_RELAENT              =$61000033;
 DT_SCE_STRTAB               =$61000035;
 DT_SCE_STRSZ                =$61000037;
 DT_SCE_SYMTAB               =$61000039;
 DT_SCE_SYMENT               =$6100003B;
 DT_SCE_HASHSZ               =$6100003D;
 DT_SCE_SYMTABSZ             =$6100003F;
 DT_SCE_HIOS                 =$6FFFF000;
 DT_GNU_HASH                 =$6ffffef5;
 DT_VERSYM                   =$6ffffff0;
 DT_RELACOUNT                =$6ffffff9;
 DT_RELCOUNT                 =$6ffffffa;
 DT_FLAGS_1                  =$6ffffffb;
 DT_VERDEF                   =$6ffffffc;
 DT_VERDEFNUM                =$6ffffffd;

 DF_ORIGIN    =$01;
 DF_SYMBOLIC  =$02;
 DF_TEXTREL   =$04;
 DF_BIND_NOW  =$08;
 DF_STATIC_TLS=$10;

 DF_1_BIND_NOW=$01;
 DF_1_NODELETE=$08;
 DF_1_LOADFLTR=$10;
 DF_1_NOOPEN  =$40;

 SHT_SYMTAB=2;
 SHT_STRTAB=3;

 // Relocation types for AMD x86-64 architecture
 R_X86_64_NONE                = 0; // No reloc
 R_X86_64_64                  = 1; // Direct 64 bit
 R_X86_64_PC32                = 2; // PC relative 32 bit signed
 R_X86_64_GOT32               = 3; // 32 bit GOT entry
 R_X86_64_PLT32               = 4; // 32 bit PLT address
 R_X86_64_COPY                = 5; // Copy symbol at runtime
 R_X86_64_GLOB_DAT            = 6; // Create GOT entry
 R_X86_64_JUMP_SLOT           = 7; // Create PLT entry
 R_X86_64_RELATIVE            = 8; // Adjust by program base
 R_X86_64_GOTPCREL            = 9; // 32 bit signed pc relative offset to GOT
 R_X86_64_32                  =10; // Direct 32 bit zero extended
 R_X86_64_32S                 =11; // Direct 32 bit sign extended
 R_X86_64_16                  =12; // Direct 16 bit zero extended
 R_X86_64_PC16                =13; // 16 bit sign extended pc relative
 R_X86_64_8                   =14; // Direct 8 bit sign extended
 R_X86_64_PC8                 =15; // 8 bit sign extended pc relative
 R_X86_64_DTPMOD64            =16; // ID of module containing symbol
 R_X86_64_DTPOFF64            =17; // Offset in module's TLS block
 R_X86_64_TPOFF64             =18; // Offset in initial TLS block
 R_X86_64_TLSGD               =19; // 32 bit signed PC relative offset to two GOT entries for GD symbol
 R_X86_64_TLSLD               =20; // 32 bit signed PC relative offset to two GOT entries for LD symbol
 R_X86_64_DTPOFF32            =21; // Offset in TLS block
 R_X86_64_GOTTPOFF            =22; // 32 bit signed PC relative offset to GOT entry for IE symbol
 R_X86_64_TPOFF32             =23; // Offset in initial TLS block
 R_X86_64_PC64                =24; // PC relative 64 bit
 R_X86_64_GOTOFF64            =25; // 64 bit offset to GOT
 R_X86_64_GOTPC32             =26; // 32 bit signed pc relative offset to GOT
 R_X86_64_GOT64               =27; // 64-bit GOT entry offset
 R_X86_64_GOTPCREL64          =28; // 64-bit PC relative offset to GOT entry
 R_X86_64_GOTPC64             =29; // 64-bit PC relative offset to GOT
 R_X86_64_GOTPLT64            =30; // like GOT64, says PLT entry needed
 R_X86_64_PLTOFF64            =31; // 64-bit GOT relative offset to PLT entry
 R_X86_64_SIZE32              =32; // Size of symbol plus 32-bit addend
 R_X86_64_SIZE64              =33; // Size of symbol plus 64-bit addend
 R_X86_64_GOTPC32_TLSDESC     =34; // GOT offset for TLS descriptor
 R_X86_64_TLSDESC_CALL        =35; // Marker for call through TLS descriptor
 R_X86_64_TLSDESC             =36; // TLS descriptor
 R_X86_64_IRELATIVE           =37; // Adjust indirectly by program base
 R_X86_64_RELATIVE64          =38; // 64bit adjust by program base
 R_X86_64_ORBIS_GOTPCREL_LOAD =40;

 STB_LOCAL =0;
 STB_GLOBAL=1;
 STB_WEAK  =2;

 STT_NOTYPE        = 0; //module_start/module_stop
 STT_OBJECT        = 1;
 STT_FUN           = 2;
 STT_SECTION       = 3;
 STT_FILE          = 4;
 STT_COMMON        = 5;
 STT_TLS           = 6;
 STT_LOOS          =10;
 STT_SCE           =11; //module_start/module_stop

 //ST_LOCAL_NONE      = 0x00
 //ST_LOCAL_OBJECT    = 0x01
 //ST_LOCAL_FUNCTION  = 0x02
 //ST_LOCAL_SECTION   = 0x03
 //ST_LOCAL_FILE      = 0x04
 //ST_LOCAL_COMMON    = 0x05
 //ST_LOCAL_TLS       = 0x06
 //ST_LOCAL_SCE       = 0x0B
 //ST_GLOBAL_NONE     = 0x10
 //ST_GLOBAL_OBJECT   = 0x11
 //ST_GLOBAL_FUNCTION = 0x12
 //ST_GLOBAL_SECTION  = 0x13
 //ST_GLOBAL_FILE     = 0x14
 //ST_GLOBAL_COMMON   = 0x15
 //ST_GLOBAL_TLS      = 0x16
 //ST_GLOBAL_SCE      = 0x1B
 //ST_WEAK_NONE       = 0x20
 //ST_WEAK_OBJECT     = 0x21
 //ST_WEAK_FUNCTION   = 0x22
 //ST_WEAK_SECTION    = 0x23
 //ST_WEAK_FILE       = 0x24
 //ST_WEAK_COMMON     = 0x25
 //ST_WEAK_TLS        = 0x26
 //ST_WEAK_SCE        = 0x2B

 STV_DEFAULT   =0;
 STV_INTERNAL  =1;
 STV_HIDDEN    =2;
 STV_PROTECTED =3;

 SHN_UNDEF=0;

 PF_X=$1;
 PF_W=$2;
 PF_R=$4;

type
 Elf64_Addr  =cuint64;
 Elf64_Half  =cuint16;
 Elf64_SHalf =cint64 ;
 Elf64_Off   =cuint64;
 Elf64_Sword =cint32 ;
 Elf64_Word  =cuint32;
 Elf64_Xword =cuint64;
 Elf64_Sxword=cint64 ;

 p_elf64_hdr=^elf64_hdr;
 elf64_hdr=packed record
  e_ident:Array[0..EI_NIDENT-1] of Byte; // ELF "magic number"
  e_type     :Elf64_Half;
  e_machine  :Elf64_Half;
  e_version  :Elf64_Word;
  e_entry    :Elf64_Addr; // Entry point virtual address from where the process starts executing.
  e_phoff    :Elf64_Off ; // Program header table file offset
  e_shoff    :Elf64_Off ; // Section header table file offset
  e_flags    :Elf64_Word;
  e_ehsize   :Elf64_Half;
  e_phentsize:Elf64_Half;
  e_phnum    :Elf64_Half;
  e_shentsize:Elf64_Half;
  e_shnum    :Elf64_Half;
  e_shstrndx :Elf64_Half;
 end;

 p_elf64_phdr=^elf64_phdr;
 elf64_phdr=packed record
  p_type  :Elf64_Word ;
  p_flags :Elf64_Word ;
  p_offset:Elf64_Off  ; // Segment file offset
  p_vaddr :Elf64_Addr ; // Segment virtual address
  p_paddr :Elf64_Addr ; // Segment physical address
  p_filesz:Elf64_Xword; // Segment size in file
  p_memsz :Elf64_Xword; // Segment size in memory
  p_align :Elf64_Xword; // Segment alignment, file & memory
 end;

 p_elf64_shdr=^elf64_shdr;
 elf64_shdr=packed record
  sh_name     :Elf64_Word ;   // Section name, index in string tbl
  sh_type     :Elf64_Word ;   // Type of section
  sh_flags    :Elf64_Xword;   // Miscellaneous section attributes
  sh_addr     :Elf64_Addr ;   // Section virtual addr at execution
  sh_offset   :Elf64_Off  ;   // Section file offset
  sh_size     :Elf64_Xword;   // Size of section in bytes
  sh_link     :Elf64_Word ;   // Index of another section
  sh_info     :Elf64_Word ;   // Additional section information
  sh_addralign:Elf64_Xword;   // Section alignment
  sh_entsize  :Elf64_Xword;   // Entry size if section holds table
 end;

 p_elf64_dyn=^elf64_dyn;
 elf64_dyn=packed record
  d_tag:Elf64_Sxword;  // entry tag value
  d_un :packed record
   Case Byte of
    0:(d_val:Elf64_Xword);
    1:(d_ptr:Elf64_Addr);
  end;
 end;

 p_elf64_rela=^elf64_rela;
 elf64_rela=packed record
  r_offset:Elf64_Addr;         // Location at which to apply the action
  r_info  :Elf64_Xword;        // index and type of relocation
  r_addend:Elf64_Sxword;       // Constant addend used to compute value
 end;

 p_elf64_sym=^elf64_sym;
 elf64_sym=packed record
  st_name :Elf64_Word;         // Symbol name, index in string tbl
  st_info :Byte;               // Type and binding attributes
  st_other:Byte;               // No defined meaning, 0
  st_shndx:Elf64_Half;         // Associated section index
  st_value:Elf64_Addr;         // Value of the symbol
  st_size :Elf64_Xword;        // Associated symbol size
 end;

const
 SELF_MAGIC     =$1D3D154F;
 SELF_VERSION   =$0;
 SELF_MODE      =$1;
 SELF_ENDIANNESS=$1;

 SELF_AUTH_INFO_SIZE         =$88;
 SELF_KEY_SIZE               =$10;
 SELF_DIGEST_SIZE            =$20;
 SELF_SEGMENT_BLOCK_ALIGNMENT=$10;

type
 p_self_header=^t_self_header;
 t_self_header=packed record
  Magic       :DWORD;       //Magic              4F 15 3D 1D
  Version     :Byte;        //0
  Mode        :Byte;        //1
  Endian      :Byte;        //1
  Attr        :Byte;        //
  Content_Type:Byte;        //Content Type       1 on Self, 4 on PUP Entry
  Program_Type:Byte;        //Program Type
  Padding     :Word;        //Padding
  Header_Size :Word;        //Header Size
  Meta_size   :Word;        //Signature Size     Metadata Size?
  File_size   :QWORD;       //Size of SELF
  Num_Segments:Word;        //Number of Segments
  Flags       :Word;        //
  reserved    :DWORD;       //
 end;

const
 SELF_PROPS_ORDERED       = $00000001;
 SELF_PROPS_ENCRYPTED     = $00000002;
 SELF_PROPS_SIGNED        = $00000004;
 SELF_PROPS_COMPRESSED    = $00000008;
 SELF_PROPS_WINDOW        = $00000700;
 SELF_PROPS_BLOCKED       = $00000800;
 SELF_PROPS_BLOCK_SIZE    = $0000F000;
 SELF_PROPS_HAS_DIGESTS   = $00010000;
 SELF_PROPS_HAS_EXTENTS   = $00020000;
 SELF_PROPS_SEGMENT_INDEX = $7FF00000;

 SELF_PROPS_WINDOW_OFFSET=8;
 SELF_PROPS_WINDOW_MASK  =7;

 SELF_PROPS_BLOCK_SIZE_OFFSET=12;
 SELF_PROPS_BLOCK_SIZE_MASK  =$F;

 SELF_PROPS_SEGMENT_INDEX_OFFSET=20;
 SELF_PROPS_SEGMENT_INDEX_MASK  =$7FF;

 SELF_PT_FAKE         =$1;
 SELF_PT_NPDRM_EXEC   =$4;
 SELF_PT_NPDRM_DYNLIB =$5;
 SELF_PT_SYSTEM_EXEC  =$8;
 SELF_PT_SYSTEM_DYNLIB=$9;
 SELF_PT_HOST_KERNEL  =$C;
 SELF_PT_SECURE_MODULE=$E;
 SELF_PT_SECURE_KERNEL=$F;

 SELF_CONTROL_BLOCK_TYPE_NPDRM = $3;

type
 p_self_segment=^t_self_segment;
 t_self_segment=packed record
  flags :QWORD;
  offset:QWORD;
  filesz:QWORD;
  memsz :QWORD;
 end;

 p_self_authinfo=^t_self_authinfo;
 t_self_authinfo=packed object
  AuthorityID    :QWORD;
  Program_Type   :QWORD;
  Program_Version:QWORD;
  System_Version :QWORD;
  Digest_SHA_256 :array[0..31] of Byte;
 end;

 p_self_authinfo_npdrm=^t_self_authinfo_npdrm;
 t_self_authinfo_npdrm=packed object(t_self_authinfo)
  Unknow         :array[0..15] of Byte;     //Program_Type = 0x04,0x05 (NPDRM_*)
  Content_ID     :array[0..31] of AnsiChar; //Program_Type = 0x04,0x05 (NPDRM_*)
 end;

 p_self_npdrm_control_block=^t_self_npdrm_control_block;
 t_self_npdrm_control_block=packed record
  pType    :Word;
  Unknown  :array[0..13] of byte;
  ContentID:array[0..18] of byte;
  RandomPad:array[0..12] of byte;
 end;

 p_eh_frame_hdr=^eh_frame_hdr;
 eh_frame_hdr=packed record
  version         :Byte;
  eh_frame_ptr_enc:Byte;
  fde_count_enc   :Byte;
  table_enc       :Byte;
  encoded:record end;
  //encoded eh_frame_ptr
  //encoded fde_count
 end;

const
 DW_EH_PE_omit   =$ff; // no data follows

 DW_EH_PE_absptr =$00;
 DW_EH_PE_pcrel	 =$10;
 DW_EH_PE_datarel=$30;

 DW_EH_PE_uleb128=$01;
 DW_EH_PE_udata2 =$02;
 DW_EH_PE_udata4 =$03;
 DW_EH_PE_udata8 =$04;
 DW_EH_PE_sleb128=$09;
 DW_EH_PE_sdata2 =$0A;
 DW_EH_PE_sdata4 =$0B;
 DW_EH_PE_sdata8 =$0C;

type
 TModuleValue=packed record
  case Byte of
   0:(value      :Int64);
   1:(name_offset:DWORD;
      version    :Word;
      id         :Word);
 end;

 TLibraryValue=packed record
  case Byte of
   0:(value      :Int64);
   1:(name_offset:DWORD;
      version    :Word;
      id         :Word);
 end;

 TLibraryAttr=packed record
  case Byte of
   0:(value:Int64);
   1:(attr :WORD;
      align:DWORD;
      id   :Word);
 end;

 PTLS_index=^TLS_index;
 TLS_index=packed record
  ti_moduleid :QWORD;
  ti_tlsoffset:QWORD;
 end;

 PPS4StartupParams=^TPS4StartupParams;
 TPS4StartupParams=packed record
  argc:Integer;
  align:Integer;
  argv:array[0..2] of Pointer;
  //envrion = argv + argc + 1
 end;

type
 t_user_malloc_init       =function():Integer;                              SysV_ABI_CDecl;
 t_user_malloc_finalize   =function():Integer;                              SysV_ABI_CDecl;
 t_user_malloc            =function(size:qword):Pointer;                    SysV_ABI_CDecl;
 t_user_free              =procedure(ptr:Pointer);                          SysV_ABI_CDecl;
 t_user_calloc            =function(nelem,count:qword):Pointer;             SysV_ABI_CDecl;
 t_user_realloc           =function(ptr:Pointer;size:qword):Pointer;        SysV_ABI_CDecl;
 t_user_memalign          =function(align,size:qword):Pointer;              SysV_ABI_CDecl;
 t_user_reallocalign      =function(ptr:Pointer;size,align:qword):Pointer;  SysV_ABI_CDecl;
 t_user_posix_memalign    =function(ptr:PPointer;align,size:qword):Integer; SysV_ABI_CDecl;
 t_user_malloc_stats      =function(mmsize:Pointer):Integer;                SysV_ABI_CDecl;
 t_user_malloc_stats_fast =function(mmsize:Pointer):Integer;                SysV_ABI_CDecl;
 t_user_malloc_usable_size=function(ptr:Pointer):qword;                     SysV_ABI_CDecl;

 PsceLibcMallocReplace=^TsceLibcMallocReplace;
 TsceLibcMallocReplace=packed record
  Size:QWORD;
  Unknown1:QWORD; //00000001
  user_malloc_init       :t_user_malloc_init;
  user_malloc_finalize   :t_user_malloc_finalize;
  user_malloc            :t_user_malloc;
  user_free              :t_user_free;
  user_calloc            :t_user_calloc;
  user_realloc           :t_user_realloc;
  user_memalign          :t_user_memalign;
  user_reallocalign      :t_user_reallocalign;
  user_posix_memalign    :t_user_posix_memalign;
  user_malloc_stats      :t_user_malloc_stats;
  user_malloc_stats_fast :t_user_malloc_stats_fast;
  user_malloc_usable_size:t_user_malloc_usable_size;
 end;

 t_user_new_1         =function(size:qword):Pointer;                    SysV_ABI_CDecl;
 t_user_new_2         =function(size:qword;throw:Pointer):Pointer;      SysV_ABI_CDecl;
 t_user_new_array_1   =function(size:qword):Pointer;                    SysV_ABI_CDecl;
 t_user_new_array_2   =function(size:qword;throw:Pointer):Pointer;      SysV_ABI_CDecl;
 t_user_delete_1      =procedure(ptr:Pointer);                          SysV_ABI_CDecl;
 t_user_delete_2      =procedure(ptr:Pointer;throw:Pointer);            SysV_ABI_CDecl;
 t_user_delete_array_1=procedure(ptr:Pointer);                          SysV_ABI_CDecl;
 t_user_delete_array_2=procedure(ptr:Pointer;throw:Pointer);            SysV_ABI_CDecl;
 t_user_delete_3      =procedure(ptr:Pointer;size:qword);               SysV_ABI_CDecl;
 t_user_delete_4      =procedure(ptr:Pointer;size:qword;throw:Pointer); SysV_ABI_CDecl;
 t_user_delete_array_3=procedure(ptr:Pointer;size:qword);               SysV_ABI_CDecl;
 t_user_delete_array_4=procedure(ptr:Pointer;size:qword;throw:Pointer); SysV_ABI_CDecl;

 PsceLibcNewReplace=^TsceLibcNewReplace;
 TsceLibcNewReplace=packed record
  Size:QWORD;
  Unknown1:QWORD; //00000002
  user_new_1         :t_user_new_1;
  user_new_2         :t_user_new_2;
  user_new_array_1   :t_user_new_array_1;
  user_new_array_2   :t_user_new_array_2;
  user_delete_1      :t_user_delete_1;
  user_delete_2      :t_user_delete_2;
  user_delete_array_1:t_user_delete_array_1;
  user_delete_array_2:t_user_delete_array_2;
  user_delete_3      :t_user_delete_3;
  user_delete_4      :t_user_delete_4;
  user_delete_array_3:t_user_delete_array_3;
  user_delete_array_4:t_user_delete_array_4;
 end;

 t_user_malloc_init_for_tls   =function():Integer;                              SysV_ABI_CDecl;
 t_user_malloc_fini_for_tls   =function():Integer;                              SysV_ABI_CDecl;
 t_user_malloc_for_tls        =function(size:qword):Pointer;                    SysV_ABI_CDecl;
 t_user_posix_memalign_for_tls=function(ptr:PPointer;align,size:qword):Integer; SysV_ABI_CDecl;
 t_user_free_for_tls          =procedure(ptr:Pointer);                          SysV_ABI_CDecl;

 PsceLibcMallocReplaceForTls=^TsceLibcMallocReplaceForTls;
 TsceLibcMallocReplaceForTls=packed record
  Size:QWORD;
  Unknown1:QWORD; //00000001
  user_malloc_init_for_tls   :t_user_malloc_init_for_tls;
  user_malloc_fini_for_tls   :t_user_malloc_fini_for_tls;
  user_malloc_for_tls        :t_user_malloc_for_tls;
  user_posix_memalign_for_tls:t_user_posix_memalign_for_tls;
  user_free_for_tls          :t_user_free_for_tls;
 end;

 PSceLibcParam=^TSceLibcParam;
 TSceLibcParam=packed record
  Size:QWORD;
  entry_count:DWORD;
  SceLibcInternalHeap              :DWORD; //1 //(entry_count > 1)
  sceLibcHeapSize                  :PDWORD;
  sceLibcHeapDelayedAlloc          :PDWORD;
  sceLibcHeapExtendedAlloc         :PDWORD;
  sceLibcHeapInitialSize           :PDWORD;
  _sceLibcMallocReplace            :PsceLibcMallocReplace;
  _sceLibcNewReplace               :PsceLibcNewReplace;
  sceLibcHeapHighAddressAlloc      :PQWORD;    //(entry_count > 2)
  Need_sceLibc                     :PDWORD;
  sceLibcHeapMemoryLock            :PQWORD;    //(entry_count > 4)
  sceKernelInternalMemorySize      :PQWORD;
  _sceLibcMallocReplaceForTls      :PsceLibcMallocReplaceForTls;
  //The maximum amount of the memory areas for the mspace. min:0x1000000
  sceLibcMaxSystemSize             :PQWORD;    //(entry_count > 7)
  sceLibcHeapDebugFlags            :PQWORD;    //(entry_count > 8)
  sceLibcStdThreadStackSize        :PDWORD;
  Unknown3:QWORD;
  sceKernelInternalMemoryDebugFlags:PDWORD;
  sceLibcWorkerThreadNum           :PDWORD;
  sceLibcWorkerThreadPriority      :PDWORD;
  sceLibcThreadUnnamedObjects      :PDWORD;
 end;

 PSceKernelMemParam=^TSceKernelMemParam;
 TSceKernelMemParam=packed record
  Size:QWORD;
  sceKernelExtendedPageTable   :PQWORD; //in bytes (virtual), MAX 64GB
  sceKernelFlexibleMemorySize  :PQWORD; //in bytes, MAX 448MB
  sceKernelExtendedMemory1     :PByte ; //bool (SCE_KERNEL_EXTENDED_DMEM_NEO_256)
  sceKernelExtendedGpuPageTable:PQWORD; //in bytes (virtual), MAX 64GB
  sceKernelExtendedMemory2     :PByte ; //bool (SCE_KERNEL_EXTENDED_DMEM_BASE_128)
  sceKernelExtendedCpuPageTable:PQWORD; //in bytes (virtual), MAX 64GB
 end;

 PSceKernelFsParam=^TSceKernelFsParam;
 TSceKernelFsParam=packed record
  Size:QWORD;
  sceKernelFsDupDent    :PDWORD;
  sceWorkspaceUpdateMode:Pointer;
  sceTraceAprNameMode   :Pointer;
 end;

 PSceProcParam=^TSceProcParam;
 TSceProcParam=packed record
  Size                      :QWORD; //0x50
  Magic                     :DWORD; //"ORBI" //0x4942524F
  Entry_count               :DWORD; //>=1
  SDK_version               :QWORD; //0x4508101
  sceProcessName            :PChar;
  sceUserMainThreadName     :PChar;
  sceUserMainThreadPriority :PDWORD;
  sceUserMainThreadStackSize:PDWORD;
  _sceLibcParam             :PSceLibcParam;
  _sceKernelMemParam        :PSceKernelMemParam;
  _sceKernelFsParam         :PSceKernelFsParam;
  sceProcessPreloadEnabled  :PDWORD;
  Unknown1                  :QWORD;
 end;

 PsceModuleParam=^TsceModuleParam;
 TsceModuleParam=packed record
  Size       :QWORD;
  Magic      :QWORD;
  SDK_version:QWORD;
 end;

function SELF_WINDOW(i:Int64):Integer; inline;
function SELF_BLOCK_SIZE(i:Int64):Int64; inline;
function SELF_SEGMENT_INDEX(i:Int64):Integer; inline;

function ELF64_R_SYM (i:QWORD):DWORD; inline;
function ELF64_R_TYPE(i:QWORD):DWORD; inline;
function ELF64_ST_BIND(i:Byte):Byte; inline;
function ELF64_ST_TYPE(i:Byte):Byte; inline;
function ELF64_ST_VISIBILITY(i:Byte):Byte; inline;

function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline;
function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline;
function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline;
function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline;

implementation

function SELF_WINDOW(i:Int64):Integer; inline;
begin
 Result:=(i shr SELF_PROPS_WINDOW_OFFSET) and SELF_PROPS_WINDOW_MASK;
end;

function SELF_BLOCK_SIZE(i:Int64):Int64; inline;
begin
 Result:=(i shr SELF_PROPS_BLOCK_SIZE_OFFSET) and SELF_PROPS_BLOCK_SIZE_MASK;
 Result:=QWORD(1) shl (Result+12)
end;

function SELF_SEGMENT_INDEX(i:Int64):Integer; inline;
begin
 Result:=(i shr SELF_PROPS_SEGMENT_INDEX_OFFSET) and SELF_PROPS_SEGMENT_INDEX_MASK;
end;

function ELF64_R_SYM(i:QWORD):DWORD; inline;
begin
 Result:=i shr 32;
end;

function ELF64_R_TYPE(i:QWORD):DWORD; inline;
begin
 Result:=i and $ffffffff;
end;

function ELF64_ST_BIND(i:Byte):Byte; inline;
begin
 Result:=i shr 4;
end;

function ELF64_ST_TYPE(i:Byte):Byte; inline;
begin
 Result:=i and $f;
end;

function ELF64_ST_VISIBILITY(i:Byte):Byte; inline;
begin
 Result:=i and 3;
end;

function AlignUp(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
var
 tmp:PtrUInt;
begin
 if (alignment=0) then Exit(addr);
 tmp:=addr+PtrUInt(alignment-1);
 Result:=tmp-(tmp mod alignment);
end;

function AlignUp(addr:Pointer;alignment:PtrUInt):Pointer; inline;
begin
 Result:=Pointer(Align(PtrUInt(addr),alignment));
end;

function AlignDw(addr:PtrUInt;alignment:PtrUInt):PtrUInt; inline;
begin
 Result:=addr-(addr mod alignment);
end;

function AlignDw(addr:Pointer;alignment:PtrUInt):Pointer; inline;
begin
 Result:=Pointer(AlignDw(PtrUInt(addr),alignment));
end;

function IsAlign(Addr:Pointer;Alignment:PtrUInt):Boolean; inline;
begin
 Result:=(PtrUInt(addr) mod alignment)=0;
end;

function IsAlign(Addr:PtrUInt;Alignment:PtrUInt):Boolean; inline;
begin
 Result:=(addr mod alignment)=0;
end;

end.

