about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYip Coekjan <69834864+Coekjan@users.noreply.github.com>2024-07-02 19:47:48 +0800
committerGitHub <noreply@github.com>2024-07-02 13:47:48 +0200
commit9cd8812d8b2b1648a40c05e02787c375d5ce5cd4 (patch)
treec9be3f2f7692387ec8e28d6eb5f0bfd0afb6a3ca /src
parent4b0b3fc98ae4a1e848765e0cd48f958a13fc683d (diff)
downloadbox64-9cd8812d8b2b1648a40c05e02787c375d5ce5cd4.tar.gz
box64-9cd8812d8b2b1648a40c05e02787c375d5ce5cd4.zip
Handle `.relr.dyn` section (#1626)
Diffstat (limited to 'src')
-rw-r--r--src/elfs/elfload_dump.c12
-rw-r--r--src/elfs/elfloader.c28
-rw-r--r--src/elfs/elfloader_private.h3
-rw-r--r--src/elfs/elfparser.c9
-rw-r--r--src/emu/x64int3.c2
-rw-r--r--src/include/elfload_dump.h1
-rw-r--r--src/include/elfloader.h19
7 files changed, 73 insertions, 1 deletions
diff --git a/src/elfs/elfload_dump.c b/src/elfs/elfload_dump.c
index 2a8189b5..62cedcf6 100644
--- a/src/elfs/elfload_dump.c
+++ b/src/elfs/elfload_dump.c
@@ -367,6 +367,18 @@ void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name)
     }
 }
 
+void DumpRelRTable(elfheader_t *h, int cnt, Elf64_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, (void*)relr[i]);
+        printf_dump(LOG_NEVER, "ELF Dump %s Table=====\n", name);
+    }
+}
+
 void DumpBinary(char* p, int sz)
 {
     // dump p as 
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index efb0ef57..fab47ad6 100644
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -784,12 +784,40 @@ int RelocateElfRELA(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbin
     }
     return bindnow?ret_ok:0;
 }
+
+int RelocateElfRELR(elfheader_t *head, int cnt, Elf64_Relr *relr) {
+    Elf64_Addr *where = NULL;
+    for (int i = 0; i < cnt; i++) {
+        Elf64_Relr p = relr[i];
+        if ((p & 1) == 0) {
+            where = (Elf64_Addr *)(p + head->delta);
+            printf_dump(LOG_NEVER, "Apply (even) RELR %p -> %p\n", *where, *where + head->delta);
+            *where++ += head->delta;
+        } else {
+            for (long j = 0; (p >>= 1) != 0; j++)
+                if ((p & 1) != 0) {
+                    printf_dump(LOG_NEVER, "Apply (odd) RELR %p -> %p\n", where[j], where[j] + head->delta);
+                    where[j] += head->delta;
+                }
+            where += CHAR_BIT * sizeof(Elf64_Relr) - 1;
+        }
+    }
+    return 0;
+}
+
 int RelocateElf(lib_t *maplib, lib_t *local_maplib, int bindnow, int deepbind, elfheader_t* head)
 {
     if((head->flags&DF_BIND_NOW) && !bindnow) {
         bindnow = 1;
         printf_log(LOG_DEBUG, "Forcing %s to Bind Now\n", head->name);
     }
+    if(head->relr) {
+        int cnt = head->relrsz / head->relrent;
+        DumpRelRTable(head, cnt, (Elf64_Relr *)(head->relr + head->delta), "RelR");
+        printf_dump(LOG_DEBUG, "Applying %d Relocation(s) without Addend for %s bindnow=%d, deepbind=%d\n", cnt, head->name, bindnow, deepbind);
+        if(RelocateElfRELR(head, cnt, (Elf64_Relr *)(head->relr + head->delta)))
+            return -1;
+    }
     if(head->rel) {
         int cnt = head->relsz / head->relent;
         DumpRelTable(head, cnt, (Elf64_Rel *)(head->rel + head->delta), "Rel");
diff --git a/src/elfs/elfloader_private.h b/src/elfs/elfloader_private.h
index 91b3b510..d813488c 100644
--- a/src/elfs/elfloader_private.h
+++ b/src/elfs/elfloader_private.h
@@ -68,6 +68,9 @@ typedef struct elfheader_s {
     uintptr_t   rela;
     size_t      relasz;
     int         relaent;
+    uintptr_t   relr;
+    size_t      relrsz;
+    int         relrent;
     uintptr_t   jmprel;
     size_t      pltsz;
     int         pltent;
diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c
index fb6e4637..545503c9 100644
--- a/src/elfs/elfparser.c
+++ b/src/elfs/elfparser.c
@@ -219,6 +219,15 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
                 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;
diff --git a/src/emu/x64int3.c b/src/emu/x64int3.c
index b407848c..836366aa 100644
--- a/src/emu/x64int3.c
+++ b/src/emu/x64int3.c
@@ -26,12 +26,12 @@
 #include "wrapper.h"
 #include "box64context.h"
 #include "librarian.h"
-#include "elfload_dump.h"
 #include "signals.h"
 #include "tools/bridge_private.h"
 
 #include <elf.h>
 #include "elfloader.h"
+#include "elfload_dump.h"
 #include "elfs/elfloader_private.h"
 
 typedef int32_t (*iFpppp_t)(void*, void*, void*, void*);
diff --git a/src/include/elfload_dump.h b/src/include/elfload_dump.h
index ce0e9c1b..ad2ecd71 100644
--- a/src/include/elfload_dump.h
+++ b/src/include/elfload_dump.h
@@ -18,6 +18,7 @@ void DumpDynamicRPath(elfheader_t *h);
 void DumpDynSym(elfheader_t *h);
 void DumpRelTable(elfheader_t *h, int cnt, Elf64_Rel *rel, const char* name);
 void DumpRelATable(elfheader_t *h, int cnt, Elf64_Rela *rela, const char* name);
+void DumpRelRTable(elfheader_t *h, int cnt, Elf64_Relr *relr, const char *name);
 
 void DumpBinary(char* p, int sz);
 
diff --git a/src/include/elfloader.h b/src/include/elfloader.h
index ea0928b1..770709c8 100644
--- a/src/include/elfloader.h
+++ b/src/include/elfloader.h
@@ -1,6 +1,7 @@
 #ifndef __ELF_LOADER_H_
 #define __ELF_LOADER_H_
 #include <stdio.h>
+#include <elf.h>
 
 typedef struct elfheader_s elfheader_t;
 typedef struct lib_s lib_t;
@@ -14,6 +15,24 @@ typedef struct kh_defaultversion_s kh_defaultversion_t;
 typedef struct dynablock_s dynablock_t;
 #endif
 
+// Define for handling .relr.dyn section (since glibc 2.36)
+// See Also https://lists.gnu.org/archive/html/info-gnu/2022-08/msg00000.html
+//
+// if glibc 2.36 is widely used in the future, this part can be removed
+#ifndef DT_RELR
+
+// Copy from (glibc 2.36) elf.h
+
+#define SHT_RELR	  19            /* RELR relative relocations */
+
+typedef Elf32_Word	Elf32_Relr;
+typedef Elf64_Xword	Elf64_Relr;
+
+#define DT_RELRSZ	35		/* Total size of RELR relative relocations */
+#define DT_RELR		36		/* Address of RELR relative relocations */
+#define DT_RELRENT	37		/* Size of one RELR relative relocaction */
+#endif // DT_RELR
+
 // Open an elfheader. Transfert control of f to elfheader also!
 elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
 void FreeElfHeader(elfheader_t** head);