From 54e4e9ad6e17d57d94ec082495f27afd1ecdad53 Mon Sep 17 00:00:00 2001 From: Zhou Kang Date: Tue, 8 Aug 2023 03:20:10 +0000 Subject: [PATCH] fix .rela.dyn process --- src/elf_hugepage.c | 2 +- src/elf_link_common.c | 18 ++++++-- src/elf_link_common.h | 29 ++++++++++++- src/elf_link_elf.c | 86 +++++++++++++++++++++++++------------ src/elf_read_elf.c | 6 +-- src/elf_read_elf.h | 2 +- src/elf_relocation.c | 21 +++++---- src/elf_relocation_x86_64.c | 2 +- tests/bash/Makefile | 2 +- 9 files changed, 118 insertions(+), 50 deletions(-) diff --git a/src/elf_hugepage.c b/src/elf_hugepage.c index feb3d70..5a23212 100644 --- a/src/elf_hugepage.c +++ b/src/elf_hugepage.c @@ -88,7 +88,7 @@ int elf_set_rto(char *path, bool state) void elf_set_hugepage(elf_link_t *elf_link) { int i, exec_only = 1; - elf_file_t *ef = &elf_link->out_ef; + elf_file_t *ef = get_out_ef(elf_link); int count = ef->hdr->e_phnum; Elf64_Phdr *phdr = (Elf64_Phdr *)ef->hdr_Phdr; diff --git a/src/elf_link_common.c b/src/elf_link_common.c index 02bc1ae..f66c73c 100644 --- a/src/elf_link_common.c +++ b/src/elf_link_common.c @@ -1026,7 +1026,7 @@ unsigned long get_new_name_offset(elf_link_t *elf_link, elf_file_t *src_ef, Elf6 return 0; } -int get_new_sym_index_no_clear(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index) +int get_new_sym_index(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index) { if (old_index == 0) { return 0; @@ -1034,10 +1034,10 @@ int get_new_sym_index_no_clear(elf_link_t *elf_link, elf_file_t *src_ef, unsigne const char *name = elf_get_dynsym_name_by_index(src_ef, old_index); - return find_dynsym_index_by_name(&elf_link->out_ef, name, false); + return elf_find_dynsym_index_by_name(&elf_link->out_ef, name); } -int get_new_sym_index(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index) +int get_new_sym_index_or_clear(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index) { if (old_index == 0) { return 0; @@ -1045,5 +1045,15 @@ int get_new_sym_index(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old const char *name = elf_get_dynsym_name_by_index(src_ef, old_index); - return find_dynsym_index_by_name(&elf_link->out_ef, name, true); + elf_file_t *out_ef = get_out_ef(elf_link); + Elf64_Sym *sym = elf_find_dynsym_by_name(out_ef, name); + if (sym == NULL) { + si_panic("%s\n", name); + } + + if (sym->st_shndx != 0) { + return NEED_CLEAR_RELA; + } + + return elf_get_dynsym_index(out_ef, sym); } diff --git a/src/elf_link_common.h b/src/elf_link_common.h index 9fbaebc..924400c 100644 --- a/src/elf_link_common.h +++ b/src/elf_link_common.h @@ -248,6 +248,33 @@ static inline bool is_need_preinit(elf_link_t *elf_link) return false; } +static inline bool is_gnu_hash_sec_name(const char *name) +{ + if (strcmp(name, ".gnu.hash") == 0) { + return true; + } + + return false; +} + +static inline bool is_dynsym_sec_name(const char *name) +{ + if (strcmp(name, ".dynsym") == 0) { + return true; + } + + return false; +} + +static inline bool is_gnu_version_r_sec_name(const char *name) +{ + if (strcmp(name, ".gnu.version_r") == 0) { + return true; + } + + return false; +} + static inline bool is_version_sec_name(const char *name) { // TODO: fix .gnu.version_d @@ -287,8 +314,8 @@ static inline void modify_elf_file(elf_link_t *elf_link, unsigned long loc, void // symbol bool is_symbol_maybe_undefined(const char *name); bool is_gnu_weak_symbol(Elf64_Sym *sym); -int get_new_sym_index_no_clear(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index); int get_new_sym_index(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index); +int get_new_sym_index_or_clear(elf_link_t *elf_link, elf_file_t *src_ef, unsigned int old_index); Elf64_Sym *elf_lookup_symbol_by_rela(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela *src_rela, elf_file_t **lookup_ef); // addr diff --git a/src/elf_link_elf.c b/src/elf_link_elf.c index 537b4b5..96a3acd 100644 --- a/src/elf_link_elf.c +++ b/src/elf_link_elf.c @@ -174,34 +174,50 @@ elf_file_t *elf_link_add_infile(elf_link_t *elf_link, char *path) return ef; } +static int get_new_sec_index_by_old(elf_link_t *elf_link, Elf64_Shdr *dst_sec, int old_index) +{ + if (old_index == 0) { + return 0; + } + + elf_obj_mapping_t *obj_mapping = elf_get_mapping_by_dst(elf_link, dst_sec); + elf_file_t *src_ef = obj_mapping->src_ef; + //Elf64_Shdr *src_sec = (Elf64_Shdr *)obj_mapping->src_obj; + + // is not section index, do not change + if (old_index >= src_ef->hdr->e_shnum) { + return old_index; + } + Elf64_Shdr *old_sec = &src_ef->sechdrs[old_index]; + Elf64_Shdr *new_sec = find_tmp_section_by_src(elf_link, old_sec); + if (new_sec == NULL) { + // old sec struct may not copy to dst + char *sec_name = elf_get_section_name(src_ef, old_sec); + new_sec = find_tmp_section_by_name(elf_link, sec_name); + if (new_sec == NULL) { + si_panic("find sec fail old %s %s\n", src_ef->file_name, sec_name); + } + } + + return new_sec - elf_link->out_ef.sechdrs; +} + +// .dynsym段是动态符号表, sh_info字段表示该段中符号表的第一个非本地符号的索引 +// .gnu.version_r段是用于动态链接的版本控制信息的段, sh_info指定了版本表中默认版本的索引 static void modify_section_link(elf_link_t *elf_link) { - elf_file_t *template_ef = get_template_ef(elf_link); - int count = template_ef->hdr->e_shnum; - int j = elf_link->out_ef.hdr->e_shnum; - Elf64_Shdr *find_sec = NULL; - Elf64_Shdr *src_sec = template_ef->sechdrs; + int out_sec_count = elf_link->out_ef.hdr->e_shnum; Elf64_Shdr *sec = NULL; // fix link - for (int i = 1; i < j; i++) { + for (int i = 1; i < out_sec_count; i++) { sec = &elf_link->out_ef.sechdrs[i]; - if (sec->sh_link != 0 && (int)sec->sh_link < count) { - find_sec = find_tmp_section_by_src(elf_link, &src_sec[sec->sh_link]); - if (find_sec == NULL) { - si_panic("find sec fail\n"); - } - sec->sh_link = find_sec - elf_link->out_ef.sechdrs; - } - if (sec->sh_info != 0 && (int)sec->sh_info < count) { - find_sec = find_tmp_section_by_src(elf_link, &src_sec[sec->sh_info]); - if (find_sec == NULL) { - // when .plt merge to .text, can not find .plt - sec->sh_info = 0; - continue; - } - sec->sh_info = find_sec - elf_link->out_ef.sechdrs; + sec->sh_link = get_new_sec_index_by_old(elf_link, sec, sec->sh_link); + char *name = elf_get_tmp_section_name(elf_link, sec); + if (is_dynsym_sec_name(name) || is_gnu_version_r_sec_name(name)) { + continue; } + sec->sh_info = get_new_sec_index_by_old(elf_link, sec, sec->sh_info); } } @@ -222,7 +238,7 @@ static void modify_PHDR_segment(elf_link_t *elf_link) static void modify_INTERP_segment(elf_link_t *elf_link) { - elf_file_t *out_ef = &elf_link->out_ef; + elf_file_t *out_ef = get_out_ef(elf_link); // INTERP segment is second segment Elf64_Phdr *p = &out_ef->segments[1]; @@ -241,7 +257,7 @@ static void modify_INTERP_segment(elf_link_t *elf_link) static void modify_GNU_EH_FRAME_segment(elf_link_t *elf_link) { - elf_file_t *out_ef = &elf_link->out_ef; + elf_file_t *out_ef = get_out_ef(elf_link); Elf64_Phdr *p = out_ef->frame_Phdr; if (p == NULL) { @@ -335,7 +351,12 @@ static void write_interp_and_note(elf_link_t *elf_link) Elf64_Shdr *end_sec = NULL; char *name = NULL; - begin_sec = elf_find_section_by_name(template_ef, ".interp"); + if (is_static_nolibc_mode(elf_link)) { + begin_sec = elf_find_section_by_name(template_ef, ".note.gnu.property"); + } else { + begin_sec = elf_find_section_by_name(template_ef, ".interp"); + } + // end is before .gnu.hash end_sec = elf_find_section_by_name(template_ef, ".gnu.hash"); @@ -349,7 +370,6 @@ static void write_interp_and_note(elf_link_t *elf_link) } } -// .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt static void write_first_LOAD_segment(elf_link_t *elf_link) { Elf64_Phdr *p = NULL; @@ -363,6 +383,7 @@ static void write_first_LOAD_segment(elf_link_t *elf_link) write_interp_and_note(elf_link); // first sec is .gnu.hash, end by SHF_EXECINSTR + // .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt Elf64_Shdr *sec = elf_find_section_by_name(template_ef, ".gnu.hash"); int i = sec - secs; for (; i < count; i++) { @@ -376,9 +397,16 @@ static void write_first_LOAD_segment(elf_link_t *elf_link) }*/ name = elf_get_section_name(template_ef, &secs[i]); - if (is_direct_call_optimize(elf_link) && (strcmp(name, ".rela.plt") == 0)) { + if (is_static_nold_mode(elf_link) && is_gnu_hash_sec_name(name)) { + merge_libc_ef_section(elf_link, name); + continue; + } + + if (is_static_nold_mode(elf_link) && is_dynsym_sec_name(name)) { + merge_libc_ef_section(elf_link, name); continue; } + if (is_version_sec_name(name)) { if (is_delete_symbol_version(elf_link) == false) { // nold mode copy from libc @@ -387,6 +415,10 @@ static void write_first_LOAD_segment(elf_link_t *elf_link) continue; } + if (is_direct_call_optimize(elf_link) && (strcmp(name, ".rela.plt") == 0)) { + continue; + } + merge_all_ef_section(elf_link, name); } @@ -701,8 +733,6 @@ static int dynamic_add_soname(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int le (void)dynamic_copy_dyn_by_type(elf_link, libc_ef, DT_SONAME, dst_dyn); len++; - printf("zk--- DT_SONAME \n"); - return len; } diff --git a/src/elf_read_elf.c b/src/elf_read_elf.c index 479c778..17d218c 100644 --- a/src/elf_read_elf.c +++ b/src/elf_read_elf.c @@ -175,17 +175,13 @@ Elf64_Sym *elf_find_dynsym_by_name(elf_file_t *ef, const char *name) return NULL; } -int find_dynsym_index_by_name(elf_file_t *ef, const char *name, bool clear) +int elf_find_dynsym_index_by_name(elf_file_t *ef, const char *name) { Elf64_Sym *sym = elf_find_dynsym_by_name(ef, name); if (sym == NULL) { si_panic("%s\n", name); } - if (clear && sym->st_shndx != 0) { - return NEED_CLEAR_RELA; - } - return elf_get_dynsym_index(ef, sym); } diff --git a/src/elf_read_elf.h b/src/elf_read_elf.h index 5e889c2..2d047bb 100644 --- a/src/elf_read_elf.h +++ b/src/elf_read_elf.h @@ -217,7 +217,7 @@ Elf64_Sym *elf_find_symbol_by_name(elf_file_t *ef, const char *sym_name); Elf64_Sym *elf_find_symbol_by_addr(elf_file_t *ef, unsigned long addr); unsigned long elf_find_symbol_addr_by_name(elf_file_t *ef, char *sym_name); Elf64_Sym *elf_find_dynsym_by_name(elf_file_t *ef, const char *name); -int find_dynsym_index_by_name(elf_file_t *ef, const char *name, bool clear); +int elf_find_dynsym_index_by_name(elf_file_t *ef, const char *name); char *elf_get_dynsym_name_by_index(elf_file_t *ef, unsigned int index); // rela diff --git a/src/elf_relocation.c b/src/elf_relocation.c index 4fee631..18633bc 100644 --- a/src/elf_relocation.c +++ b/src/elf_relocation.c @@ -228,10 +228,7 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * // modify offset dst_rela->r_offset = get_new_addr_by_old_addr(elf_link, src_ef, src_rela->r_offset); - // old sym index to new index of .dynsym unsigned int old_index = ELF64_R_SYM(src_rela->r_info); - int new_index = get_new_sym_index_no_clear(elf_link, src_ef, old_index); - dst_rela->r_info = ELF64_R_INFO(new_index, ELF64_R_TYPE(src_rela->r_info)); type = ELF64_R_TYPE(src_rela->r_info); switch (type) { @@ -245,12 +242,10 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * // 000000000000129d 0000006e0000002a R_X86_64_REX_GOTPCRELX 0000000000004000 ___g_so_path_list - 4 // 129a: 4c 8b 2d 4f 2d 00 00 mov 0x2d4f(%rip),%r13 # 3ff0 <___g_so_path_list@@Base-0x10> // 48: 0000000000004000 4096 OBJECT GLOBAL DEFAULT 27 ___g_so_path_list - new_index = ELF64_R_SYM(dst_rela->r_info); - const char *sym_name = elf_get_dynsym_name_by_index(&elf_link->out_ef, new_index); + const char *sym_name = elf_get_dynsym_name_by_index(src_ef, old_index); if (elf_is_same_symbol_name(sym_name, "___g_so_path_list")) { // when ELF load, real addr will set - dst_rela->r_info = ELF64_R_INFO(new_index, ELF64_R_TYPE(R_X86_64_RELATIVE)); - dst_rela->r_addend = (unsigned long)elf_link->so_path_struct; + rela_change_to_relative(dst_rela, (unsigned long)elf_link->so_path_struct); break; } } @@ -266,6 +261,8 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * // 14: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND _rtld_global@GLIBC_PRIVATE (37) if ((ELF64_ST_TYPE(sym->st_info) == STT_FUNC) || (ELF64_ST_TYPE(sym->st_info) == STT_OBJECT)) { modify_rela_to_RELATIVE(elf_link, src_ef, src_rela, dst_rela); + } else { + si_panic("error branch %s %lx\n", src_ef->file_name, src_rela->r_offset); } break; case R_X86_64_IRELATIVE: @@ -277,17 +274,19 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * if (!elf_is_rela_symbol_null(src_rela)) { si_panic("%s %lx\n", src_ef->file_name, src_rela->r_offset); } + // relative type have no sym index dst_rela->r_addend = get_new_addr_by_old_addr(elf_link, src_ef, src_rela->r_addend); break; case R_AARCH64_TLS_TPREL: // all TLS got entry will be modified directly when processing instructions later, // so no .dyn.rela entry is needed. - dst_rela->r_info = ELF64_R_INFO(0, R_AARCH64_NONE); + elf_clear_rela(dst_rela); break; case R_X86_64_TPOFF64: case R_X86_64_TPOFF32: // Offset in initial TLS block // 00000000001f0d78 0000000000000012 R_X86_64_TPOFF64 38 + // TLS type have no sym index dst_rela->r_addend = elf_get_new_tls_offset(elf_link, src_ef, src_rela->r_addend); break; case R_X86_64_COPY: @@ -296,6 +295,12 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * case R_AARCH64_COPY: // Variables in the bss section, some from glibc, some declared by the application // Redefined in the template file temporarily, so skip here + // TODO: is really do nothing? + { + int new_index = get_new_sym_index(elf_link, src_ef, old_index); + dst_rela->r_info = ELF64_R_INFO(new_index, ELF64_R_TYPE(src_rela->r_info)); + } + break; case R_AARCH64_NONE: /* nothing need to do */ break; diff --git a/src/elf_relocation_x86_64.c b/src/elf_relocation_x86_64.c index ae6b4fd..dc69c6b 100644 --- a/src/elf_relocation_x86_64.c +++ b/src/elf_relocation_x86_64.c @@ -438,7 +438,7 @@ void modify_rela_plt(elf_link_t *elf_link, si_array_t *arr) // old sym index to new index of .dynsym unsigned int old_index = ELF64_R_SYM(src_rela->r_info); - int new_index = get_new_sym_index_no_clear(elf_link, obj_rel->src_ef, old_index); + int new_index = get_new_sym_index(elf_link, obj_rel->src_ef, old_index); // func in this ELF need clear rela if (new_index == NEED_CLEAR_RELA) { elf_clear_rela(dst_rela); diff --git a/tests/bash/Makefile b/tests/bash/Makefile index 0effcf7..d494bcd 100644 --- a/tests/bash/Makefile +++ b/tests/bash/Makefile @@ -59,9 +59,9 @@ else # static-nolibc bash: clear + make -C $(ROOT_DIR) readelf -W -a $(TEMPLATE_FILE) > sysboost_static_template.elf objdump -d $(TEMPLATE_FILE) > sysboost_static_template.asm - make -C $(ROOT_DIR) xz $(TEMPLATE_FILE) mv -f $(TEMPLATE_FILE).xz $(TEMPLATE_FILE_PUB_PATH) @echo ===rto=== -- Gitee