about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-08-17 14:25:04 +0200
committerptitSeb <sebastien.chev@gmail.com>2024-08-17 14:25:04 +0200
commitd47b1b0e5679652e6b5fb5fd4cee52b775229a63 (patch)
tree46f331bed24c7b7212fb7005c162d324a6956d23 /src
parentfa87b0fcef3dff593a507b3200ef83d846101d64 (diff)
downloadbox64-d47b1b0e5679652e6b5fb5fd4cee52b775229a63.tar.gz
box64-d47b1b0e5679652e6b5fb5fd4cee52b775229a63.zip
[BOX32] Added 32bits elf header parser and dumper
Diffstat (limited to 'src')
-rw-r--r--src/elfs/elfhash.c35
-rw-r--r--src/elfs/elfload_dump.c44
-rwxr-xr-xsrc/elfs/elfload_dump32.c352
-rw-r--r--src/elfs/elfloader.c2
-rw-r--r--src/elfs/elfloader_private.h1
-rw-r--r--src/elfs/elfparser.c3
-rwxr-xr-xsrc/elfs/elfparser32.c466
-rw-r--r--src/elfs/elfparser64.c406
-rw-r--r--src/include/elfload_dump.h9
9 files changed, 901 insertions, 417 deletions
diff --git a/src/elfs/elfhash.c b/src/elfs/elfhash.c
index 61d1af65..a20c31d9 100644
--- a/src/elfs/elfhash.c
+++ b/src/elfs/elfhash.c
@@ -18,7 +18,12 @@
 #include "elfload_dump.h"
 #include "elfloader_private.h"
 
-const char* GetSymbolVersion32(elfheader_t* h, int version) { /* TODO */ return NULL; }
+const char* GetSymbolVersion32(elfheader_t* h, int version)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
 const char* GetSymbolVersion64(elfheader_t* h, int version)
 {
     if(version<2)
@@ -44,7 +49,12 @@ const char* GetSymbolVersion(elfheader_t* h, int version)
     return box64_is32bits?GetSymbolVersion32(h, version):GetSymbolVersion64(h, version);
 }
 
-const char* GetParentSymbolVersion32(elfheader_t* h, int index) { /* TODO */ return NULL; }
+const char* GetParentSymbolVersion32(elfheader_t* h, int index)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
 const char* GetParentSymbolVersion64(elfheader_t* h, int index)
 {
     if(!h->VerDef._64 || (index<1))
@@ -111,7 +121,12 @@ uint16_t GetSymbolVersionFlag(elfheader_t* h, int index) {
 }
 
 
-int GetVersionIndice32(elfheader_t* h, const char* vername) { /* TODO */ return 0; }
+int GetVersionIndice32(elfheader_t* h, const char* vername)
+#ifndef BOX32
+{ return 0; }
+#else
+ ;
+#endif
 int GetVersionIndice64(elfheader_t* h, const char* vername)
 {
     if(!vername)
@@ -132,7 +147,12 @@ int GetVersionIndice(elfheader_t* h, const char* vername)
     return box64_is32bits?GetVersionIndice32(h, vername):GetVersionIndice64(h, vername);
 }
 
-int GetNeededVersionCnt32(elfheader_t* h, const char* libname) { /* TODO */ return 0; }
+int GetNeededVersionCnt32(elfheader_t* h, const char* libname)
+#ifndef BOX32
+{ return 0; }
+#else
+ ;
+#endif
 int GetNeededVersionCnt64(elfheader_t* h, const char* libname)
 {
     if(!libname)
@@ -153,7 +173,12 @@ int GetNeededVersionCnt(elfheader_t* h, const char* libname)
     return box64_is32bits?GetNeededVersionCnt32(h, libname):GetNeededVersionCnt64(h, libname);
 }
 
-const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx) { /* TODO */ return NULL; }
+const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx)
+#ifndef BOX32
+{ return NULL; }
+#else
+ ;
+#endif
 const char* GetNeededVersionString64(elfheader_t* h, const char* libname, int idx)
 {
     if(!libname)
diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c
index 5c5f349a..18d4dbc6 100644
--- a/src/elfs/elfload_dump.c
+++ b/src/elfs/elfload_dump.c
@@ -174,7 +174,9 @@ static const char* DumpPHEntry(Elf64_Phdr *e)
     }
     return buff;
 }
-
+#ifndef BOX32
+const char* DumpRelType32(int t) { return NULL; }
+#endif
 const char* DumpRelType64(int t)
 {
     static char buff[50];
@@ -241,6 +243,9 @@ static const char* DumpSym(elfheader_t *h, Elf64_Sym* sym, int version)
     return buff;
 }
 
+#ifndef BOX32
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym) { return NULL; }
+#endif
 const char* SymName64(elfheader_t *h, Elf64_Sym* sym)
 {
     return h->DynStr+sym->st_name;
@@ -250,6 +255,9 @@ static const char* IdxSymName(elfheader_t *h, int sym)
     return h->DynStr+h->DynSym._64[sym].st_name;
 }
 
+#ifndef BOX32
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h) { }
+#endif
 void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h)
 {
     if(box64_dump) {
@@ -275,7 +283,9 @@ void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h)
         printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
     }
 }
-
+#ifndef BOX32
+void DumpSymTab32(elfheader_t *h) { }
+#endif
 void DumpSymTab64(elfheader_t *h)
 {
     if(box64_dump && h->SymTab._64) {
@@ -289,6 +299,9 @@ void DumpSymTab64(elfheader_t *h)
     }
 }
 
+#ifndef BOX32
+void DumpDynamicSections32(elfheader_t *h) { }
+#endif
 void DumpDynamicSections64(elfheader_t *h)
 {
     if(box64_dump && h->Dynamic._64) {
@@ -299,6 +312,9 @@ void DumpDynamicSections64(elfheader_t *h)
     }
 }
 
+#ifndef BOX32
+void DumpDynSym32(elfheader_t *h) { }
+#endif
 void DumpDynSym64(elfheader_t *h)
 {
     if(box64_dump && h->DynSym._64) {
@@ -312,7 +328,12 @@ void DumpDynSym64(elfheader_t *h)
     }
 }
 
-void DumpDynamicNeeded32(elfheader_t *h) { /* TODO */}
+void DumpDynamicNeeded32(elfheader_t *h)
+#ifndef BOX32
+ {  }
+#else
+ ;
+#endif
 void DumpDynamicNeeded(elfheader_t *h)
 {
     if(box64_is32bits)
@@ -328,7 +349,12 @@ void DumpDynamicNeeded(elfheader_t *h)
         }
 }
 
-void DumpDynamicRPath32(elfheader_t *h) { /* TODO */}
+void DumpDynamicRPath32(elfheader_t *h) 
+#ifndef BOX32
+{  }
+#else
+ ;
+#endif
 void DumpDynamicRPath(elfheader_t *h)
 {
     if(box64_is32bits)
@@ -348,6 +374,9 @@ void DumpDynamicRPath(elfheader_t *h)
         }
 }
 
+#ifndef BOX32
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name) { }
+#endif
 void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
 {
     if(box64_dump) {
@@ -360,7 +389,9 @@ void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name)
         printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
     }
 }
-
+#ifndef BOX32
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name) { }
+#endif
 void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
 {
     if(box64_dump && h->rela) {
@@ -375,6 +406,9 @@ void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name
     }
 }
 
+#ifndef BOX32
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name) { }
+#endif
 void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name)
 {
     if(box64_dump && h->relr) {
diff --git a/src/elfs/elfload_dump32.c b/src/elfs/elfload_dump32.c
new file mode 100755
index 00000000..b6d8df41
--- /dev/null
+++ b/src/elfs/elfload_dump32.c
@@ -0,0 +1,352 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "box32.h"
+
+static const char* DumpSection(Elf32_Shdr *s, char* SST) {
+    static char buff[400];
+    switch (s->sh_type) {
+        case SHT_NULL:
+            return "SHT_NULL";
+        #define GO(A) \
+        case A:     \
+            sprintf(buff, #A " Name=\"%s\"(%d) off=0x%X, size=%d, attr=0x%04X, addr=%p(%02X), link/info=%d/%d", \
+                SST+s->sh_name, s->sh_name, s->sh_offset, s->sh_size, s->sh_flags, from_ptrv(s->sh_addr), s->sh_addralign, s->sh_link, s->sh_info); \
+            break
+        GO(SHT_PROGBITS);
+        GO(SHT_SYMTAB);
+        GO(SHT_STRTAB);
+        GO(SHT_RELA);
+        GO(SHT_HASH);
+        GO(SHT_DYNAMIC);
+        GO(SHT_NOTE);
+        GO(SHT_NOBITS);
+        GO(SHT_REL);
+        GO(SHT_SHLIB);
+        GO(SHT_DYNSYM);
+        GO(SHT_INIT_ARRAY);
+        GO(SHT_FINI_ARRAY);
+        GO(SHT_PREINIT_ARRAY);
+        GO(SHT_GROUP);
+        GO(SHT_SYMTAB_SHNDX);
+        GO(SHT_NUM);
+        GO(SHT_LOPROC);
+        GO(SHT_HIPROC);
+        GO(SHT_LOUSER);
+        GO(SHT_HIUSER);
+        #if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
+        GO(SHT_GNU_versym);
+        GO(SHT_GNU_ATTRIBUTES);
+        GO(SHT_GNU_HASH);
+        GO(SHT_GNU_LIBLIST);
+        GO(SHT_CHECKSUM);
+        GO(SHT_LOSUNW);
+        //GO(SHT_SUNW_move);
+        GO(SHT_SUNW_COMDAT);
+        GO(SHT_SUNW_syminfo);
+        GO(SHT_GNU_verdef);
+        GO(SHT_GNU_verneed);
+        #endif
+        #undef GO
+        default:
+            sprintf(buff, "0x%X unknown type", s->sh_type);
+    }
+    return buff;
+}
+
+static const char* DumpDynamic(Elf32_Dyn *s) {
+    static char buff[200];
+    switch (s->d_tag) {
+        case DT_NULL:
+            return "DT_NULL: End Dynamic Section";
+        #define GO(A, Add) \
+        case A:     \
+            sprintf(buff, #A " %s=0x%X", (Add)?"Addr":"Val", (Add)?s->d_un.d_ptr:s->d_un.d_val); \
+            break
+            GO(DT_NEEDED, 0);
+            GO(DT_PLTRELSZ, 0);
+            GO(DT_PLTGOT, 1);
+            GO(DT_HASH, 1);
+            GO(DT_STRTAB, 1);
+            GO(DT_SYMTAB, 1);
+            GO(DT_RELA, 1);
+            GO(DT_RELASZ, 0);
+            GO(DT_RELAENT, 0);
+            GO(DT_STRSZ, 0);
+            GO(DT_SYMENT, 0);
+            GO(DT_INIT, 1);
+            GO(DT_FINI, 1);
+            GO(DT_SONAME, 0);
+            GO(DT_RPATH, 0);
+            GO(DT_SYMBOLIC, 0);
+            GO(DT_REL, 1);
+            GO(DT_RELSZ, 0);
+            GO(DT_RELENT, 0);
+            GO(DT_PLTREL, 0);
+            GO(DT_DEBUG, 0);
+            GO(DT_TEXTREL, 0);
+            GO(DT_JMPREL, 1);
+            GO(DT_BIND_NOW, 1);
+            GO(DT_INIT_ARRAY, 1);
+            GO(DT_FINI_ARRAY, 1);
+            GO(DT_INIT_ARRAYSZ, 0);
+            GO(DT_FINI_ARRAYSZ, 0);
+            GO(DT_RUNPATH, 0);
+            GO(DT_FLAGS, 0);
+            GO(DT_ENCODING, 0);
+            #if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
+            GO(DT_NUM, 0);
+            GO(DT_VALRNGLO, 0);
+            GO(DT_GNU_PRELINKED, 0);
+            GO(DT_GNU_CONFLICTSZ, 0);
+            GO(DT_GNU_LIBLISTSZ, 0);
+            GO(DT_CHECKSUM, 0);
+            GO(DT_PLTPADSZ, 0);
+            GO(DT_MOVEENT, 0);
+            GO(DT_MOVESZ, 0);
+            GO(DT_FEATURE_1, 0);
+            GO(DT_POSFLAG_1, 0);
+            GO(DT_SYMINSZ, 0);
+            GO(DT_SYMINENT, 0);
+            GO(DT_ADDRRNGLO, 0);
+            GO(DT_GNU_HASH, 0);
+            GO(DT_TLSDESC_PLT, 0);
+            GO(DT_TLSDESC_GOT, 0);
+            GO(DT_GNU_CONFLICT, 0);
+            GO(DT_GNU_LIBLIST, 0);
+            GO(DT_CONFIG, 0);
+            GO(DT_DEPAUDIT, 0);
+            GO(DT_AUDIT, 0);
+            GO(DT_PLTPAD, 0);
+            GO(DT_MOVETAB, 0);
+            GO(DT_SYMINFO, 0);
+            GO(DT_VERSYM, 0);
+            GO(DT_RELACOUNT, 0);
+            GO(DT_RELCOUNT, 0);
+            GO(DT_FLAGS_1, 0);
+            GO(DT_VERDEF, 0);
+            GO(DT_VERDEFNUM, 0);
+            GO(DT_VERNEED, 0);
+            GO(DT_VERNEEDNUM, 0);
+            GO(DT_AUXILIARY, 0);
+            GO(DT_FILTER, 0);
+            #endif
+        #undef GO
+        default:
+            sprintf(buff, "0x%X unknown type", s->d_tag);
+    }
+    return buff;
+}
+
+static const char* DumpPHEntry(Elf32_Phdr *e)
+{
+    static char buff[500];
+    memset(buff, 0, sizeof(buff));
+    switch(e->p_type) {
+        case PT_NULL: sprintf(buff, "type: %s", "PT_NULL"); break;
+        #define GO(T) case T: sprintf(buff, "type: %s, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", #T, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break
+        GO(PT_LOAD);
+        GO(PT_DYNAMIC);
+        GO(PT_INTERP);
+        GO(PT_NOTE);
+        GO(PT_SHLIB);
+        GO(PT_PHDR);
+        GO(PT_TLS);
+        #ifdef PT_NUM
+        GO(PT_NUM);
+        GO(PT_LOOS);
+        GO(PT_GNU_EH_FRAME);
+        GO(PT_GNU_STACK);
+        GO(PT_GNU_RELRO);
+        #endif
+        #undef GO
+        default: sprintf(buff, "type: %x, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", e->p_type, e->p_offset, from_ptrv(e->p_vaddr), from_ptrv(e->p_paddr), e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break;
+    }
+    return buff;
+}
+
+const char* DumpRelType32(int t)
+{
+    static char buff[50];
+    memset(buff, 0, sizeof(buff));
+    switch(t) {
+        #define GO(T) case T: sprintf(buff, "type: %s", #T); break
+        GO(R_386_NONE);
+        GO(R_386_32);
+        GO(R_386_PC32);
+        GO(R_386_GOT32);
+        GO(R_386_PLT32);
+        GO(R_386_COPY);
+        GO(R_386_GLOB_DAT);
+        GO(R_386_JMP_SLOT);
+        GO(R_386_RELATIVE);
+        GO(R_386_GOTOFF);
+        GO(R_386_GOTPC);
+        GO(R_386_PC8);
+        GO(R_386_TLS_TPOFF);
+        GO(R_386_TLS_GD_32);
+        GO(R_386_TLS_DTPMOD32);
+        GO(R_386_TLS_DTPOFF32);
+        GO(R_386_TLS_TPOFF32);
+        #undef GO
+        default: sprintf(buff, "type: 0x%x (unknown)", t); break;
+    }
+    return buff;
+}
+
+static const char* DumpSym(elfheader_t *h, Elf32_Sym* sym, int version)
+{
+    static char buff[4096];
+    const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
+    memset(buff, 0, sizeof(buff));
+    sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d (ver=%d/%s)", 
+        h->DynStr+sym->st_name, from_ptrv(sym->st_value), sym->st_size,
+        sym->st_info, sym->st_other, sym->st_shndx, version, vername);
+    return buff;
+}
+
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym)
+{
+    return h->DynStr+sym->st_name;
+}
+static const char* IdxSymName(elfheader_t *h, int sym)
+{
+    return h->DynStr+h->DynSym._32[sym].st_name;
+}
+
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h)
+{
+    if(box64_dump) {
+        printf_dump(LOG_NEVER, "ELF Dump main header\n");
+        printf_dump(LOG_NEVER, "  Entry point = %p\n", from_ptrv(header->e_entry));
+        printf_dump(LOG_NEVER, "  Program Header table offset = %p\n", from_ptrv(header->e_phoff));
+        printf_dump(LOG_NEVER, "  Section Header table offset = %p\n", from_ptrv(header->e_shoff));
+        printf_dump(LOG_NEVER, "  Flags = 0x%X\n", header->e_flags);
+        printf_dump(LOG_NEVER, "  ELF Header size = %d\n", header->e_ehsize);
+        printf_dump(LOG_NEVER, "  Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
+        printf_dump(LOG_NEVER, "  Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
+        printf_dump(LOG_NEVER, "  Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
+        printf_dump(LOG_NEVER, "ELF Dump ==========\n");
+
+        printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries);
+        for (int i=0; i<h->numPHEntries; ++i)
+            printf_dump(LOG_NEVER, "  PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries._32+i));
+        printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
+
+        printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries);
+        for (int i=0; i<h->numSHEntries; ++i)
+            printf_dump(LOG_NEVER, "  Section %04d : %s\n", i, DumpSection(h->SHEntries._32+i, h->SHStrTab));
+        printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
+    }
+}
+
+void DumpSymTab32(elfheader_t *h)
+{
+    if(box64_dump && h->SymTab._32) {
+        const char* name = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab);
+        for (int i=0; i<h->numSymTab; ++i)
+            printf_dump(LOG_NEVER, "  %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name, 
+                i, h->StrTab+h->SymTab._32[i].st_name, from_ptrv(h->SymTab._32[i].st_value), h->SymTab._32[i].st_size,
+                h->SymTab._32[i].st_info, h->SymTab._32[i].st_other, h->SymTab._32[i].st_shndx);
+        printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
+    }
+}
+
+void DumpDynamicSections32(elfheader_t *h)
+{
+    if(box64_dump && h->Dynamic._32) {
+        printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
+        for (int i=0; i<h->numDynamic; ++i)
+            printf_dump(LOG_NEVER, "  Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic._32+i));
+        printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
+    }
+}
+
+void DumpDynSym32(elfheader_t *h)
+{
+    if(box64_dump && h->DynSym._32) {
+        const char* name = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym);
+        for (int i=0; i<h->numDynSym; ++i) {
+            int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
+            printf_dump(LOG_NEVER, "  %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym._32+i, version));
+        }
+        printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
+    }
+}
+
+void DumpDynamicNeeded32(elfheader_t *h)
+{
+    if(box64_dump && h->DynStrTab) {
+        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+        for (int i=0; i<h->numDynamic; ++i)
+            if(h->Dynamic._32[i].d_tag==DT_NEEDED) {
+                printf_dump(LOG_NEVER, "  Needed : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+        printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
+    }
+}
+
+void DumpDynamicRPath32(elfheader_t *h)
+{
+    if(box64_dump && h->DynStrTab) {
+        printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
+        for (int i=0; i<h->numDynamic; ++i) {
+            if(h->Dynamic._32[i].d_tag==DT_RPATH) {
+                printf_dump(LOG_NEVER, "   RPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+            if(h->Dynamic._32[i].d_tag==DT_RUNPATH) {
+                printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic._32[i].d_un.d_val + h->delta);
+            }
+        }
+        printf_dump(LOG_NEVER, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
+    }
+}
+
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name)
+{
+    if(box64_dump) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
+                i, from_ptrv(rel[i].r_offset), rel[i].r_info, DumpRelType32(ELF32_R_TYPE(rel[i].r_info)), 
+                ELF32_R_SYM(rel[i].r_info), IdxSymName(h, ELF32_R_SYM(rel[i].r_info)));
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name)
+{
+    if(box64_dump && h->rela) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
+                i, from_ptrv(rela[i].r_offset), rela[i].r_info, DumpRelType32(ELF32_R_TYPE(rela[i].r_info)), 
+                ELF32_R_SYM(rela[i].r_info), IdxSymName(h, ELF32_R_SYM(rela[i].r_info)), 
+                rela[i].r_addend);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char* name)
+{
+    if(box64_dump && h->relr) {
+        const char* elfname = ElfName(h);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, relr);
+        for (int i = 0; i<cnt; ++i)
+            printf_dump(LOG_NEVER, "  %s:%s[%d] = %p\n", elfname, name,
+                i, from_ptrv(relr[i]));
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index 20fa13c0..beeacbfb 100644
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -55,7 +55,7 @@ int getElfIndex(box64context_t* ctx, elfheader_t* head) {
 
 elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
 {
-    elfheader_t *h = ParseElfHeader64(f, name, exec);
+    elfheader_t *h = box64_is32bits?ParseElfHeader32(f, name, exec):ParseElfHeader64(f, name, exec);
     if(!h)
         return NULL;
 
diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h
index d881149a..3743ce25 100644
--- a/src/elfs/elfloader_private.h
+++ b/src/elfs/elfloader_private.h
@@ -198,6 +198,7 @@ typedef struct elfheader_s {
 #define ELF64_ST_VISIBILITY(o)   ((o) & 0x03)
 #endif
 
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec);
 elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec);
 
 const char* BindSym(int bind);
diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c
index 8f51e8c3..c9919123 100644
--- a/src/elfs/elfparser.c
+++ b/src/elfs/elfparser.c
@@ -61,6 +61,9 @@ static void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, c
     }
 }
 
+#ifndef BOX32
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec) { return NULL; }
+#endif
 elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec)
 {
     Elf64_Ehdr header;
diff --git a/src/elfs/elfparser32.c b/src/elfs/elfparser32.c
new file mode 100755
index 00000000..b4bb78e4
--- /dev/null
+++ b/src/elfs/elfparser32.c
@@ -0,0 +1,466 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <elf.h>
+
+#include "box64version.h"
+#include "elfloader.h"
+#include "debug.h"
+#include "elfload_dump.h"
+#include "elfloader_private.h"
+#include "box32.h"
+
+#ifndef PN_XNUM 
+#define PN_XNUM (0xffff)
+#endif
+
+static int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
+{
+    if(type && (s->sh_type != type)) {
+        printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
+        return -1;
+    }
+    if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf32_Sym)) {
+        printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
+    }
+    *SH = box_calloc(1, s->sh_size);
+    fseeko64(f, s->sh_offset ,SEEK_SET);
+    if(fread(*SH, s->sh_size, 1, f)!=1) {
+            printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
+            return -1;
+    }
+
+    return 0;
+}
+
+static int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
+{
+    for (int i=0; i<n; ++i) {
+        if(s[i].sh_type!=SHT_NULL)
+            if(!strcmp(SHStrTab+s[i].sh_name, name))
+                return i;
+    }
+    return 0;
+}
+
+static void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
+{
+    int n = FindSection(s, size, SHStrTab, name);
+    printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
+    if(n)
+        LoadSH(f, s+n, what, name, type);
+    if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
+        if(*what && num)
+            *num = s[n].sh_size / sizeof(Elf32_Sym);
+    } else if(type==SHT_DYNAMIC) {
+        if(*what && num)
+            *num = s[n].sh_size / sizeof(Elf32_Dyn);
+    }
+}
+
+elfheader_t* ParseElfHeader32(FILE* f, const char* name, int exec)
+{
+    Elf32_Ehdr header;
+    int level = (exec)?LOG_INFO:LOG_DEBUG;
+    if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
+        printf_log(level, "Cannot read ELF Header\n");
+        return NULL;
+    }
+    if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
+        printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
+        return NULL;
+    }
+    if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
+        if(header.e_ident[EI_CLASS]==ELFCLASS64) {
+            printf_log(LOG_INFO, "This is a 64bits ELF! box32 can only run 32bits ELF!\n");
+        } else {
+            printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
+        }
+        return NULL;
+    }
+    if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
+        printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
+        return NULL;
+    }
+    if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
+        printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
+        return NULL;
+    }
+    if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) {
+        printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
+        return NULL;
+    }
+
+    if(header.e_type != ET_EXEC && header.e_type != ET_DYN) {
+        printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
+        return NULL;
+    }
+
+    if(header.e_machine != EM_386) {
+        printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
+        return NULL;
+    }
+
+    if(header.e_entry == 0 && exec) {
+        printf_log(LOG_INFO, "No entry point in ELF\n");
+        return NULL;
+    }
+    if(header.e_phentsize != sizeof(Elf32_Phdr)) {
+        printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %ld)\n", header.e_phentsize, sizeof(Elf32_Phdr));
+        return NULL;
+    }
+    if(header.e_shentsize != sizeof(Elf32_Shdr) && header.e_shentsize != 0) {
+        printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %ld)\n", header.e_shentsize, sizeof(Elf32_Shdr));
+        return NULL;
+    }
+
+    elfheader_t *h = box_calloc(1, sizeof(elfheader_t));
+    h->name = box_strdup(name);
+    h->entrypoint = header.e_entry;
+    h->numPHEntries = header.e_phnum;
+    h->numSHEntries = header.e_shnum;
+    h->SHIdx = header.e_shstrndx;
+    h->e_type = header.e_type;
+    if(header.e_shentsize && header.e_shnum) {
+        // special cases for nums
+        if(h->numSHEntries == 0) {
+            printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
+            // read 1st section header and grab actual number from here
+            fseeko64(f, header.e_shoff, SEEK_SET);
+            Elf32_Shdr section;
+            if(fread(&section, sizeof(Elf32_Shdr), 1, f)!=1) {
+                box_free(h);
+                printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
+                return NULL;
+            }
+            h->numSHEntries = section.sh_size;
+        }
+        // now read all section headers
+        printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
+        h->SHEntries._32 = (Elf32_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf32_Shdr));
+        fseeko64(f, header.e_shoff ,SEEK_SET);
+        if(fread(h->SHEntries._32, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
+                FreeElfHeader(&h);
+                printf_log(LOG_INFO, "Cannot read all Section Header\n");
+                return NULL;
+        }
+
+        if(h->numPHEntries == PN_XNUM) {
+            printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
+            // read 1st section header and grab actual number from here
+            h->numPHEntries = h->SHEntries._32[0].sh_info;
+        }
+    }
+
+    printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
+    h->PHEntries._32 = (Elf32_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf32_Phdr));
+    fseeko64(f, header.e_phoff ,SEEK_SET);
+    if(fread(h->PHEntries._32, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
+            FreeElfHeader(&h);
+            printf_log(LOG_INFO, "Cannot read all Program Header\n");
+            return NULL;
+    }
+
+    if(header.e_shentsize && header.e_shnum) {
+        if(h->SHIdx == SHN_XINDEX) {
+            printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
+            h->SHIdx = h->SHEntries._32[0].sh_link;
+        }
+        if(h->SHIdx > h->numSHEntries) {
+            printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
+            FreeElfHeader(&h);
+            return NULL;
+        }
+        // load Section table
+        printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
+        if(LoadSH(f, h->SHEntries._32+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
+            FreeElfHeader(&h);
+            return NULL;
+        }
+        if(box64_dump) DumpMainHeader32(&header, h);
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab._32, &h->numSymTab);
+        if(box64_dump && h->SymTab._32) DumpSymTab32(h);
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic._32, &h->numDynamic);
+        if(box64_dump && h->Dynamic._32) DumpDynamicSections32(h);
+        // grab DT_REL & DT_RELA stuffs
+        // also grab the DT_STRTAB string table
+        {
+            for (int i=0; i<h->numDynamic; ++i) {
+                Elf32_Dyn d = h->Dynamic._32[i];
+                Elf32_Word val = d.d_un.d_val;
+                Elf32_Addr ptr = d.d_un.d_ptr;
+                switch (d.d_tag) {
+                case DT_REL:
+                    h->rel = ptr;
+                    break;
+                case DT_RELSZ:
+                    h->relsz = val;
+                    break;
+                case DT_RELENT:
+                    h->relent = val;
+                    break;
+                case DT_RELA:
+                    h->rela = ptr;
+                    break;
+                case DT_RELASZ:
+                    h->relasz = val;
+                    break;
+                case DT_RELAENT:
+                    h->relaent = val;
+                    break;
+                case DT_RELR:
+                    h->relr = ptr;
+                    break;
+                case DT_RELRSZ:
+                    h->relrsz = val;
+                    break;
+                case DT_RELRENT:
+                    h->relrent = val;
+                    break;
+                case DT_PLTGOT:
+                    h->pltgot = ptr;
+                    break;
+                case DT_PLTREL:
+                    h->pltrel = val;
+                    break;
+                case DT_PLTRELSZ:
+                    h->pltsz = val;
+                    break;
+                case DT_JMPREL:
+                    h->jmprel = ptr;
+                    break;
+                case DT_STRTAB:
+                    h->DynStrTab = (char *)from_ptr(ptr);
+                    break;
+                case DT_STRSZ:
+                    h->szDynStrTab = val;
+                    break;
+                case DT_INIT: // Entry point
+                    h->initentry = ptr;
+                    printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", from_ptrv(h->initentry));
+                    break;
+                case DT_INIT_ARRAY:
+                    h->initarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", from_ptrv(h->initarray));
+                    break;
+                case DT_INIT_ARRAYSZ:
+                    h->initarray_sz = val / sizeof(Elf32_Addr);
+                    printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
+                    break;
+                case DT_PREINIT_ARRAYSZ:
+                    if(val)
+                        printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
+                    break;
+                case DT_FINI: // Exit hook
+                    h->finientry = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", from_ptrv(h->finientry));
+                    break;
+                case DT_FINI_ARRAY:
+                    h->finiarray = ptr;
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", from_ptrv(h->finiarray));
+                    break;
+                case DT_FINI_ARRAYSZ:
+                    h->finiarray_sz = val / sizeof(Elf32_Addr);
+                    printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
+                    break;
+                case DT_VERNEEDNUM:
+                    h->szVerNeed = val;
+                    printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
+                    break;
+                case DT_VERNEED:
+                    h->VerNeed._32 = (Elf32_Verneed*)from_ptr(ptr);
+                    printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
+                    break;
+                case DT_VERDEFNUM:
+                    h->szVerDef = val;
+                    printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
+                    break;
+                case DT_VERDEF:
+                    h->VerDef._32 = (Elf32_Verdef*)from_ptr(ptr);
+                    printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
+                    break;
+                case DT_HASH:
+                    h->hash = ptr;
+                    printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash);
+                    break;
+                case DT_GNU_HASH:
+                    h->gnu_hash = ptr;
+                    printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash);
+                    break;
+                }
+            }
+            if(h->rel) {
+                if(h->relent != sizeof(Elf32_Rel)) {
+                    printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%lx)\n", h->relent, sizeof(Elf32_Rel));
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", from_ptrv(h->rel), h->relsz, h->relent);
+            }
+            if(h->rela) {
+                if(h->relaent != sizeof(Elf32_Rela)) {
+                    printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%lx)\n", h->relaent, sizeof(Elf32_Rela));
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", from_ptrv(h->rela), h->relasz, h->relaent);
+            }
+            if(h->jmprel) {
+                if(h->pltrel == DT_REL) {
+                    h->pltent = sizeof(Elf32_Rel);
+                } else if(h->pltrel == DT_RELA) {
+                    h->pltent = sizeof(Elf32_Rela);
+                } else {
+                    printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
+                    printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
+                    FreeElfHeader(&h);
+                    return NULL;
+                }
+                printf_log(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", from_ptrv(h->jmprel), h->pltrel, h->pltsz, h->pltent);
+            }
+            if(h->DynStrTab && h->szDynStrTab) {
+                //DumpDynamicNeeded32(h); cannot dump now, it's not loaded yet
+            }
+        }
+        // look for PLT Offset
+        int ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got.plt");
+        if(ii) {
+            h->gotplt = h->SHEntries._32[ii].sh_addr;
+            h->gotplt_end = h->gotplt + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", from_ptrv(h->gotplt));
+        }
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".got");
+        if(ii) {
+            h->got = h->SHEntries._32[ii].sh_addr;
+            h->got_end = h->got + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", from_ptrv(h->got), from_ptrv(h->got_end));
+        }
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".plt");
+        if(ii) {
+            h->plt = h->SHEntries._32[ii].sh_addr;
+            h->plt_end = h->plt + h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", from_ptrv(h->plt), from_ptrv(h->plt_end));
+        }
+        // grab version of symbols
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".gnu.version");
+        if(ii) {
+            h->VerSym = (Elf32_Half*)from_ptrv(h->SHEntries._32[ii].sh_addr);
+            printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
+        }
+        // grab .text for main code
+        ii = FindSection(h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".text");
+        if(ii) {
+            h->text = (uintptr_t)(h->SHEntries._32[ii].sh_addr);
+            h->textsz = h->SHEntries._32[ii].sh_size;
+            printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", from_ptrv(h->text), h->textsz);
+        }
+
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
+        LoadNamedSection(f, h->SHEntries._32, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
+    }
+    
+    return h;
+}
+
+const char* GetParentSymbolVersion32(elfheader_t* h, int index)
+{
+    if(!h->VerDef._32 || (index<1))
+        return NULL;
+    Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta);
+    while(def) {
+        if(def->vd_ndx==index) {
+            if(def->vd_cnt<1)
+                return NULL;
+            /*if(def->vd_flags&VER_FLG_BASE)
+                return NULL;*/
+            Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
+            return h->DynStr+aux->vda_name; // return Parent, so 1st aux
+        }
+        def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
+    }
+    return NULL;
+}
+
+const char* GetSymbolVersion32(elfheader_t* h, int version)
+{
+    version&=0x7fff;    // remove bit15 that switch between hidden/public
+    if(!h->VerNeed._32 || (version<2))
+        return NULL;
+    /*if(version==1)
+        return "*";*/
+    Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+    while(ver) {
+        Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+        for(int j=0; j<ver->vn_cnt; ++j) {
+            if(aux->vna_other==version)
+                return h->DynStr+aux->vna_name;
+            aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
+        }
+        ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+    }
+    return GetParentSymbolVersion32(h, version);  // if symbol is "internal", use Def table instead
+}
+
+int GetVersionIndice32(elfheader_t* h, const char* vername)
+{
+    if(!vername)
+        return 0;
+    if(h->VerDef._32) {
+        Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef._32 + h->delta);
+        while(def) {
+            Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
+            if(!strcmp(h->DynStr+aux->vda_name, vername))
+                return def->vd_ndx;
+            def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
+        }
+    }
+    return 0;
+}
+
+int GetNeededVersionCnt32(elfheader_t* h, const char* libname)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed._32) {
+        Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname))
+                return ver->vn_cnt;
+            ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return 0;
+}
+
+const char* GetNeededVersionString32(elfheader_t* h, const char* libname, int idx)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed._32) {
+        Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed._32 + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname)) {
+                for(int j=0; j<ver->vn_cnt; ++j) {
+                    if(j==idx) 
+                        return h->DynStr+aux->vna_name;
+                    aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
+                }
+                return NULL;    // idx out of bound, return NULL...
+           }
+            ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return NULL;
+}
diff --git a/src/elfs/elfparser64.c b/src/elfs/elfparser64.c
deleted file mode 100644
index e496ca8b..00000000
--- a/src/elfs/elfparser64.c
+++ /dev/null
@@ -1,406 +0,0 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <elf.h>
-
-#include "box64version.h"
-#include "elfloader.h"
-#include "debug.h"
-#include "elfload_dump.h"
-#include "elfloader_private.h"
-
-#ifndef PN_XNUM 
-#define PN_XNUM (0xffff)
-#endif
-#ifndef DT_GNU_HASH
-#define DT_GNU_HASH 0x6ffffef5
-#endif
-
-static int LoadSH(FILE *f, Elf64_Shdr *s, void** SH, const char* name, uint32_t type)
-{
-    if(type && (s->sh_type != type)) {
-        printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
-        return -1;
-    }
-    if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf64_Sym)) {
-        printf_log(LOG_INFO, "Section Header \"%s\" (off=%ld, size=%ld) has size (not multiple of %ld)\n", name, s->sh_offset, s->sh_size, sizeof(Elf64_Sym));
-    }
-    *SH = box_calloc(1, s->sh_size);
-    fseeko64(f, s->sh_offset ,SEEK_SET);
-    if(fread(*SH, s->sh_size, 1, f)!=1) {
-            printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%ld, size=%ld)\n", name, s->sh_offset, s->sh_size);
-            return -1;
-    }
-
-    return 0;
-}
-
-static int FindSection(Elf64_Shdr *s, int n, char* SHStrTab, const char* name)
-{
-    for (int i=0; i<n; ++i) {
-        if(s[i].sh_type!=SHT_NULL)
-            if(!strcmp(SHStrTab+s[i].sh_name, name))
-                return i;
-    }
-    return 0;
-}
-
-static void LoadNamedSection(FILE *f, Elf64_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, size_t* num)
-{
-    int n = FindSection(s, size, SHStrTab, name);
-    printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
-    if(n)
-        LoadSH(f, s+n, what, name, type);
-    if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
-        if(*what && num)
-            *num = s[n].sh_size / sizeof(Elf64_Sym);
-    } else if(type==SHT_DYNAMIC) {
-        if(*what && num)
-            *num = s[n].sh_size / sizeof(Elf64_Dyn);
-    }
-}
-
-elfheader_t* ParseElfHeader64(FILE* f, const char* name, int exec)
-{
-    Elf64_Ehdr header;
-    int level = (exec)?LOG_INFO:LOG_DEBUG;
-    if(fread(&header, sizeof(Elf64_Ehdr), 1, f)!=1) {
-        printf_log(level, "Cannot read ELF Header\n");
-        return NULL;
-    }
-    if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
-        printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
-        return NULL;
-    }
-    if(header.e_ident[EI_CLASS]!=ELFCLASS64) {
-        if(strstr(name, ".so")) {
-            // less naging on libs...
-            printf_dump(LOG_DEBUG, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]);
-            return NULL;
-        }
-        if(header.e_ident[EI_CLASS]==ELFCLASS32) {
-            printf_log(LOG_INFO, "This is a 32bits ELF! box64 can only run 64bits ELF (%s)!\n", name);
-        } else {
-            printf_log(LOG_INFO, "Not a 64bits ELF (%d)\n", header.e_ident[EI_CLASS]);
-        }
-        return NULL;
-    }
-    if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
-        printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
-        return NULL;
-    }
-    if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
-        printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
-        return NULL;
-    }
-    if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) {
-        printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
-        return NULL;
-    }
-
-    if(header.e_type != ET_EXEC && header.e_type != ET_DYN) {
-        printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
-        return NULL;
-    }
-
-    if(header.e_machine != EM_X86_64) {
-        printf_log(level, "Not an x86_64 ELF (%d)\n", header.e_machine);
-        return NULL;
-    }
-
-    if(header.e_entry == 0 && exec) {
-        printf_log(LOG_INFO, "No entry point in ELF\n");
-        return NULL;
-    }
-    if(header.e_phentsize != sizeof(Elf64_Phdr)) {
-        printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %ld)\n", header.e_phentsize, sizeof(Elf64_Phdr));
-        return NULL;
-    }
-    if(header.e_shentsize != sizeof(Elf64_Shdr) && header.e_shentsize != 0) {
-        printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %ld)\n", header.e_shentsize, sizeof(Elf64_Shdr));
-        return NULL;
-    }
-
-    elfheader_t *head = box_calloc(1, sizeof(elfheader_t));
-    elfheader64_t* h = &head->_64;
-    h->name = box_strdup(name);
-    h->entrypoint = header.e_entry;
-    h->numPHEntries = header.e_phnum;
-    h->numSHEntries = header.e_shnum;
-    h->SHIdx = header.e_shstrndx;
-    h->e_type = header.e_type;
-    // special cases for nums
-    if(header.e_shentsize && !h->numSHEntries) {
-        printf_dump(LOG_DEBUG, "Read number of Sections in 1st Section\n");
-        // read 1st section header and grab actual number from here
-        fseeko64(f, header.e_shoff, SEEK_SET);
-        Elf64_Shdr section;
-        if(fread(&section, sizeof(Elf64_Shdr), 1, f)!=1) {
-            box_free(h);
-            printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
-            return NULL;
-        }
-        h->numSHEntries = section.sh_size;
-    }
-    if(header.e_shentsize && h->numSHEntries) {
-        // now read all section headers
-        printf_dump(LOG_DEBUG, "Read %zu Section header\n", h->numSHEntries);
-        h->SHEntries = (Elf64_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf64_Shdr));
-        fseeko64(f, header.e_shoff ,SEEK_SET);
-        if(fread(h->SHEntries, sizeof(Elf64_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
-                FreeElfHeader(&head);
-                printf_log(LOG_INFO, "Cannot read all Section Header\n");
-                return NULL;
-        }
-
-        if(h->numPHEntries == PN_XNUM) {
-            printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
-            // read 1st section header and grab actual number from here
-            h->numPHEntries = h->SHEntries[0].sh_info;
-        }
-    }
-
-    printf_dump(LOG_DEBUG, "Read %zu Program header\n", h->numPHEntries);
-    h->PHEntries = (Elf64_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf64_Phdr));
-    fseeko64(f, header.e_phoff ,SEEK_SET);
-    if(fread(h->PHEntries, sizeof(Elf64_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
-            FreeElfHeader(&head);
-            printf_log(LOG_INFO, "Cannot read all Program Header\n");
-            return NULL;
-    }
-
-    if(header.e_shentsize && header.e_shnum) {
-        if(h->SHIdx == SHN_XINDEX) {
-            printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n");
-            h->SHIdx = h->SHEntries[0].sh_link;
-        }
-        if(h->SHIdx > h->numSHEntries) {
-            printf_log(LOG_INFO, "Incoherent Section String Table Index : %zu / %zu\n", h->SHIdx, h->numSHEntries);
-            FreeElfHeader(&head);
-            return NULL;
-        }
-        // load Section table
-        printf_dump(LOG_DEBUG, "Loading Sections Table String (idx = %zu)\n", h->SHIdx);
-        if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
-            FreeElfHeader(&head);
-            return NULL;
-        }
-        if(box64_dump) DumpMainHeader(&header, head);
-
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
-        if(box64_dump && h->SymTab) DumpSymTab64(head);
-
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
-        if(box64_dump && h->Dynamic) DumpDynamicSections64(h);
-        // grab DT_REL & DT_RELA stuffs
-        // also grab the DT_STRTAB string table
-        {
-            for (size_t i=0; i<h->numDynamic; ++i) {
-                Elf64_Dyn d = h->Dynamic[i];
-                Elf64_Word val = d.d_un.d_val;
-                Elf64_Addr ptr = d.d_un.d_ptr;
-                switch (d.d_tag) {
-                case DT_REL:
-                    h->rel = ptr;
-                    break;
-                case DT_RELSZ:
-                    h->relsz = val;
-                    break;
-                case DT_RELENT:
-                    h->relent = val;
-                    break;
-                case DT_RELA:
-                    h->rela = ptr;
-                    break;
-                case DT_RELASZ:
-                    h->relasz = val;
-                    break;
-                case DT_RELAENT:
-                    h->relaent = val;
-                    break;
-                case DT_RELR:
-                    h->relr = ptr;
-                    break;
-                case DT_RELRSZ:
-                    h->relrsz = val;
-                    break;
-                case DT_RELRENT:
-                    h->relrent = val;
-                    break;
-                case DT_PLTGOT:
-                    h->pltgot = ptr;
-                    break;
-                case DT_PLTREL:
-                    h->pltrel = val;
-                    break;
-                case DT_PLTRELSZ:
-                    h->pltsz = val;
-                    break;
-                case DT_JMPREL:
-                    h->jmprel = ptr;
-                    break;
-                case DT_STRTAB:
-                    h->DynStrTab = (char*)(ptr);
-                    break;
-                case DT_STRSZ:
-                    h->szDynStrTab = val;
-                    break;
-                case DT_INIT: // Entry point
-                    h->initentry = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
-                    break;
-                case DT_INIT_ARRAY:
-                    h->initarray = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
-                    break;
-                case DT_INIT_ARRAYSZ:
-                    h->initarray_sz = val / sizeof(Elf64_Addr);
-                    printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %zu\n", h->initarray_sz);
-                    break;
-                case DT_PREINIT_ARRAYSZ:
-                    #ifndef ANDROID
-                        if(val)
-                            printf_log(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
-                    #endif
-                    break;
-                case DT_FINI: // Exit hook
-                    h->finientry = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
-                    break;
-                case DT_FINI_ARRAY:
-                    h->finiarray = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
-                    break;
-                case DT_FINI_ARRAYSZ:
-                    h->finiarray_sz = val / sizeof(Elf64_Addr);
-                    printf_dump(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %zu\n", h->finiarray_sz);
-                    break;
-                case DT_VERNEEDNUM:
-                    h->szVerNeed = val;
-                    printf_dump(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
-                    break;
-                case DT_VERNEED:
-                    h->VerNeed = (Elf64_Verneed*)ptr;
-                    printf_dump(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
-                    break;
-                case DT_VERDEFNUM:
-                    h->szVerDef = val;
-                    printf_dump(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
-                    break;
-                case DT_VERDEF:
-                    h->VerDef = (Elf64_Verdef*)ptr;
-                    printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
-                    break;
-                case DT_FLAGS:
-                    h->flags = val;
-                    printf_dump(LOG_DEBUG, "The DT_FLAGS is 0x%x\n", h->flags);
-                    break;
-                case DT_HASH:
-                    h->hash = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_HASH is at address %p\n", (void*)h->hash);
-                    break;
-                case DT_GNU_HASH:
-                    h->gnu_hash = ptr;
-                    printf_dump(LOG_DEBUG, "The DT_GNU_HASH is at address %p\n", (void*)h->gnu_hash);
-                    break;
-                }
-            }
-            if(h->rel) {
-                if(h->relent != sizeof(Elf64_Rel)) {
-                    printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%zx)\n", h->relent, sizeof(Elf64_Rel));
-                    FreeElfHeader(&head);
-                    return NULL;
-                }
-                printf_dump(LOG_DEBUG, "Rel Table @%p (0x%zx/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
-            }
-            if(h->rela) {
-                if(h->relaent != sizeof(Elf64_Rela)) {
-                    printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%zx)\n", h->relaent, sizeof(Elf64_Rela));
-                    FreeElfHeader(&head);
-                    return NULL;
-                }
-                printf_dump(LOG_DEBUG, "RelA Table @%p (0x%zx/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
-            }
-            if(h->jmprel) {
-                if(h->pltrel == DT_REL) {
-                    h->pltent = sizeof(Elf64_Rel);
-                } else if(h->pltrel == DT_RELA) {
-                    h->pltent = sizeof(Elf64_Rela);
-                } else {
-                    printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%zx, type=%ld)\n", h->pltsz, h->pltrel);
-                    FreeElfHeader(&head);
-                    return NULL;
-                }
-                if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
-                    printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%zx, ent=0x%x, type=%ld)\n", h->pltsz, h->pltent, h->pltrel);
-                    FreeElfHeader(&head);
-                    return NULL;
-                }
-                printf_dump(LOG_DEBUG, "PLT Table @%p (type=%ld 0x%zx/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
-            }
-        }
-        // look for PLT Offset
-        int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
-        if(ii) {
-            h->gotplt = h->SHEntries[ii].sh_addr;
-            h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
-            printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
-        }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
-        if(ii) {
-            h->got = h->SHEntries[ii].sh_addr;
-            h->got_end = h->got + h->SHEntries[ii].sh_size;
-            printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
-        }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
-        if(ii) {
-            h->plt = h->SHEntries[ii].sh_addr;
-            h->plt_end = h->plt + h->SHEntries[ii].sh_size;
-            printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
-        }
-        // grab version of symbols
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
-        if(ii) {
-            h->VerSym = (Elf64_Half*)(h->SHEntries[ii].sh_addr);
-            printf_dump(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
-        }
-        // grab .text for main code
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
-        if(ii) {
-            h->text = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            h->textsz = h->SHEntries[ii].sh_size;
-            printf_dump(LOG_DEBUG, "The .text is at address %p, and is %zu big\n", (void*)h->text, h->textsz);
-        }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame");
-        if(ii) {
-            h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size;
-            printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
-        }
-        ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
-        if(ii) {
-            h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr);
-            printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
-        }
-
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
-        LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
-    }
-    
-    return head;
-}
-
-const char* BindSym64(int bind)
-{
-    switch(bind) {
-        case STB_GLOBAL: return "STB_GLOBAL";
-        case STB_WEAK: return "STB_WEAK";
-        case STB_LOCAL: return "STB_LOCAL";
-        case STB_GNU_UNIQUE: return "STB_GNU_UNIQUE";
-    }
-    static char tmp[50];
-    sprintf(tmp, "??? 0x%x", bind);
-    return tmp;
-}
diff --git a/src/include/elfload_dump.h b/src/include/elfload_dump.h
index 74906b5e..3fa0a910 100644
--- a/src/include/elfload_dump.h
+++ b/src/include/elfload_dump.h
@@ -3,16 +3,25 @@
 
 typedef struct elfheader_s elfheader_t;
 
+const char* SymName32(elfheader_t *h, Elf32_Sym* sym);
 const char* SymName64(elfheader_t *h, Elf64_Sym* sym);
+const char* DumpRelType32(int t);
 const char* DumpRelType64(int t);
+void DumpMainHeader32(Elf32_Ehdr *header, elfheader_t *h);
 void DumpMainHeader64(Elf64_Ehdr *header, elfheader_t *h);
+void DumpSymTab32(elfheader_t *h);
 void DumpSymTab64(elfheader_t *h);
+void DumpDynamicSections32(elfheader_t *h);
 void DumpDynamicSections64(elfheader_t *h);
 void DumpDynamicNeeded(elfheader_t *h);
 void DumpDynamicRPath(elfheader_t *h);
+void DumpDynSym32(elfheader_t *h);
 void DumpDynSym64(elfheader_t *h);
+void DumpRelTable32(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name);
 void DumpRelTable64(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name);
+void DumpRelATable32(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name);
 void DumpRelATable64(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name);
+void DumpRelRTable32(elfheader_t *h, int cnt, Elf32_Relr *relr, const char *name);
 void DumpRelRTable64(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name);
 
 void DumpBinary(char* p, int sz);