diff --git a/src/elf_link_common.c b/src/elf_link_common.c index b0ccc55e0060c5319013421febbdf392fb3b1295..02bc1aeeff744102f2150c72e0d35eda8a1fd50c 100644 --- a/src/elf_link_common.c +++ b/src/elf_link_common.c @@ -135,7 +135,7 @@ bool is_section_needed(elf_link_t *elf_link, elf_file_t *ef, Elf64_Shdr *sec) } if (is_delete_symbol_version(elf_link) == false) { - if (!strcmp(name, ".gnu.version") || !strcmp(name, ".gnu.version_r")) { + if (is_version_sec_name(name)) { return true; } } diff --git a/src/elf_link_common.h b/src/elf_link_common.h index 0d6047148e3f47e7bd12f8dcc725196e83052e69..9fbaebc1356092827a25e04db4a1d01ed2e253e4 100644 --- a/src/elf_link_common.h +++ b/src/elf_link_common.h @@ -152,6 +152,11 @@ static inline bool is_static_nolibc_mode(elf_link_t *elf_link) return elf_link->link_mode == ELF_LINK_STATIC_NOLIBC; } +// this mode merge all ELFs exclude ld.so +// ld.so parse env and parameter, rtld_global_ro share to libc.so +// ld.so have some init process for libc, soname need call libc.so +// ld.so will lookup some func by GUN_HASH, some section need like libc.so +// .gnu.hash .dynsym .gnu.version .gnu.version_d .gnu.version_r static inline bool is_static_nold_mode(elf_link_t *elf_link) { return elf_link->link_mode == ELF_LINK_STATIC_NOLD; @@ -234,7 +239,21 @@ static inline bool is_preinit_name(const char *name) // __libc_early_init(true) static inline bool is_need_preinit(elf_link_t *elf_link) { - if (is_static_nold_mode(elf_link)) { + // TODO: clean this + (void)elf_link; + //if (is_static_nold_mode(elf_link)) { + // return true; + //} + + return false; +} + +static inline bool is_version_sec_name(const char *name) +{ + // TODO: fix .gnu.version_d + //if ((strcmp(name, ".gnu.version") == 0) || (strcmp(name, ".gnu.version_r") == 0) + // || (strcmp(name, ".gnu.version_d") == 0)) { + if ((strcmp(name, ".gnu.version") == 0) || (strcmp(name, ".gnu.version_r") == 0)) { return true; } diff --git a/src/elf_link_elf.c b/src/elf_link_elf.c index 65f3267e9f84eeea519fa1a671217eae7a058565..537b4b5f326b6cf351167a9bb5cbd97732c24a49 100644 --- a/src/elf_link_elf.c +++ b/src/elf_link_elf.c @@ -113,6 +113,10 @@ int elf_link_set_mode(elf_link_t *elf_link, unsigned int mode) SI_LOG_ERR("elf_read_file fail, %s\n", LD_SO_PATH); return -1; } + + // in this mode, ld.so lookup libc sym need symbol version + elf_link->delete_symbol_version = false; + // in this mode, ld.so and vdso layout must fixed elf_link->direct_vdso_optimize = true; return 0; @@ -375,8 +379,11 @@ static void write_first_LOAD_segment(elf_link_t *elf_link) if (is_direct_call_optimize(elf_link) && (strcmp(name, ".rela.plt") == 0)) { continue; } - if (is_delete_symbol_version(elf_link) && ((strcmp(name, ".gnu.version")) == 0 - || (strcmp(name, ".gnu.version_r")) == 0)) { + if (is_version_sec_name(name)) { + if (is_delete_symbol_version(elf_link) == false) { + // nold mode copy from libc + merge_libc_ef_section(elf_link, name); + } continue; } @@ -601,19 +608,16 @@ static bool is_lib_had_insert(elf_link_t *elf_link, char *name, Elf64_Dyn *dyn_a static int dynamic_merge_lib_one(elf_link_t *elf_link, elf_file_t *ef, Elf64_Dyn *begin_dyn, int len) { - Elf64_Shdr *sec = NULL; - Elf64_Dyn *dyn_arr = NULL; Elf64_Dyn *dyn = NULL; - Elf64_Dyn *dst_dyn = NULL; - int dyn_count = 0; - sec = elf_find_section_by_name(ef, ".dynamic"); + Elf64_Shdr *sec = elf_find_section_by_name(ef, ".dynamic"); if (sec == NULL) { return len; } - dyn_arr = ((void *)ef->hdr) + sec->sh_offset; - dyn_count = sec->sh_size / sec->sh_entsize; - dst_dyn = &begin_dyn[len]; + + Elf64_Dyn *dyn_arr = elf_get_section_data(ef, sec); + int dyn_count = sec->sh_size / sizeof(Elf64_Dyn); + Elf64_Dyn *dst_dyn = &begin_dyn[len]; for (int j = 0; j < dyn_count; j++) { dyn = &dyn_arr[j]; if (dyn->d_tag != DT_NEEDED) { @@ -655,6 +659,53 @@ static int dynamic_merge_lib(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len return len; } +static void dynamic_copy_dyn(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Dyn *src_dyn, Elf64_Dyn *dst_dyn) +{ + dst_dyn->d_tag = src_dyn->d_tag; + dst_dyn->d_un.d_val = get_new_name_offset(elf_link, src_ef, src_ef->dynstr_sec, src_dyn->d_un.d_val); +} + +static Elf64_Dyn *dynamic_copy_dyn_by_type(elf_link_t *elf_link, elf_file_t *src_ef, unsigned long dt, Elf64_Dyn *dst_dyn) +{ + Elf64_Dyn *src_dyn = elf_find_dyn_by_type(src_ef, dt); + if (src_dyn == NULL) { + si_panic("need dyn %lu\n", dt); + return NULL; + } + + dynamic_copy_dyn(elf_link, src_ef, src_dyn, dst_dyn); + return dst_dyn; +} + +// .dynamic is merge all elf, so mem space is enough +// libc is merge to APP, so let libc_map = main_map in dl_main() +static int dynamic_add_soname(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len) +{ + if (!is_static_nold_mode(elf_link)) { + return len; + } + + elf_file_t *libc_ef = get_libc_ef(elf_link); + if (libc_ef == NULL) { + si_panic("need libc.so\n"); + return len; + } + + // 0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2] + Elf64_Dyn *dst_dyn = &begin_dyn[len]; + (void)dynamic_copy_dyn_by_type(elf_link, libc_ef, DT_NEEDED, dst_dyn); + len++; + + // 0x000000000000000e (SONAME) Library soname: [libc.so.6] + dst_dyn++; + (void)dynamic_copy_dyn_by_type(elf_link, libc_ef, DT_SONAME, dst_dyn); + len++; + + printf("zk--- DT_SONAME \n"); + + return len; +} + // .dynamic is merge all elf, so mem space is enough static int dynamic_add_preinit(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len) { @@ -793,6 +844,9 @@ static void scan_dynamic(elf_link_t *elf_link) begin_dyn = ((void *)elf_link->out_ef.hdr) + tmp_sec->sh_offset; len = dynamic_merge_lib(elf_link, begin_dyn, len); + // DT_SONAME + len = dynamic_add_soname(elf_link, begin_dyn, len); + // DT_PREINIT_ARRAY len = dynamic_add_preinit(elf_link, begin_dyn, len); diff --git a/src/elf_read_elf.c b/src/elf_read_elf.c index bda80ca7be611135b057b9aa7b86faca3039ba0b..479c778f6c9d6e4b265e728a62d5a7910a442b1f 100644 --- a/src/elf_read_elf.c +++ b/src/elf_read_elf.c @@ -293,6 +293,27 @@ unsigned long elf_va_to_offset(elf_file_t *ef, unsigned long va) return -1; } +Elf64_Dyn *elf_find_dyn_by_type(elf_file_t *ef, unsigned long dt) +{ + Elf64_Dyn *dyn = NULL; + + Elf64_Shdr *sec = elf_find_section_by_name(ef, ".dynamic"); + if (sec == NULL) { + return NULL; + } + + Elf64_Dyn *dyn_arr = elf_get_section_data(ef, sec); + int dyn_count = sec->sh_size / sizeof(Elf64_Dyn); + for (int j = 0; j < dyn_count; j++) { + dyn = &dyn_arr[j]; + if (dyn->d_tag == (Elf64_Sxword)dt) { + return dyn; + } + } + + return NULL; +} + Elf64_Shdr *elf_find_section_by_addr(elf_file_t *ef, unsigned long addr) { Elf64_Shdr *sechdrs = ef->sechdrs; diff --git a/src/elf_read_elf.h b/src/elf_read_elf.h index bfd4af50eadc356f02e492b6a5e1904ed26c417c..5e889c2b41f281f90cd742f4a9943182110db578 100644 --- a/src/elf_read_elf.h +++ b/src/elf_read_elf.h @@ -223,6 +223,9 @@ char *elf_get_dynsym_name_by_index(elf_file_t *ef, unsigned int index); // rela Elf64_Rela *elf_get_rela_by_addr(elf_file_t *ef, unsigned long addr); +// dyn +Elf64_Dyn *elf_find_dyn_by_type(elf_file_t *ef, unsigned long dt); + // section Elf64_Shdr *elf_find_section_by_tls_offset(elf_file_t *ef, unsigned long obj_tls_offset); Elf64_Shdr *elf_find_section_by_name(elf_file_t *ef, const char *sec_name); diff --git a/src/elf_write_elf.c b/src/elf_write_elf.c index eb2e4f79cfad0763179edf7b8b63316c4d91ace1..6c0f975d8efb7ba5052e3fe0b0e7734800803f8f 100644 --- a/src/elf_write_elf.c +++ b/src/elf_write_elf.c @@ -392,9 +392,8 @@ static void merge_section(elf_link_t *elf_link, Elf64_Shdr *dst_sec, elf_file_t dst_sec->sh_size = elf_link->next_mem_addr - dst_sec->sh_addr; } -void merge_template_ef_section(elf_link_t *elf_link, const char *sec_name) +static void merge_ef_section_by_name(elf_link_t *elf_link, elf_file_t *ef, const char *sec_name) { - elf_file_t *ef = get_template_ef(elf_link); Elf64_Shdr *sec = elf_find_section_by_name(ef, sec_name); Elf64_Shdr *dst_sec = add_tmp_section(elf_link, ef, sec); if (dst_sec == NULL) { @@ -406,6 +405,22 @@ void merge_template_ef_section(elf_link_t *elf_link, const char *sec_name) sec_name, dst_sec->sh_addr, dst_sec->sh_offset, dst_sec->sh_size); } +void merge_libc_ef_section(elf_link_t *elf_link, const char *sec_name) +{ + elf_file_t *libc_ef = get_libc_ef(elf_link); + if (libc_ef == NULL) { + si_panic("need libc.so\n"); + } + + merge_ef_section_by_name(elf_link, libc_ef, sec_name); +} + +void merge_template_ef_section(elf_link_t *elf_link, const char *sec_name) +{ + elf_file_t *ef = get_template_ef(elf_link); + merge_ef_section_by_name(elf_link, ef, sec_name); +} + static void merge_filter_section(elf_link_t *elf_link, Elf64_Shdr *dst_sec, elf_file_t *ef, section_filter_func filter) { int count = ef->hdr->e_shnum; diff --git a/src/elf_write_elf.h b/src/elf_write_elf.h index 609519f78fe9f755299316649aa95cbe8ba9a1b5..9d05da29322fdf9c73c7cf8e9e2137518a6b0f78 100644 --- a/src/elf_write_elf.h +++ b/src/elf_write_elf.h @@ -43,6 +43,7 @@ void merge_rodata_sections(elf_link_t *elf_link); void merge_data_relro_sections(elf_link_t *elf_link); void merge_rwdata_sections(elf_link_t *elf_link); +void merge_libc_ef_section(elf_link_t *elf_link, const char *sec_name); void merge_template_ef_section(elf_link_t *elf_link, const char *sec_name); Elf64_Shdr *merge_all_ef_section(elf_link_t *elf_link, const char *name); diff --git a/tests/bash/Makefile b/tests/bash/Makefile index f9c266d9db20b093540cea2ba991bb5a46581c6c..0effcf7e00a7d04504f9685ba4c702256cc952ce 100644 --- a/tests/bash/Makefile +++ b/tests/bash/Makefile @@ -92,5 +92,9 @@ env: objdump -d $(LIBLD) > ld.so.asm LD_DEBUG=all $(BASH) -c "echo 1" &> bash.ld.log +# test dlopen load so +ld: + gdb --args env LD_DEBUG=all $(BASH).rto + clean: $(RM) *.o *.ro *.old *.so *.asm *.elf *.rto *.out *.log