diff --git a/src/elf_read_elf.c b/src/elf_read_elf.c index b78464d31d184dc4f578dad7b67eae42382f5515..3181377955b864a34a33bff73a94bfd77b0dedab 100644 --- a/src/elf_read_elf.c +++ b/src/elf_read_elf.c @@ -38,6 +38,65 @@ #define DEBUG_SEC_PRE_NAME ".debug_" #define BUILD_ID_LEN 40 +#define ELF_VERSION_NR_LOCAL 0 +#define ELF_VERSION_NR_GLOBAL 1 + +static inline char *elf_get_version_name(elf_file_t *ef, Elf64_Vernaux *vernaux) +{ + return ef->dynstr_data + vernaux->vna_name; +} + +static inline void *elf_get_section_data(elf_file_t *ef, Elf64_Shdr *sec) +{ + return (((void *)ef->hdr) + sec->sh_offset); +} + +static inline Elf64_Shdr *elf_get_version_section(elf_file_t *ef) +{ + return elf_find_section_by_name(ef, ".gnu.version"); +} + +static inline Elf64_Shdr *elf_get_version_r_section(elf_file_t *ef) +{ + return elf_find_section_by_name(ef, ".gnu.version_r"); +} + +Elf64_Vernaux *elf_get_dynsym_vernaux(elf_file_t *ef, Elf64_Sym *sym) +{ + unsigned int index = elf_get_dynsym_index(ef, sym); + Elf64_Shdr *version_sec = elf_get_version_section(ef); + Elf64_Half *version_nr_arr = (Elf64_Half *)elf_get_section_data(ef, version_sec); + Elf64_Half version_nr = version_nr_arr[index]; + + // local or global not have Elf64_Vernaux + if ((version_nr == ELF_VERSION_NR_LOCAL) || (version_nr == ELF_VERSION_NR_GLOBAL)) { + return NULL; + } + + Elf64_Vernaux *vernaux = NULL; + Elf64_Shdr *version_r_sec = elf_get_version_r_section(ef); + Elf64_Vernaux *vernaux_arr = (Elf64_Vernaux *)elf_get_section_data(ef, version_r_sec); + int count = version_r_sec->sh_size / sizeof(Elf64_Vernaux); + for (int i = 0; i < count; i++) { + vernaux = &vernaux_arr[i]; + if (version_nr == vernaux->vna_other) { + return vernaux; + } + } + + si_panic("vernaux_arr %lx\n", vernaux_arr); + return NULL; +} + +char *elf_get_dynsym_version_name(elf_file_t *ef, Elf64_Sym *sym) +{ + Elf64_Vernaux *vernaux = elf_get_dynsym_vernaux(ef, sym); + if (vernaux == NULL) { + return NULL; + } + return elf_get_version_name(ef, vernaux); +} + bool elf_is_copy_symbol(elf_file_t *ef, Elf64_Sym *sym, bool is_dynsym) { char *sym_name = NULL; @@ -45,8 +104,12 @@ bool elf_is_copy_symbol(elf_file_t *ef, Elf64_Sym *sym, bool is_dynsym) sym_name = elf_get_dynsym_name(ef, sym); // stdout@GLIBC_2.2.5 (2) // TODO: - - + char *version_name = elf_get_dynsym_version_name(ef, sym); + if (version_name == NULL) { + return false; + } + printf("zk--- %s %s\n", sym_name, version_name); + return true; } else { sym_name = elf_get_symbol_name(ef, sym); // symtab name have @LIBC diff --git a/src/elf_read_elf.h b/src/elf_read_elf.h index 18f6c9a79e2dab7cefa4badfa6d6f0f1fa8ede97..64e8005762986e4b46386f88ca231e0672b58605 100644 --- a/src/elf_read_elf.h +++ b/src/elf_read_elf.h @@ -49,6 +49,12 @@ typedef struct { char *build_id; } elf_file_t; +static inline unsigned int elf_get_dynsym_index(elf_file_t *ef, Elf64_Sym *sym) +{ + Elf64_Sym *syms = (Elf64_Sym *)(((void *)ef->hdr) + ef->dynsym_sec->sh_offset); + return sym - syms; +} + static inline char *elf_get_section_name(const elf_file_t *ef, const Elf64_Shdr *sec) { return ef->shstrtab_data + sec->sh_name; diff --git a/src/elf_relocation.c b/src/elf_relocation.c index 66992b98f554cd7307b6e513445b75c5fb85ff4b..75912ca25e4899688fd18f06f5416f79c0908f30 100644 --- a/src/elf_relocation.c +++ b/src/elf_relocation.c @@ -149,24 +149,34 @@ static void rela_use_relative(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Re // libc: 1407: 00000000001ed688 8 OBJECT GLOBAL DEFAULT 36 stdout@@GLIBC_2.2.5 // copy symbol data to bss area + elf_file_t *ef = get_libc_ef(elf_link); Elf64_Sym *sym = elf_get_dynsym_by_rela(src_ef, src_rela); if (elf_is_copy_symbol(src_ef, sym, true) == false) { - si_panic("%s %lx\n", src_ef->file_name, src_rela->r_offset); - return; + // use local symbol addr + ef = src_ef; } char *sym_name = elf_get_dynsym_name(src_ef, sym); - elf_file_t *libc_ef = get_libc_ef(elf_link); - unsigned long old_sym_addr = elf_find_symbol_addr_by_name(libc_ef, sym_name); - unsigned long new_sym_addr = get_new_addr_by_old_addr(elf_link, libc_ef, old_sym_addr); + unsigned long old_sym_addr = elf_find_symbol_addr_by_name(ef, sym_name); + unsigned long new_sym_addr = get_new_addr_by_old_addr(elf_link, ef, old_sym_addr); if (new_sym_addr == NOT_FOUND) { si_panic("%s %lx\n", src_ef->file_name, src_rela->r_offset); return; } - // TODO: check copy size + unsigned long data = elf_read_u64_va(ef, new_sym_addr); + // check copy size + if (sym->st_size == sizeof(unsigned long)) { + // 8 byte + } else if (sym->st_size == sizeof(unsigned char)) { + // NOTE: target mem is bss, so relative type write 7 zero is OK + // 1 byte + data = (unsigned char)data; + } else { + si_panic("size wrong %s %lx\n", src_ef->file_name, src_rela->r_offset); + return; + } - unsigned long data = elf_read_u64_va(libc_ef, new_sym_addr); rela_change_to_relative(dst_rela, data); }