diff --git a/src/elf_link_common.h b/src/elf_link_common.h index 44568f54011e0b8f268ebc828d6d20731b2014b1..b9f63bde86ec043345f226d3b4949dc1ddf20cc9 100644 --- a/src/elf_link_common.h +++ b/src/elf_link_common.h @@ -227,8 +227,11 @@ static inline bool is_preinit_name(const char *name) return false; } -// libc _init_first is in .init_array, this func must run before _start -// move _init_first to .preinit_array +// 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) { if (is_static_nold_mode(elf_link)) { diff --git a/src/elf_relocation.c b/src/elf_relocation.c index 3e565ca0382ef85a153233aafd3e86aa912965c2..4fee63140eab855efae652542e47074d75cbe4f8 100644 --- a/src/elf_relocation.c +++ b/src/elf_relocation.c @@ -309,6 +309,23 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * dst_rela->r_offset, dst_rela->r_info, dst_rela->r_addend); } +static Elf64_Rela *find_none_rela(elf_file_t *ef, Elf64_Shdr *sec) +{ + int count = sec->sh_size / sizeof(Elf64_Rela); + Elf64_Rela *relas = elf_get_section_data(ef, sec); + Elf64_Rela *rela = NULL; + + for (int i = 0; i < count; i++) { + rela = &relas[i]; + // TODO: for ARM + if (ELF64_R_TYPE(rela->r_info) == R_X86_64_NONE) { + return rela; + } + } + + return NULL; +} + // .rela.dyn void modify_rela_dyn(elf_link_t *elf_link) { @@ -323,6 +340,28 @@ void modify_rela_dyn(elf_link_t *elf_link) elf_file_t *src_ef = obj_rel->src_ef; modify_rela_dyn_item(elf_link, src_ef, src_rela, dst_rela); } + + // add rela for __libc_early_init + if (is_need_preinit(elf_link) == false) { + return; + } + Elf64_Shdr *find_sec = find_tmp_section_by_name(elf_link, ".preinit_array"); + if (find_sec == NULL) { + si_panic("find section fail\n"); + } + Elf64_Shdr *sec = find_tmp_section_by_name(elf_link, ".rela.dyn"); + if (sec == NULL) { + si_panic("find section fail\n"); + } + elf_file_t *out_ef = &elf_link->out_ef; + Elf64_Rela *rela = find_none_rela(out_ef, sec); + if (rela == NULL) { + si_panic("find none rela fail\n"); + } + + rela->r_offset = find_sec->sh_addr; + unsigned long func = elf_read_u64(out_ef, find_sec->sh_offset); + rela_change_to_relative(rela, func); } void modify_got(elf_link_t *elf_link) diff --git a/src/elf_write_elf.c b/src/elf_write_elf.c index b183192ef0a697c95c22f96c1c702b01c288fe44..eb2e4f79cfad0763179edf7b8b63316c4d91ace1 100644 --- a/src/elf_write_elf.c +++ b/src/elf_write_elf.c @@ -255,6 +255,22 @@ void copy_from_old_elf(elf_link_t *elf_link) } } +// add __libc_early_init to first of .preinit_array, add rela for it +// __libc_early_init first arg is bool, is one Byte +// init_func(argc, argv, env) first arg need < 256, other args no used +static void preinit_add_libc_early_init(elf_link_t *elf_link) +{ + elf_file_t *libc_ef = get_libc_ef(elf_link); + if (libc_ef == NULL) { + return; + } + + unsigned long old_sym_addr = elf_find_symbol_addr_by_name(libc_ef, "__libc_early_init"); + unsigned long new_sym_addr = get_new_addr_by_old_addr(elf_link, libc_ef, old_sym_addr); + + write_elf_file(elf_link, &new_sym_addr, sizeof(unsigned long)); +} + 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; @@ -271,6 +287,10 @@ static Elf64_Shdr *elf_merge_section(elf_link_t *elf_link, Elf64_Shdr *tmp_sec, tmp_sec->sh_addr = elf_link->next_mem_addr; SI_LOG_DEBUG("section %s at 0x%lx\n", name, tmp_sec->sh_offset); + if (is_preinit) { + preinit_add_libc_early_init(elf_link); + } + for (int i = 0; i < in_ef_nr; i++) { if (is_preinit) { // TODO: order by deps lib