diff --git a/elf/rtld.c b/elf/rtld.c

index 4abc6dd4..5b2e0583 100644

--- a/elf/rtld.c

+++ b/elf/rtld.c

@@ -861,6 +861,329 @@ handle_ld_preload (const char *preloadlist, struct link_map *main_map)

   return npreloads;

}

+

+// zk---

+struct elf_info {

+        Elf64_Ehdr *hdr;

+        Elf64_Shdr *sechdrs;

+        Elf64_Shdr *strhdr;

+        Elf64_Shdr *symsec;

+        char *secstrings;

+        char *strtab;

+        void *text_vhdr;

+        void *rodata_vhdr;

+       struct link_map *lmap;

+};

+

+#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;

+}

+

+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[256] = {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("symbol: 0x%lx %s\n", (long)sym->st_value, name);

+        return 0;

+}

+

+static int simplify_symbols(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(info->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("type %x st_value %lx r_addend %lx loc %lx\n", (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("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, struct elf_info *info)

+{

+       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;

+

+       _dl_debug_printf("\nzk--- relocation: %s, elf_info 0x%lx, link_map 0x%lx\n", DSO_FILENAME(lmap->l_name), (unsigned long)info, (unsigned long)lmap);

+       info->lmap = lmap;

+       fd = __open(DSO_FILENAME(lmap->l_name), O_RDONLY);

+       if (fd == -1) {

+                _dl_debug_printf("\nopen %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("\nELF 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;

+}

+

+// zk---

+void dl_map_new_addr(struct link_map *main_map, ElfW(Addr) *user_entry)

+{

+       ElfW(Addr) text_layout, rodata_layout;

+       struct elf_info info_buf = {0};

+       struct elf_info *info = &info_buf;

+        int i;

+        Elf64_Phdr *elf_ppnt, *elf_phdata;

+       void *load_addr;

+

+       text_layout = (ElfW(Addr)) __mmap(0, 0x40000000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(21 << MAP_HUGE_SHIFT), -1, 0);

+       rodata_layout = (ElfW(Addr)) __mmap(0, 0x40000000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|(21 << MAP_HUGE_SHIFT), -1, 0);

+

+       // cp text from ELF

+       read_elf_info(main_map, info);

+        load_addr = (void*)info->hdr;

+        elf_phdata = (Elf64_Phdr *)(load_addr + info->hdr->e_phoff);

+        for (i = 0, elf_ppnt = elf_phdata; i < info->hdr->e_phnum; i++, elf_ppnt++) {

+                if (elf_ppnt->p_type != PT_LOAD)

+                        continue;

+

+                // skip first LOAD segment

+                elf_ppnt++;

+                // text

+                info->text_vhdr = (void*)text_layout - elf_ppnt->p_offset;

+               _dl_debug_printf("\n old user_entry 0x%lx\n", (unsigned long)*user_entry);

+                *user_entry = (ElfW(Addr))info->text_vhdr + info->hdr->e_entry;

+               _dl_debug_printf("\n user_entry 0x%lx\n", (unsigned long)*user_entry);

+               _dl_debug_printf("\n text 0x%lx\n", (unsigned long)text_layout);

+                memcpy((void*)text_layout, load_addr + elf_ppnt->p_offset, elf_ppnt->p_filesz);

+                //main_map->l_text_end = text_layout + elf_ppnt->p_memsz;

+                // rodata

+                elf_ppnt++;

+                info->rodata_vhdr = (void*)rodata_layout - elf_ppnt->p_offset;

+               _dl_debug_printf("\n rodata dst 0x%lx src 0x%lx len 0x%lx\n", (unsigned long)rodata_layout, (unsigned long)main_map->l_addr + elf_ppnt->p_paddr, (unsigned long)elf_ppnt->p_memsz);

+                memcpy((void*)rodata_layout, (void*)main_map->l_addr + elf_ppnt->p_paddr, elf_ppnt->p_memsz);

+                // data

+                elf_ppnt++;

+                void *data_begin = (void*)rodata_layout + (elf_ppnt->p_paddr - (elf_ppnt - 1)->p_paddr);

+               _dl_debug_printf("\n data dst 0x%lx src 0x%lx len 0x%lx\n", (unsigned long)data_begin, (unsigned long)main_map->l_addr + elf_ppnt->p_paddr, (unsigned long)elf_ppnt->p_memsz);

+                memcpy(data_begin, (void*)main_map->l_addr + elf_ppnt->p_paddr, elf_ppnt->p_memsz);

+

+                break;

+        }

+

+        rewrite_section_headers(info);

+        simplify_symbols(info);

+        apply_relocations(info);

+}

+

static void

dl_main (const ElfW(Phdr) *phdr,

        ElfW(Word) phnum,

@@ -2296,6 +2619,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",

   _dl_unload_cache ();

#endif

+// zk---

+dl_map_new_addr(main_map, user_entry);

+

   /* Once we return, _dl_sysdep_start will invoke

      the DT_INIT functions and then *USER_ENTRY.  */

}