diff --git a/src/elf_link_common.c b/src/elf_link_common.c index f66c73cfff1d434552da7a16db542bb92a38c6a0..51c0cf0791cb1b473d5068b0dfd2a13fca30b6ff 100644 --- a/src/elf_link_common.c +++ b/src/elf_link_common.c @@ -123,7 +123,7 @@ bool is_section_needed(elf_link_t *elf_link, elf_file_t *ef, Elf64_Shdr *sec) // no use .plt, so delete .rela.plt if (is_direct_call_optimize(elf_link) == true) { - if (!strcmp(name, ".rela.plt")) { + if (elf_is_rela_plt_name(name)) { return false; } } @@ -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 (is_version_sec_name(name)) { + if (elf_is_version_sec(sec)) { return true; } } @@ -146,9 +146,6 @@ bool is_section_needed(elf_link_t *elf_link, elf_file_t *ef, Elf64_Shdr *sec) TODO: clean code, below is original implementation, don't have any effect now if ((sec->sh_type == SHT_RELA) && (!(sec->sh_flags & SHF_ALLOC))) return false; - if (sec->sh_type == SHT_GNU_versym || sec->sh_type == SHT_GNU_verdef || - sec->sh_type == SHT_GNU_verneed) - return false; if (elf_is_debug_section(ef, sec)) return false; diff --git a/src/elf_link_common.h b/src/elf_link_common.h index 924400c9a21920e9103ad75a250137058e0488fc..befe1257775fc0705d2fc4d3c43021ee168a913d 100644 --- a/src/elf_link_common.h +++ b/src/elf_link_common.h @@ -131,6 +131,13 @@ typedef struct { void *dst_obj; } elf_obj_mapping_t; +typedef Elf64_Shdr *(*meger_section_func)(elf_link_t *elf_link, const char *sec_name); + +typedef struct { + const char *sec_name; + meger_section_func func; +} elf_section_t; + static inline bool is_share_mode(elf_link_t *elf_link) { return elf_link->link_mode == ELF_LINK_SHARE; @@ -214,75 +221,55 @@ static inline elf_file_t *get_libc_ef(elf_link_t *elf_link) return elf_link->libc_ef; } -static inline bool is_init_name(const char *name) -{ - if (strcmp(name, ".init_array") == 0) { - return true; - } - - return false; -} -static inline bool is_preinit_name(const char *name) +static inline bool is_rela_plt_name(const char *name) { - if (strcmp(name, ".preinit_array") == 0) { + if (strcmp(name, ".rela.plt") == 0) { return true; } return false; } -// libc _init_first is in .init_array, must run before _start, move _init_first to .preinit_array -// libc __libc_early_init need init before .init_array, so put first of .preinit_array -// dl_main(phdr, phnum, user_entry, auxv) -// _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true); -// __libc_early_init(true) -static inline bool is_need_preinit(elf_link_t *elf_link) -{ - // TODO: clean this - (void)elf_link; - //if (is_static_nold_mode(elf_link)) { - // return true; - //} - - return false; -} - -static inline bool is_gnu_hash_sec_name(const char *name) +static inline bool is_rela_dyn_name(const char *name) { - if (strcmp(name, ".gnu.hash") == 0) { + if (strcmp(name, ".rela.dyn") == 0) { return true; } return false; } -static inline bool is_dynsym_sec_name(const char *name) +static inline bool is_init_name(const char *name) { - if (strcmp(name, ".dynsym") == 0) { + if (strcmp(name, ".init_array") == 0) { return true; } return false; } -static inline bool is_gnu_version_r_sec_name(const char *name) +static inline bool is_preinit_name(const char *name) { - if (strcmp(name, ".gnu.version_r") == 0) { + if (strcmp(name, ".preinit_array") == 0) { return true; } return false; } -static inline bool is_version_sec_name(const char *name) +// libc _init_first is in .init_array, must run before _start, move _init_first to .preinit_array +// libc __libc_early_init need init before .init_array, so put first of .preinit_array +// dl_main(phdr, phnum, user_entry, auxv) +// _dl_call_libc_early_init (GL(dl_ns)[LM_ID_BASE].libc_map, true); +// __libc_early_init(true) +static inline bool is_need_preinit(elf_link_t *elf_link) { - // 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; - } + // TODO: clean this + (void)elf_link; + //if (is_static_nold_mode(elf_link)) { + // return true; + //} return false; } diff --git a/src/elf_link_elf.c b/src/elf_link_elf.c index c71c3df5fb4e1ebf95ccc1344f466d48b580d622..d8a2cb11197653b6ed7785926a9a73d28935cdcb 100644 --- a/src/elf_link_elf.c +++ b/src/elf_link_elf.c @@ -204,20 +204,30 @@ static int get_new_sec_index_by_old(elf_link_t *elf_link, Elf64_Shdr *dst_sec, i // .dynsym段是动态符号表, sh_info字段表示该段中符号表的第一个非本地符号的索引 // .gnu.version_r段是用于动态链接的版本控制信息的段, sh_info指定了版本表中默认版本的索引 +// .gnu.version_d段, sh_info表示自定义version个数 +static bool elf_is_need_fix_sh_info(Elf64_Shdr *sec) +{ + // SHT_RELA sh_info is index of text code section + if (sec->sh_type == SHT_RELA) { + return true; + } + + return false; +} + static void modify_section_link(elf_link_t *elf_link) { int out_sec_count = elf_link->out_ef.hdr->e_shnum; Elf64_Shdr *sec = NULL; - // fix link + // fix sh_link and sh_info for (int i = 1; i < out_sec_count; i++) { sec = &elf_link->out_ef.sechdrs[i]; 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; + + if (elf_is_need_fix_sh_info(sec)) { + sec->sh_info = get_new_sec_index_by_old(elf_link, sec, sec->sh_info); } - sec->sh_info = get_new_sec_index_by_old(elf_link, sec, sec->sh_info); } } @@ -342,87 +352,77 @@ static void write_sysboost_section(elf_link_t *elf_link) }*/ // main ELF and libc.so have .interp, need to ignore it -// .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag -static void write_interp_and_note(elf_link_t *elf_link) -{ - elf_file_t *template_ef = get_template_ef(elf_link); - Elf64_Shdr *sec = NULL; - Elf64_Shdr *begin_sec = NULL; - Elf64_Shdr *end_sec = NULL; - char *name = NULL; - - if (is_static_nolibc_mode(elf_link)) { - begin_sec = elf_find_section_by_name(template_ef, ".note.gnu.property"); - if (begin_sec == NULL) - begin_sec = elf_find_section_by_name(template_ef, ".note.gnu.build-id"); - } 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"); - - if (begin_sec == NULL || end_sec == NULL) { - si_panic("section not found\n"); - } +// .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt +static elf_section_t hdr_segment_section_arr[] = { + {".interp", merge_template_ef_section}, + {".note.gnu.property", merge_template_ef_section}, + {".note.gnu.build-id", merge_template_ef_section}, + {".note.ABI-tag", merge_template_ef_section}, + {".gnu.hash", merge_all_ef_section}, + {".dynsym", merge_all_ef_section}, + {".dynstr", merge_all_ef_section}, + {".gnu.version", NULL}, + {".gnu.version_d", NULL}, + {".gnu.version_r", NULL}, + {".rela.dyn", merge_all_ef_section}, + {".rela.plt", merge_all_ef_section}, +}; +#define HDR_SEGMENT_SECTION_ARR_LEN (sizeof(hdr_segment_section_arr) / sizeof(hdr_segment_section_arr[0])) - for (sec = begin_sec; sec < end_sec; sec = sec + 1) { - name = elf_get_section_name(template_ef, sec); - merge_template_ef_section(elf_link, name); +static void write_hdr_segment_section_arr(elf_link_t *elf_link) +{ + for (unsigned i = 0; i < HDR_SEGMENT_SECTION_ARR_LEN; i++) { + elf_section_t *sec_obj = &hdr_segment_section_arr[i]; + if (sec_obj->func == NULL) { + continue; + } + sec_obj->func(elf_link, sec_obj->sec_name); } } -static void write_first_LOAD_segment(elf_link_t *elf_link) +static void fix_section_merge_func(elf_link_t *elf_link) { - Elf64_Phdr *p = NULL; - char *name = NULL; - elf_file_t *template_ef = get_template_ef(elf_link); - int count = template_ef->hdr->e_shnum; - Elf64_Shdr *secs = template_ef->sechdrs; - - // main ELF and libc.so have .interp, need to ignore it - // .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag - 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++) { - if (secs[i].sh_flags & SHF_EXECINSTR) { - break; - } - - // write after NOTE section, so it can load in first PAGE memory - /*if ((sechdrs[i - 1].sh_type == SHT_NOTE) && (sechdrs[i].sh_type != SHT_NOTE)) { - write_sysboost_section(elf_link); - }*/ + for (unsigned i = 0; i < HDR_SEGMENT_SECTION_ARR_LEN; i++) { + elf_section_t *sec_obj = &hdr_segment_section_arr[i]; - name = elf_get_section_name(template_ef, &secs[i]); - if (is_static_nold_mode(elf_link) && is_gnu_hash_sec_name(name)) { - merge_libc_ef_section(elf_link, name); + // .gnu.hash + if (is_static_nold_mode(elf_link) && elf_is_gnu_hash_sec_name(sec_obj->sec_name)) { + sec_obj->func = merge_libc_ef_section; continue; } - if (is_static_nold_mode(elf_link) && is_dynsym_sec_name(name)) { - merge_libc_ef_section(elf_link, name); + // .dynsym + if (is_static_nold_mode(elf_link) && elf_is_dynsym_sec_name(sec_obj->sec_name)) { + sec_obj->func = merge_libc_ef_section; continue; } - if (is_version_sec_name(name)) { + // .gnu.version .gnu.version_d .gnu.version_r + if (elf_is_version_sec_name(sec_obj->sec_name)) { if (is_delete_symbol_version(elf_link) == false) { // nold mode copy from libc - merge_libc_ef_section(elf_link, name); + sec_obj->func = merge_libc_ef_section; + continue; } - continue; } - if (is_direct_call_optimize(elf_link) && (strcmp(name, ".rela.plt") == 0)) { + if (is_direct_call_optimize(elf_link) && elf_is_rela_plt_name(sec_obj->sec_name)) { + sec_obj->func = NULL; continue; } - - merge_all_ef_section(elf_link, name); } +} + +// .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt +static void write_first_LOAD_segment(elf_link_t *elf_link) +{ + fix_section_merge_func(elf_link); + write_hdr_segment_section_arr(elf_link); + + // write after NOTE section, so it can load in first PAGE memory + /*if ((sechdrs[i - 1].sh_type == SHT_NOTE) && (sechdrs[i].sh_type != SHT_NOTE)) { + write_sysboost_section(elf_link); + }*/ // after merge section, .dynstr put new addr Elf64_Shdr *tmp_sec = find_tmp_section_by_name(elf_link, ".dynstr"); @@ -437,7 +437,7 @@ static void write_first_LOAD_segment(elf_link_t *elf_link) // first LOAD segment elf_file_t *out_ef = &elf_link->out_ef; - p = out_ef->hdr_Phdr; + Elf64_Phdr *p = out_ef->hdr_Phdr; p->p_filesz = elf_link->next_file_offset; p->p_memsz = p->p_filesz; p->p_align = SI_HUGEPAGE_ALIGN_SIZE; @@ -696,7 +696,27 @@ static int dynamic_merge_lib(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int 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); + + switch (src_dyn->d_tag) { + case DT_NEEDED: + case DT_SONAME: + // fix name index + dst_dyn->d_un.d_val = get_new_name_offset(elf_link, src_ef, src_ef->dynstr_sec, src_dyn->d_un.d_val); + break; + case DT_VERDEF: + case DT_VERNEED: + case DT_VERSYM: + dst_dyn->d_un.d_val = get_new_addr_by_old_addr(elf_link, src_ef, src_dyn->d_un.d_val); + break; + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + // do not change nr, just copy from libc + dst_dyn->d_un.d_val = src_dyn->d_un.d_val; + break; + default: + si_panic("error dyn %lu\n", dst_dyn->d_tag); + break; + } } 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) @@ -711,9 +731,27 @@ static Elf64_Dyn *dynamic_copy_dyn_by_type(elf_link_t *elf_link, elf_file_t *src return dst_dyn; } +// 0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2] +// 0x000000000000000e (SONAME) Library soname: [libc.so.6] +// 0x000000006ffffffc (VERDEF) 0x23a70 +// 0x000000006ffffffd (VERDEFNUM) 36 +// 0x000000006ffffffe (VERNEED) 0x23f70 +// 0x000000006fffffff (VERNEEDNUM) 1 +// 0x000000006ffffff0 (VERSYM) 0x222de +static unsigned long libc_dt_arr[] = { + DT_NEEDED, + DT_SONAME, + DT_VERDEF, + DT_VERDEFNUM, + DT_VERNEED, + DT_VERNEEDNUM, + DT_VERSYM, +}; +#define LIBC_DT_ARR_LEN (sizeof(libc_dt_arr) / sizeof(libc_dt_arr[0])) + // .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) +static int dynamic_add_obj_from_libc(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len) { if (!is_static_nold_mode(elf_link)) { return len; @@ -725,15 +763,12 @@ static int dynamic_add_soname(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int le 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++; + for (unsigned i = 0; i < LIBC_DT_ARR_LEN; i++) { + (void)dynamic_copy_dyn_by_type(elf_link, libc_ef, libc_dt_arr[i], dst_dyn); + len++; + dst_dyn++; + } return len; } @@ -777,17 +812,18 @@ static int dynamic_copy_obj(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len) dyn = &dyn_arr[i]; switch (dyn->d_tag) { case DT_NEEDED: + case DT_SONAME: + case DT_VERDEF: + case DT_VERNEED: + case DT_VERSYM: + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + // have done before, here do nothing continue; case DT_RUNPATH: // fix name index new_d_val = get_new_name_offset(elf_link, ef, ef->dynstr_sec, dyn->d_un.d_val); break; - case DT_VERNEED: - case DT_VERSYM: - if (is_delete_symbol_version(elf_link)) { - continue; - } - fallthrough; case DT_INIT: case DT_FINI: case DT_GNU_HASH: @@ -845,12 +881,6 @@ static int dynamic_copy_obj(elf_link_t *elf_link, Elf64_Dyn *begin_dyn, int len) sec = find_tmp_section_by_name(elf_link, ".fini_array"); new_d_val = sec->sh_size; break; - case DT_VERNEEDNUM: - if (is_delete_symbol_version(elf_link)) { - continue; - } - // TODO: feature, symbol version DT_VERNEEDNUM - fallthrough; default: *dst_dyn = *dyn; dst_dyn++; @@ -877,7 +907,7 @@ static void scan_dynamic(elf_link_t *elf_link) len = dynamic_merge_lib(elf_link, begin_dyn, len); // DT_SONAME - len = dynamic_add_soname(elf_link, begin_dyn, len); + len = dynamic_add_obj_from_libc(elf_link, begin_dyn, len); // DT_PREINIT_ARRAY len = dynamic_add_preinit(elf_link, begin_dyn, len); @@ -1312,7 +1342,7 @@ static void do_special_adapts(elf_link_t *elf_link) // .data .tm_clone_table __libc_subfreeres __libc_IO_vtables __libc_atexit .bss __libc_freeres_ptrs static void elf_link_write_sections(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 + // .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt write_first_LOAD_segment(elf_link); // .init .plt .text __libc_freeres_fn .fini diff --git a/src/elf_read_elf.h b/src/elf_read_elf.h index e68125b305aab39fbbfec806af3daef6b6a11aa8..638fa3314dc821d6ec620b2fa9ae5dd647d0ff2b 100644 --- a/src/elf_read_elf.h +++ b/src/elf_read_elf.h @@ -233,10 +233,86 @@ static inline bool elf_rela_is_relative(Elf64_Rela *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 +static inline bool elf_is_rela_plt_name(const char *name) +{ + if (strcmp(name, ".rela.plt") == 0) { + return true; + } + + return false; +} + +static inline bool elf_is_dynstr_name(const char *name) +{ + if (strcmp(name, ".dynstr") == 0) { + return true; + } + + return false; +} + +static inline bool elf_is_dynsym_sec_name(const char *name) +{ + if (strcmp(name, ".dynsym") == 0) { + return true; + } + + return false; +} + +static inline bool elf_is_gnu_hash_sec_name(const char *name) +{ + if (strcmp(name, ".gnu.hash") == 0) { + return true; + } + + return false; +} + +static inline bool elf_is_gnu_hash_sec(Elf64_Shdr *sec) +{ + if (sec->sh_type == SHT_GNU_HASH) { + return true; + } + + return false; +} + +static inline bool elf_is_dynsym_sec(Elf64_Shdr *sec) +{ + if (sec->sh_type == SHT_DYNSYM) { + return true; + } + + return false; +} + +static inline bool elf_is_version_sec_name(const char *name) +{ + if ((strcmp(name, ".gnu.version") == 0) || (strcmp(name, ".gnu.version_r") == 0) + || (strcmp(name, ".gnu.version_d") == 0)) { + return true; + } + + return false; +} + +static inline bool elf_is_version_sec(Elf64_Shdr *sec) +{ + if (sec->sh_type == SHT_GNU_versym || sec->sh_type == SHT_GNU_verdef || + sec->sh_type == SHT_GNU_verneed) { + return true; + } + + return false; +} + 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); Elf64_Shdr *elf_find_section_by_addr(elf_file_t *ef, unsigned long addr); diff --git a/src/elf_write_elf.c b/src/elf_write_elf.c index 6c0f975d8efb7ba5052e3fe0b0e7734800803f8f..cd8ec899557a53450a6b7a3afe0a7e263fa9252f 100644 --- a/src/elf_write_elf.c +++ b/src/elf_write_elf.c @@ -271,14 +271,69 @@ static void preinit_add_libc_early_init(elf_link_t *elf_link) write_elf_file(elf_link, &new_sym_addr, sizeof(unsigned long)); } +static void record_rela_arr(elf_link_t *elf_link, elf_file_t *ef, Elf64_Shdr *sec, void *dst) +{ + si_array_t *arr = NULL; + char *name = elf_get_section_name(ef, sec); + + void *src = ((void *)ef->hdr) + sec->sh_offset; + + if (is_rela_plt_name(name)) { + arr = elf_link->rela_plt_arr; + } else if (is_rela_dyn_name(name)) { + arr = elf_link->rela_dyn_arr; + } else { + return; + } + + int obj_nr = sec->sh_size / sec->sh_entsize; + for (int j = 0; j < obj_nr; j++) { + elf_obj_mapping_t obj_rel = {0}; + obj_rel.src_ef = ef; + obj_rel.src_sec = sec; + obj_rel.src_obj = src; + obj_rel.dst_obj = dst; + si_array_append(arr, &obj_rel); + src = src + sec->sh_entsize; + dst = dst + sec->sh_entsize; + } +} + +static unsigned long elf_get_sh_size(elf_link_t *elf_link, Elf64_Shdr *tmp_sec) +{ + if (tmp_sec->sh_flags & SHF_ALLOC) { + // .text .bss + return elf_link->next_mem_addr - tmp_sec->sh_addr; + } else { + // .symtab is not ALLOC, so not need mem addr + // it is at end of file, it get mem space is OK too + return elf_link->next_file_offset - tmp_sec->sh_offset; + } +} + +static bool is_merge_libc_first(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, const char *name) +{ + if (!is_static_nold_mode(elf_link)) { + return false; + } + + if (elf_is_dynsym_sec(tmp_sec)) { + return true; + } + + if (elf_is_dynstr_name(name)) { + return true; + } + + return false; +} + static Elf64_Shdr *elf_merge_section(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, const char *name, bool skip_main_ef) { - elf_file_t *ef; + elf_file_t *ef = NULL; int in_ef_nr = elf_link->in_ef_nr; Elf64_Shdr *sec = NULL; - elf_obj_mapping_t obj_rel = {0}; void *dst = NULL; - si_array_t *arr = NULL; elf_file_t *main_ef = get_main_ef(elf_link); bool is_preinit = is_need_preinit(elf_link) && is_preinit_name(name); char *l_name = (char*)name; @@ -291,6 +346,16 @@ static Elf64_Shdr *elf_merge_section(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, preinit_add_libc_early_init(elf_link); } + // libc .dynsym .dynstr need put first, so version section no change + bool is_first_libc = is_merge_libc_first(elf_link, tmp_sec, name); + elf_file_t *libc_ef = get_libc_ef(elf_link); + if (is_first_libc) { + ef = libc_ef; + sec = elf_find_section_by_name(ef, name); + elf_align_file(elf_link, sec->sh_addralign); + write_elf_file_section(elf_link, ef, sec, tmp_sec); + } + for (int i = 0; i < in_ef_nr; i++) { if (is_preinit) { // TODO: order by deps lib @@ -303,6 +368,9 @@ static Elf64_Shdr *elf_merge_section(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, if (skip_main_ef && (ef == main_ef)) { continue; } + if (is_first_libc && (ef == libc_ef)) { + continue; + } sec = elf_find_section_by_name(ef, l_name); if (sec == NULL) { continue; @@ -310,33 +378,10 @@ static Elf64_Shdr *elf_merge_section(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, elf_align_file(elf_link, sec->sh_addralign); dst = write_elf_file_section(elf_link, ef, sec, tmp_sec); - - void *src = ((void *)ef->hdr) + sec->sh_offset; - - if (strcmp(name, ".rela.plt") == 0) { - arr = elf_link->rela_plt_arr; - } else if (strcmp(name, ".rela.dyn") == 0) { - arr = elf_link->rela_dyn_arr; - } else { - continue; - } - int obj_nr = sec->sh_size / sec->sh_entsize; - for (int j = 0; j < obj_nr; j++) { - obj_rel.src_ef = ef; - obj_rel.src_sec = sec; - obj_rel.src_obj = src; - obj_rel.dst_obj = dst; - si_array_append(arr, &obj_rel); - src = src + sec->sh_entsize; - dst = dst + sec->sh_entsize; - } + record_rela_arr(elf_link, ef, sec, dst); } - if (tmp_sec->sh_flags & SHF_ALLOC) { - tmp_sec->sh_size = elf_link->next_mem_addr - tmp_sec->sh_addr; - } else { - tmp_sec->sh_size = elf_link->next_file_offset - tmp_sec->sh_offset; - } + tmp_sec->sh_size = elf_get_sh_size(elf_link, tmp_sec); return tmp_sec; } @@ -389,36 +434,37 @@ static void merge_section(elf_link_t *elf_link, Elf64_Shdr *dst_sec, elf_file_t dst_sec->sh_addr = 0; append_section(elf_link, dst_sec, ef, sec); - dst_sec->sh_size = elf_link->next_mem_addr - dst_sec->sh_addr; + dst_sec->sh_size = elf_get_sh_size(elf_link, dst_sec); } -static void merge_ef_section_by_name(elf_link_t *elf_link, elf_file_t *ef, const char *sec_name) +static Elf64_Shdr *merge_ef_section_by_name(elf_link_t *elf_link, elf_file_t *ef, const char *sec_name) { 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) { - return; + return NULL; } merge_section(elf_link, dst_sec, ef, sec); SI_LOG_DEBUG("section %-20s %08lx %08lx %06lx\n", sec_name, dst_sec->sh_addr, dst_sec->sh_offset, dst_sec->sh_size); + return dst_sec; } -void merge_libc_ef_section(elf_link_t *elf_link, const char *sec_name) +Elf64_Shdr *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); + return 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) +Elf64_Shdr *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); + return 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) diff --git a/src/elf_write_elf.h b/src/elf_write_elf.h index 9d05da29322fdf9c73c7cf8e9e2137518a6b0f78..48c05ec7b0addb4f2b0755e33b4c3f1ac2d2906e 100644 --- a/src/elf_write_elf.h +++ b/src/elf_write_elf.h @@ -43,8 +43,8 @@ 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_libc_ef_section(elf_link_t *elf_link, const char *sec_name); +Elf64_Shdr *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); int create_elf_file(char *file_name, elf_file_t *elf_file);