From 0a3a6c0571d26f95508a9a08f534ab7c8ec96ffc Mon Sep 17 00:00:00 2001
From: root <root@localhost.localdomain>
Date: Wed, 13 Oct 2021 20:56:18 +0800
Subject: [PATCH] elf: relocate text and data

relocate text and data

Signed-off-by: zhoukang <zhoukang7@huawei.com>
---
 elf/dl-close.c              |   6 +
 elf/dl-deps.c               |   1 +
 elf/dl-fini.c               |   4 +
 elf/dl-hwcaps.c             |   3 +
 elf/dl-init.c               |   4 +
 elf/dl-load.c               | 105 +++++++++++-
 elf/dl-reloc.c              |   3 +
 elf/dl-runtime.c            |   2 +
 elf/dl-version.c            |   8 +
 elf/do-rel.h                |  25 ++-
 elf/get-dynamic-info.h      |   9 +-
 elf/rtld.c                  | 316 ++++++++++++++++++++++++++++++++++++
 include/link.h              |  72 ++++++++
 sysdeps/x86_64/dl-machine.h |   7 +
 14 files changed, 559 insertions(+), 6 deletions(-)

diff --git a/elf/dl-close.c b/elf/dl-close.c
index ecd67297..bb3fe3f1 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -278,6 +278,9 @@ _dl_close_worker (struct link_map *map, bool force)
 
 	      if (imap->l_info[DT_FINI_ARRAY] != NULL)
 		{
+// HUGEPAGE
+hugepage_use_data_vhdr(imap);
+
 		  ElfW(Addr) *array =
 		    (ElfW(Addr) *) (imap->l_addr
 				    + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
@@ -288,6 +291,9 @@ _dl_close_worker (struct link_map *map, bool force)
 		    ((fini_t) array[sz]) ();
 		}
 
+// HUGEPAGE
+hugepage_use_text_vhdr(imap);
+
 	      /* Next try the old-style destructor.  */
 	      if (imap->l_info[DT_FINI] != NULL)
 		DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 9d9b1ba7..5738142b 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -234,6 +234,7 @@ _dl_map_object_deps (struct link_map *map,
 	  args.open_mode = open_mode;
 	  orig = runp;
 
+_dl_debug_printf("HUGEPAGE: linkmap 0x%lx, l_ld 0x%lx\n", (unsigned long)l, (unsigned long)l->l_ld);
 	  for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
 	    if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
 	      {
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 3cfc2624..64009aa2 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -129,6 +129,8 @@ _dl_fini (void)
 		      /* First see whether an array is given.  */
 		      if (l->l_info[DT_FINI_ARRAY] != NULL)
 			{
+// HUGEPAGE
+hugepage_use_rodata_vhdr(l);
 			  ElfW(Addr) *array =
 			    (ElfW(Addr) *) (l->l_addr
 					    + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
@@ -138,6 +140,8 @@ _dl_fini (void)
 			    ((fini_t) array[i]) ();
 			}
 
+// HUGEPAGE
+hugepage_use_text_vhdr(l);
 		      /* Next try the old-style destructor.  */
 		      if (l->l_info[DT_FINI] != NULL)
 			DL_CALL_DT_FINI
diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c
index 23482a88..e925f98b 100644
--- a/elf/dl-hwcaps.c
+++ b/elf/dl-hwcaps.c
@@ -65,6 +65,9 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
       for (uint_fast16_t i = 0; i < phnum; ++i)
 	if (phdr[i].p_type == PT_NOTE)
 	  {
+// HUGEPAGE
+hugepage_use_elf_vhdr(GLRO(dl_sysinfo_map));
+
 	    const ElfW(Addr) start = (phdr[i].p_vaddr
 				      + GLRO(dl_sysinfo_map)->l_addr);
 	    /* NB: Some PT_NOTE segment may have alignment value of 0
diff --git a/elf/dl-init.c b/elf/dl-init.c
index 45405cd0..409f2e0f 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -50,6 +50,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
     _dl_debug_printf ("\ncalling init: %s\n\n",
 		      DSO_FILENAME (l->l_name));
 
+// HUGEPAGE
+hugepage_use_text_vhdr(l);
   /* Now run the local constructors.  There are two forms of them:
      - the one named by DT_INIT
      - the others in the DT_INIT_ARRAY.
@@ -67,6 +69,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
 
       jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
 
+// HUGEPAGE
+hugepage_use_rodata_vhdr(l);
       addrs = (ElfW(Addr) *) (init_array->d_un.d_ptr + l->l_addr);
       for (j = 0; j < jm; ++j)
 	((init_t) addrs[j]) (argc, argv, env);
diff --git a/elf/dl-load.c b/elf/dl-load.c
index f60e6876..7eaf4d53 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -852,6 +852,81 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
 }
 
 
+// HUGEPAGE
+extern char *layout_alloc(int type, unsigned int len);
+
+const char * _dl_map_segments_mode3 (struct link_map *l, int fd,
+                  const ElfW(Ehdr) *header, int type,
+                  const struct loadcmd loadcmds[], size_t nloadcmds,
+                  const size_t maplength, bool has_holes,
+                  struct link_map *loader)
+{
+	const struct loadcmd *c = loadcmds;
+	char *layout = NULL;
+	unsigned int len;
+	struct elf_info *info = &l->info;
+	size_t ret;
+
+	if (__glibc_unlikely (type != ET_DYN)) {
+		return "ELF must be ET_DYN";
+	}
+
+	// first LOAD segment
+	l->l_map_start = (ElfW(Addr)) __mmap (0, c->mapend - c->mapstart, c->prot, MAP_COPY|MAP_FILE, fd, c->mapoff);
+	l->l_map_end = l->l_map_start + c->mapend;
+	l->l_addr = l->l_map_start - c->mapstart;
+	info->elf_vhdr = (char*)(l->l_map_start - c->mapstart);
+
+	// text
+	++c;
+	info->text_begin = c->mapstart;
+	len = c->mapend - c->mapstart;
+	layout = layout_alloc(LAYOUT_TEXT, len);
+	__lseek(fd, c->mapoff, SEEK_SET);
+	_dl_debug_printf("\nHUGEPAGE: linkmap 0x%lx, text 0x%lx, len 0x%lx, file-offset 0x%lx\n", (unsigned long)l, (unsigned long)layout, (unsigned long)len, c->mapoff);
+	ret = (size_t) __read_nocancel(fd, (void *)layout, len);
+	if (ret != len) {
+		_dl_debug_printf("\nHUGEPAGE: ret 0x%lx, len 0x%lx\n", (unsigned long)ret, (unsigned long)len);
+		return "cannot read file data";
+	}
+	info->text_vhdr = layout - c->mapstart;
+
+	// rodata
+	++c;
+	info->rodata_begin = c->mapstart;
+	len = (c + 1)->allocend - c->mapstart;
+	layout = layout_alloc(LAYOUT_RODATA, len);
+
+	len = c->mapend - c->mapstart;
+	__lseek(fd, c->mapoff, SEEK_SET);
+	_dl_debug_printf("\n rodata 0x%lx, len 0x%lx\n", (unsigned long)layout, (unsigned long)len);
+	if ((size_t) __read_nocancel(fd, (void *)layout, len) != len) {
+		return "cannot read file data";
+	}
+	info->rodata_vhdr = layout - c->mapstart;
+	info->data_vhdr = info->rodata_vhdr;
+	if (c->allocend > c->dataend) {
+		memset(info->rodata_vhdr + c->dataend, '\0', c->allocend - c->dataend);
+	}
+
+	// data
+	++c;
+	layout = layout + (c->mapstart - (c - 1)->mapstart);
+	len = c->mapend - c->mapstart;
+	__lseek(fd, c->mapoff, SEEK_SET);
+	_dl_debug_printf("\n data 0x%lx, len 0x%lx\n", (unsigned long)layout, (unsigned long)len);
+	if ((size_t) __read_nocancel(fd, (void *)layout, len) != len) {
+		return "cannot read file data";
+	}
+	if (c->allocend > c->dataend) {
+		memset(info->rodata_vhdr + c->dataend, '\0', c->allocend - c->dataend);
+	}
+
+	l->l_contiguous = 0;
+	return NULL;
+}
+
+
 /* Map in the shared object NAME, actually located in REALNAME, and already
    opened on FD.  */
 
@@ -1200,8 +1275,15 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
        This is responsible for filling in:
        l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
      */
+
+if (l->l_name[0] == '/') {
     errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
 				  maplength, has_holes, loader);
+} else {
+// HUGEPAGE
+    errstring = _dl_map_segments_mode3 (l, fd, header, type, loadcmds, nloadcmds, maplength, has_holes, loader);
+}
+
     if (__glibc_unlikely (errstring != NULL))
       goto call_lose;
   }
@@ -1215,7 +1297,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	}
     }
   else
-    l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+    { 
+      // HUGEPAGE
+      hugepage_use_rodata_vhdr(l);
+      l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+    }
 
   elf_get_dynamic_info (l, NULL);
 
@@ -1255,8 +1341,12 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
       l->l_phdr_allocated = 1;
     }
   else
-    /* Adjust the PT_PHDR value by the runtime load address.  */
-    l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
+    {
+      // HUGEPAGE
+      hugepage_use_elf_vhdr(l);
+      /* Adjust the PT_PHDR value by the runtime load address.  */
+      l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
+    }
 
   if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
     {
@@ -1271,6 +1361,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	  const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
 
 	  struct link_map *const m = &GL(dl_rtld_map);
+// HUGEPAGE
+hugepage_use_data_vhdr(m);
 	  const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
 					+ m->l_relro_size)
 				       & -GLRO(dl_pagesize));
@@ -1306,8 +1398,11 @@ cannot enable executable stack as shared object requires");
     }
 
   /* Adjust the address of the TLS initialization image.  */
-  if (l->l_tls_initimage != NULL)
+  if (l->l_tls_initimage != NULL) {
+    // HUGEPAGE
+    hugepage_use_rodata_vhdr(l);
     l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
+  }
 
   /* We are done mapping in the file.  We no longer need the descriptor.  */
   if (__glibc_unlikely (__close_nocancel (fd) != 0))
@@ -1321,6 +1416,8 @@ cannot enable executable stack as shared object requires");
   /* If this is ET_EXEC, we should have loaded it as lt_executable.  */
   assert (type != ET_EXEC || l->l_type == lt_executable);
 
+  // HUGEPAGE
+  hugepage_use_text_vhdr(l);
   l->l_entry += l->l_addr;
 
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 164f4efa..d3df5ef5 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -306,6 +306,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
 void
 _dl_protect_relro (struct link_map *l)
 {
+// HUGEPAGE
+return;
+
   ElfW(Addr) start = ALIGN_DOWN((l->l_addr
 				 + l->l_relro_addr),
 				GLRO(dl_pagesize));
diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c
index 3d2f4a7a..7a8dc152 100644
--- a/elf/dl-runtime.c
+++ b/elf/dl-runtime.c
@@ -72,6 +72,8 @@ _dl_fixup (
     = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset);
   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
   const ElfW(Sym) *refsym = sym;
+// HUGEPAGE
+hugepage_use_elf_vhdr(l);
   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
   lookup_t result;
   DL_FIXUP_VALUE_TYPE value;
diff --git a/elf/dl-version.c b/elf/dl-version.c
index 7860cc81..d9fb5797 100644
--- a/elf/dl-version.c
+++ b/elf/dl-version.c
@@ -87,6 +87,8 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
   def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
   assert (def_offset != 0);
 
+// HUGEPAGE
+hugepage_use_elf_vhdr(map);
   def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
   while (1)
     {
@@ -177,6 +179,8 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
 
   if (dyn != NULL)
     {
+// HUGEPAGE
+hugepage_use_elf_vhdr(map);
       /* This file requires special versions from its dependencies.  */
       ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
 
@@ -290,6 +294,10 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
       if (dyn != NULL)
 	{
 	  ElfW(Verneed) *ent;
+
+// HUGEPAGE
+hugepage_use_elf_vhdr(map);
+
 	  ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
 	  while (1)
 	    {
diff --git a/elf/do-rel.h b/elf/do-rel.h
index 19cb5d23..716a87ad 100644
--- a/elf/do-rel.h
+++ b/elf/do-rel.h
@@ -108,8 +108,14 @@ elf_dynamic_do_Rel (struct link_map *map,
 	if (l_addr != 0 || ! map->l_info[VALIDX(DT_GNU_PRELINKED)])
 # endif
 #endif
-	  for (; relative < r; ++relative)
+
+	  for (; relative < r; ++relative) {
+	    // HUGEPAGE
+	    hugepage_use_vhdr(map, (long)relative->r_addend);
+	    l_addr = map->l_addr;
+	    hugepage_use_vhdr(map, (long)relative->r_offset);
 	    DO_ELF_MACHINE_REL_RELATIVE (map, l_addr, relative);
+	  }
 
 #ifdef RTLD_BOOTSTRAP
       /* The dynamic linker always uses versioning.  */
@@ -118,6 +124,10 @@ elf_dynamic_do_Rel (struct link_map *map,
       if (map->l_info[VERSYMIDX (DT_VERSYM)])
 #endif
 	{
+
+// HUGEPAGE
+hugepage_use_elf_vhdr(map);
+
 	  const ElfW(Half) *const version =
 	    (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
 
@@ -133,6 +143,9 @@ elf_dynamic_do_Rel (struct link_map *map,
 		}
 #endif
 
+// HUGEPAGE
+hugepage_use_data_vhdr(map);
+
 	      ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
 	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
 			       &map->l_versions[ndx],
@@ -144,6 +157,8 @@ elf_dynamic_do_Rel (struct link_map *map,
 	    for (; r2 <= end2; ++r2)
 	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
 		{
+// HUGEPAGE
+hugepage_use_data_vhdr(map);
 		  ElfW(Half) ndx
 		    = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
 		  elf_machine_rel (map, r2,
@@ -167,16 +182,24 @@ elf_dynamic_do_Rel (struct link_map *map,
 	      }
 	    else
 # endif
+{
+// HUGEPAGE
+hugepage_use_data_vhdr(map);
 	      elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
 			       (void *) (l_addr + r->r_offset), skip_ifunc);
+}
 
 # ifdef ELF_MACHINE_IRELATIVE
 	  if (r2 != NULL)
 	    for (; r2 <= end2; ++r2)
 	      if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
+{
+// HUGEPAGE
+hugepage_use_data_vhdr(map);
 		elf_machine_rel (map, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
 				 NULL, (void *) (l_addr + r2->r_offset),
 				 skip_ifunc);
+}
 # endif
 	}
 #endif
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index 4b1ea7c4..b2965165 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -98,8 +98,10 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
 	  }								      \
       while (0)
 
+      // HUGEPAGE
+      hugepage_use_elf_vhdr(l);
+      l_addr = l->l_addr;
       ADJUST_DYN_INFO (DT_HASH);
-      ADJUST_DYN_INFO (DT_PLTGOT);
       ADJUST_DYN_INFO (DT_STRTAB);
       ADJUST_DYN_INFO (DT_SYMTAB);
 # if ! ELF_MACHINE_NO_RELA
@@ -111,6 +113,11 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
       ADJUST_DYN_INFO (DT_JMPREL);
       ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
       ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH));
+
+      hugepage_use_rodata_vhdr(l);
+      l_addr = l->l_addr;
+      ADJUST_DYN_INFO (DT_PLTGOT);
+
 # undef ADJUST_DYN_INFO
       assert (cnt <= DL_RO_DYN_TEMP_CNT);
     }
diff --git a/elf/rtld.c b/elf/rtld.c
index 4abc6dd4..2fbd8fe2 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -861,6 +861,310 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map)
   return npreloads;
 }
 
+
+// HUGEPAGE
+#define SYM_NAME_SIZE 256
+#define LAYOUT_SIZE 0x40000000
+
+char *g_text_layout = NULL;
+char *g_rodata_layout = NULL;
+
+#define BYTES_NOP1      0x90
+
+#define CALL_INSN_SIZE          5
+#define CALL_INSN_OPCODE        0xE8
+
+#define JMP32_INSN_SIZE         5
+#define JMP32_INSN_OPCODE       0xE9
+
+#define POKE_MAX_OPCODE_SIZE    10
+
+union text_poke_insn {
+        unsigned char text[POKE_MAX_OPCODE_SIZE];
+        struct {
+                unsigned char opcode;
+                int disp;
+        } __attribute__ ((packed));
+};
+
+static int text_gen_insn(const void *loc, const void *dest)
+{
+        union text_poke_insn *insn;
+
+        // ff 15 00 00 00 00       callq  *0x00(%rip)
+        if ((*(unsigned char *)(loc - 2) == 0xff) && (*(unsigned char *)(loc - 1) == 0x15)) {
+                insn = (union text_poke_insn *)(loc - 2);
+                insn->opcode = CALL_INSN_OPCODE;
+                insn->disp = (long)dest - (long)(loc - 2 + CALL_INSN_SIZE);
+                insn->text[5] = BYTES_NOP1;
+                return 0;
+        }
+	return -1;
+}
+
+void layout_init(void)
+{
+	g_text_layout = (char*) __mmap(0, LAYOUT_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(21 << MAP_HUGE_SHIFT), -1, 0);
+	g_rodata_layout = (char*) __mmap(0, LAYOUT_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(21 << MAP_HUGE_SHIFT), -1, 0);
+
+	if (g_text_layout == NULL) {
+		_dl_debug_printf("\nHUGEPAGE: g_text_layout alloc fail \n");
+	}
+}
+
+char *layout_alloc(int type, unsigned int len)
+{
+	char *ret = NULL;
+
+	if (g_text_layout == NULL) {
+		layout_init();
+	}
+
+	len = ALIGN_UP(len, 0x1000);
+	if (type == LAYOUT_TEXT) {
+		ret = g_text_layout;
+		g_text_layout += len;
+	} else {
+		ret = g_rodata_layout;
+		g_rodata_layout += len;
+	}
+	return ret;
+}
+
+static int rewrite_section_headers(struct elf_info *info)
+{
+        unsigned int i;
+        Elf64_Ehdr *hdr = info->hdr;
+        Elf64_Shdr *sechdrs = info->sechdrs;
+
+        /* This should always be true, but let's be sure. */
+        sechdrs[0].sh_addr = 0;
+
+        for (i = 1; i < hdr->e_shnum; i++) {
+                Elf64_Shdr *shdr = &sechdrs[i];
+                shdr->sh_addr = (size_t) hdr + shdr->sh_offset;
+        }
+
+        return 0;
+}
+
+static int resolve_symbol(struct link_map *l, const char *name, Elf64_Sym *sym)
+{
+	const ElfW(Sym) *ref = sym;
+	struct link_map *sym_map = NULL;
+        char buf[SYM_NAME_SIZE] = {0};
+        for (int i = 0; ; i++) {
+                if (name[i] == '\0' || name[i] == '@')
+                        break;
+                buf[i] = name[i];
+        }
+        sym_map = _dl_lookup_symbol_x(buf, l, &ref, l->l_scope, 0, ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA, DL_LOOKUP_ADD_DEPENDENCY, NULL);
+	// TODO: use vhdr
+	if (ref != NULL) {
+        	sym->st_value = (Elf64_Addr)sym_map->l_addr + ref->st_value;
+	}
+        _dl_debug_printf("HUGEPAGE: symbol: 0x%lx %s\n", (long)sym->st_value, name);
+        return 0;
+}
+
+static int simplify_symbols(struct link_map *lmap, struct elf_info *info)
+{
+        char *strtab = info->strtab;
+        Elf64_Shdr *symsec = info->symsec;
+        Elf64_Sym *syms = (void *)symsec->sh_addr;
+        unsigned long secbase = 0;
+        unsigned int i;
+        int ret = 0;
+
+        // .symtab
+        for (i = 1; i < symsec->sh_size / sizeof(Elf64_Sym); i++) {
+                Elf64_Sym *sym = syms + i;
+                const char *name = strtab + sym->st_name;
+
+                switch (sym->st_shndx) {
+                case SHN_COMMON:
+                case SHN_ABS:
+                        /* Don't need to do anything */
+                        break;
+
+                case SHN_UNDEF:
+                        ret = resolve_symbol(lmap, name, sym);
+                        break;
+
+                default:
+                        if ((ELF64_ST_TYPE(sym->st_info) == STT_SECTION) || (ELF64_ST_TYPE(sym->st_info) == STT_NOTYPE)) {
+                                break;
+                        }
+                        // local ELF FUNC
+                        if (ELF64_ST_TYPE(sym->st_info) == STT_FUNC) {
+                                secbase = (unsigned long)info->text_vhdr;
+                        }
+                        // TODO: rodata
+                        // local ELF OBJECT
+                        if (ELF64_ST_TYPE(sym->st_info) == STT_OBJECT) {
+                                secbase = (unsigned long)info->rodata_vhdr;
+                        }
+                        sym->st_value += secbase;
+                        _dl_debug_printf("symbol: 0x%lx %s 0x%x local\n", (long)sym->st_value, name, sym->st_info);
+
+                        break;
+                }
+        }
+
+        return ret;
+}
+
+static void relocate_rewrite_value(struct elf_info *info, Elf64_Rela *rel, void *loc)
+{
+        unsigned long val;
+
+        // GOT data offset to elf hdr
+        val = *(int *)loc - rel->r_addend + rel->r_offset;
+        val = (unsigned long)info->rodata_vhdr + val;
+        val = val - (unsigned long)loc + rel->r_addend;
+        memcpy(loc, &val, 4);
+}
+
+#if __has_attribute(__fallthrough__)
+# define fallthrough                    __attribute__((__fallthrough__))
+#else
+# define fallthrough                    do {} while (0)  /* fallthrough */
+#endif
+
+static int apply_relocate_add(Elf64_Shdr *shdr, struct elf_info *info)
+{
+        unsigned int i;
+        Elf64_Rela *rel_tab = (void *)shdr->sh_addr;
+        Elf64_Sym *sym;
+        void *loc;
+        int ret;
+
+        for (i = 0; i < shdr->sh_size / sizeof(Elf64_Rela); i++) {
+                Elf64_Rela *rel = rel_tab + i;
+                /* This is where to make the change */
+                loc = info->text_vhdr + rel->r_offset;
+                sym = (Elf64_Sym *)info->symsec->sh_addr + ELF64_R_SYM(rel->r_info);
+
+                _dl_debug_printf("HUGEPAGE: offset %lx, type %x, st_value %lx, r_addend %lx, loc %lx\n", (unsigned long)rel->r_offset, (int)ELF64_R_TYPE(rel->r_info), sym->st_value,
+                       rel->r_addend, (unsigned long)loc);
+
+                switch (ELF64_R_TYPE(rel->r_info)) {
+                case R_X86_64_NONE:
+                case R_X86_64_PLT32:
+                        break;
+                case R_X86_64_GOTPCRELX:
+                        // ff 15 00 00 00 00       callq  *0x00(%rip)
+                        ret = text_gen_insn(loc, (const void *)sym->st_value);
+                        if (ret == 0)
+                                break;
+                        // 48 83 3d d2 fe 5f 00    cmpq   $0x0,0x5ffed2(%rip)
+			relocate_rewrite_value(info, rel, loc);
+                        break;
+                case R_X86_64_PC32:
+                        // SHN_COMMON STT_FUNC no need reloc
+                        if (ELF64_ST_TYPE(sym->st_info) == STT_FUNC)
+                                break;
+                        // STT_OBJECT
+                        // TODO: direct mov, do not use lea
+                        fallthrough;
+                case R_X86_64_GOTPCREL:
+                case R_X86_64_REX_GOTPCRELX:
+                        // sym may not exist, change data offset
+			relocate_rewrite_value(info, rel, loc);
+                        break;
+                default:
+                        _dl_debug_printf("invalid relocation target, type %x, loc %lx\n",
+                               (int)ELF64_R_TYPE(rel->r_info), (unsigned long)loc);
+                        return -1;
+                }
+        }
+        return 0;
+}
+
+static int apply_relocations(struct elf_info *info)
+{
+        Elf64_Shdr *sechdrs = info->sechdrs;
+        char *secstrings = info->secstrings;
+        unsigned int shnum = info->hdr->e_shnum;
+        unsigned int i;
+        int err = 0;
+
+        for (i = 1; i < shnum; i++) {
+                Elf64_Shdr *shdr = &sechdrs[i];
+
+                /* Not a valid relocation section? */
+                if (shdr->sh_info >= shnum)
+                        continue;
+
+                if (shdr->sh_type == SHT_RELA) {
+                        const char *name = secstrings + shdr->sh_name;
+                        if ((strcmp(name, ".rela.text") != 0) && (strcmp(name, ".rela.init") != 0))
+                                continue;
+                        _dl_debug_printf("HUGEPAGE: relocation %s\n", name);
+                        err = apply_relocate_add(shdr, info);
+                }
+                if (err < 0)
+                        break;
+        }
+        return err;
+}
+
+static int read_elf_info(struct link_map *lmap)
+{
+	int fd = -1;
+        int ret;
+        unsigned int i;
+        unsigned int index_str;
+        Elf64_Ehdr *hdr = NULL;
+        Elf64_Shdr *sechdrs = NULL;
+        Elf64_Shdr *strhdr;
+        void *buf;
+	struct elf_info *info = &lmap->info;
+
+	_dl_debug_printf("\nHUGEPAGE: relocation: %s, elf_info 0x%lx, link_map 0x%lx\n", DSO_FILENAME(lmap->l_name), (unsigned long)info, (unsigned long)lmap);
+	fd = __open(DSO_FILENAME(lmap->l_name), O_RDONLY);
+	if (fd == -1) {
+		_dl_debug_printf("\nHUGEPAGE: open %s fail\n", DSO_FILENAME(lmap->l_name));
+		return -1;
+	}
+
+        ret = __lseek(fd, 0, SEEK_END);
+        buf = __mmap(0, ret, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+        _dl_debug_printf("\nHUGEPAGE: ELF len %u, addr 0x%lx\n", ret, (unsigned long)buf);
+
+        hdr = (Elf64_Ehdr *) buf;
+        sechdrs = (void *)hdr + hdr->e_shoff;
+
+        // session header name string table
+        strhdr = &sechdrs[hdr->e_shstrndx];
+        info->secstrings = (void *)hdr + strhdr->sh_offset;
+
+        // .symtab
+        for (i = 1; i < hdr->e_shnum; i++) {
+                if (sechdrs[i].sh_type == SHT_SYMTAB) {
+                        info->symsec = &sechdrs[i];
+                        index_str = sechdrs[i].sh_link;
+                        info->strtab = (char *)hdr + sechdrs[index_str].sh_offset;
+                        break;
+                }
+        }
+
+        info->hdr = hdr;
+        info->sechdrs = sechdrs;
+        info->strhdr = strhdr;
+
+	close(fd);
+        return 0;
+}
+
+void dl_map_new_addr(struct link_map *main_map)
+{
+	read_elf_info(main_map);
+        rewrite_section_headers(&main_map->info);
+        simplify_symbols(main_map, &main_map->info);
+        apply_relocations(&main_map->info);
+}
+
 static void
 dl_main (const ElfW(Phdr) *phdr,
 	 ElfW(Word) phnum,
@@ -1147,11 +1451,19 @@ of this helper program; chances are you did not intend to run this program.\n\
 	main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
 	break;
       case PT_DYNAMIC:
+
+// HUGEPAGE
+hugepage_use_rodata_vhdr(main_map);
+
 	/* This tells us where to find the dynamic section,
 	   which tells us everything we need to do.  */
 	main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
 	break;
       case PT_INTERP:
+
+// HUGEPAGE
+hugepage_use_elf_vhdr(main_map);
+
 	/* This "interpreter segment" was used by the program loader to
 	   find the program interpreter, which is this program itself, the
 	   dynamic linker.  We note what name finds us, so that a future
@@ -2296,6 +2608,10 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
   _dl_unload_cache ();
 #endif
 
+// HUGEPAGE
+dl_map_new_addr(main_map);
+_dl_debug_printf("\nHUGEPAGE: user_entry 0x%lx 0x%lx\n", (unsigned long)*user_entry, (unsigned long)main_map->l_entry);
+
   /* Once we return, _dl_sysdep_start will invoke
      the DT_INIT functions and then *USER_ENTRY.  */
 }
diff --git a/include/link.h b/include/link.h
index 83b1c34b..03d20d2d 100644
--- a/include/link.h
+++ b/include/link.h
@@ -80,6 +80,28 @@ struct r_search_path_struct
   };
 
 
+// HUGEPAGE
+struct elf_info {
+	Elf64_Ehdr *hdr;
+	Elf64_Shdr *sechdrs;
+	Elf64_Shdr *strhdr;
+	Elf64_Shdr *symsec;
+	char *secstrings;
+	char *strtab;
+
+	long text_begin;
+	long rodata_begin;
+	char *elf_vhdr;
+	char *text_vhdr;
+	char *rodata_vhdr;
+	char *data_vhdr;
+};
+
+#define LAYOUT_TEXT 0x1
+#define LAYOUT_RODATA 0x2
+#define LAYOUT_DATA 0x3
+
+
 /* Structure describing a loaded shared object.  The `l_next' and `l_prev'
    members form a chain of all the shared objects loaded at startup.
 
@@ -333,8 +355,58 @@ struct link_map
       uintptr_t cookie;
       unsigned int bindflags;
     } l_audit[0];
+
+	// HUGEPAGE
+	struct elf_info info;
   };
 
+static __always_inline void hugepage_use_vhdr(struct link_map *l, long offset)
+{
+	if (l->info.elf_vhdr == NULL) {
+		return;
+	}
+	if (offset < l->info.text_begin) {
+		l->l_addr = (ElfW(Addr))l->info.elf_vhdr;
+	} else 	if (offset < l->info.rodata_begin) {
+		l->l_addr = (ElfW(Addr))l->info.text_vhdr;
+	} else {
+		l->l_addr = (ElfW(Addr))l->info.rodata_vhdr;
+	}
+}
+
+static __always_inline void hugepage_use_elf_vhdr(struct link_map *l)
+{
+	if (l->info.elf_vhdr == NULL) {
+		return;
+	}
+	l->l_addr = (ElfW(Addr))l->info.elf_vhdr;
+}
+
+static __always_inline void hugepage_use_text_vhdr(struct link_map *l)
+{
+	if (l->info.elf_vhdr == NULL) {
+		return;
+	}
+	l->l_addr = (ElfW(Addr))l->info.text_vhdr;
+}
+
+static __always_inline void hugepage_use_rodata_vhdr(struct link_map *l)
+{
+	if (l->info.elf_vhdr == NULL) {
+		return;
+	}
+	l->l_addr = (ElfW(Addr))l->info.rodata_vhdr;
+}
+
+static __always_inline void hugepage_use_data_vhdr(struct link_map *l)
+{
+	if (l->info.elf_vhdr == NULL) {
+		return;
+	}
+	// TODO: split rodata and data
+	l->l_addr = (ElfW(Addr))l->info.rodata_vhdr;
+}
+
 
 #if __ELF_NATIVE_CLASS == 32
 # define symbind symbind32
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 1942ed50..8e3ac9c5 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -272,6 +272,9 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
   ElfW(Addr) *const reloc_addr = reloc_addr_arg;
   const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
 
+// HUGEPAGE
+hugepage_use_vhdr(map, (long)reloc->r_addend);
+
 # if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
   if (__glibc_unlikely (r_type == R_X86_64_RELATIVE))
     {
@@ -509,6 +512,10 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
 	  break;
 #  endif
 	case R_X86_64_IRELATIVE:
+// HUGEPAGE
+hugepage_use_text_vhdr(map);
+_dl_debug_printf("HUGEPAGE: linkmap 0x%lx, l_addr 0x%lx, reloc->r_addend 0x%lx\n", (unsigned long)map, (unsigned long)map->l_addr, (unsigned long)reloc->r_addend);
+
 	  value = map->l_addr + reloc->r_addend;
 	  value = ((ElfW(Addr) (*) (void)) value) ();
 	  *reloc_addr = value;
-- 
2.27.0

