From e4d12d67984cab7bdc446503248b4befe5312f59 Mon Sep 17 00:00:00 2001 From: Zhou Kang Date: Tue, 11 Jul 2023 11:18:23 +0000 Subject: [PATCH] fix ifunc name with symbol version --- src/elf_ext.h | 3 +++ src/elf_link_common.c | 33 +++++++++++++++++++++++++-------- src/elf_relocation.c | 6 ++++++ tests/bash/Makefile | 12 +++++++++++- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/elf_ext.h b/src/elf_ext.h index 2616e87..47f00d4 100644 --- a/src/elf_ext.h +++ b/src/elf_ext.h @@ -73,4 +73,7 @@ #define ELF_VVAR_AND_VDSO_LEN (ELF_VVAR_LEN + ELF_VDSO_LEN) +// ELF not define max len, but sometime we need +#define ELF_MAX_SYMBOL_NAME_LEN (128) + #endif /* _ELF_EXT_H */ diff --git a/src/elf_link_common.c b/src/elf_link_common.c index b7f29a3..0b48e5c 100644 --- a/src/elf_link_common.c +++ b/src/elf_link_common.c @@ -573,7 +573,7 @@ unsigned long get_new_offset_by_old_offset(elf_link_t *elf_link, elf_file_t *src return get_new_addr_by_old_addr(elf_link, src_ef, offset); } -static unsigned long _get_ifunc_new_addr(elf_link_t *elf_link, char *sym_name); +static unsigned long get_ifunc_new_addr(elf_link_t *elf_link, elf_file_t *ef, Elf64_Sym *sym, char *sym_name); static unsigned long _get_new_addr_by_sym_name(elf_link_t *elf_link, char *sym_name) { @@ -614,7 +614,7 @@ static unsigned long _get_new_addr_by_sym_name(elf_link_t *elf_link, char *sym_n out: if (ELF64_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) { - return _get_ifunc_new_addr(elf_link, sym_name); + return get_ifunc_new_addr(elf_link, ef, sym, sym_name); } return get_new_addr_by_old_addr(elf_link, ef, sym->st_value); @@ -710,19 +710,36 @@ static unsigned long _get_ifunc_new_addr(elf_link_t *elf_link, char *sym_name) return 0; } +static void elf_gen_nice_name(char *sym_name) +{ + if (sym_name == NULL) { + return; + } + + char *c = index(sym_name, '@'); + if (c) { + *c = '\0'; + } +} + // ifunc is in ELFs, so it can not init when start // Assume that ifunc function name is unique -static unsigned long append_ifunc_symbol(elf_link_t *elf_link, elf_file_t *ef, Elf64_Sym *sym, char *sym_name) +static unsigned long get_ifunc_new_addr(elf_link_t *elf_link, elf_file_t *ef, Elf64_Sym *sym, char *sym_name) { + // sym name may have version, strpbrk@GLIBC_2.2.5 + char nice_sym_name[ELF_MAX_SYMBOL_NAME_LEN] = { 0 }; + (void)strncpy(nice_sym_name, sym_name, ELF_MAX_SYMBOL_NAME_LEN - 1); + elf_gen_nice_name(nice_sym_name); + unsigned long ret; if (is_static_nolibc_mode(elf_link)) { - ret = _get_ifunc_new_addr(elf_link, sym_name); + ret = _get_ifunc_new_addr(elf_link, nice_sym_name); } else { // use ifunc return value - ret = _get_ifunc_new_addr_by_dl(elf_link, ef, sym, sym_name); + ret = _get_ifunc_new_addr_by_dl(elf_link, ef, sym, nice_sym_name); } - append_symbol_mapping(elf_link, sym_name, ret); - SI_LOG_DEBUG("ifunc %s %16lx\n", sym_name, ret); + append_symbol_mapping(elf_link, nice_sym_name, ret); + SI_LOG_DEBUG("ifunc %s %16lx\n", nice_sym_name, ret); return ret; } @@ -772,7 +789,7 @@ static unsigned long _get_new_addr_by_sym(elf_link_t *elf_link, elf_file_t *ef, return ret; } if (is_direct_call_optimize(elf_link) && (ELF64_ST_TYPE(sym->st_info) == STT_GNU_IFUNC)) { - return append_ifunc_symbol(elf_link, ef, sym, sym_name); + return get_ifunc_new_addr(elf_link, ef, sym, sym_name); } // When the shndx != SHN_UNDEF, the symbol in this ELF. diff --git a/src/elf_relocation.c b/src/elf_relocation.c index 8b01cc4..6d2a368 100644 --- a/src/elf_relocation.c +++ b/src/elf_relocation.c @@ -203,6 +203,12 @@ void modify_rela_dyn_item(elf_link_t *elf_link, elf_file_t *src_ef, Elf64_Rela * // [36] .data PROGBITS 00000000001f1000 1f0000 0016a8 00 WA 0 0 32 dst_rela->r_addend = elf_get_new_tls_offset(elf_link, src_ef, src_rela->r_addend); break; + case R_X86_64_COPY: + // 000000000012dd60 000001b900000005 R_X86_64_COPY 000000000012dd60 stdout@GLIBC_2.2.5 + 0 + // 441: 000000000012dd60 8 OBJECT GLOBAL DEFAULT 36 stdout@GLIBC_2.2.5 (2) + // copy addr of sym to bss var, dyn sym need fix sym.value, see modify_symbol() + // nothing need to do here + break; 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 diff --git a/tests/bash/Makefile b/tests/bash/Makefile index 38f0743..a1ef804 100644 --- a/tests/bash/Makefile +++ b/tests/bash/Makefile @@ -16,10 +16,18 @@ LIBC_R=$(RELOCATION_DIR)$(LIBC).relocation VERSION_ID=$(shell cat /etc/os-release | grep VERSION_ID) ifeq ($(VERSION_ID), VERSION_ID="22.03") LIBTINFO=/usr/lib64/libtinfo.so.6 +LIBTINFO_R=$(RELOCATION_DIR)$(LIBTINFO).3.relocation else LIBTINFO=/usr/lib64/libtinfo.so.7 -endif LIBTINFO_R=$(RELOCATION_DIR)$(LIBTINFO).relocation +endif + +ARCH=$(shell uname -m) +ifeq ($(ARCH), aarch64) + LIBLD=/lib/ld-linux-aarch64.so.1 +else + LIBLD=/lib64/ld-linux-x86-64.so.2 +endif MODE?=--static-nold #MODE=--static-nolibc @@ -77,3 +85,5 @@ env: objdump -d $(LIBC_R) > libc.so.asm readelf -W -a $(LIBTINFO_R) > libtinfo.so.elf objdump -d $(LIBTINFO_R) > libtinfo.so.asm + readelf -W -a $(LIBLD) > ld.so.elf + objdump -d $(LIBLD) > ld.so.asm -- Gitee