diff --git a/libc-test/src/functionalext/symver/BUILD.gn b/libc-test/src/functionalext/symver/BUILD.gn index a278922df8c588fa74bc15bda72a3a5bde2ea65a..7193abe88beeb486b353904df15384e00f055583 100644 --- a/libc-test/src/functionalext/symver/BUILD.gn +++ b/libc-test/src/functionalext/symver/BUILD.gn @@ -37,6 +37,7 @@ group("dso_shared") { ":dso_hard_symver", ":dso_no_symver", ":dso_symver", + ":reloc_symver_dso", ] } @@ -53,3 +54,10 @@ test_sharedlib("dso_no_symver") { test_sharedlib("dso_symver") { } + +test_sharedlib("reloc_symver_dso") { + deps = [ + ":dso_easy_symver", + ":dso_no_symver", + ] +} diff --git a/libc-test/src/functionalext/symver/reloc_symver.c b/libc-test/src/functionalext/symver/reloc_symver.c new file mode 100644 index 0000000000000000000000000000000000000000..0f7e8053d3aee63fa5f277897f62a922a4cf0988 --- /dev/null +++ b/libc-test/src/functionalext/symver/reloc_symver.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "dso_symver.h" + +/** + * @tc.name : reloc_symver_0100 + * @tc.desc : find versioning symbol while relocating. + * load libreloc_symver_dso.so that deps on libdso_no_symver.so and libdso_easy_symver.so. + * @tc.level : Level 1 + */ +static void reloc_symver_0100(void) +{ + symver_log("start"); + + void *so = dlopen("libreloc_symver_dso.so", RTLD_NOW); + if (so) { + dlclose(so); + } else { + symver_error("%s", dlerror()); + } + + symver_log("end"); +} + +int main(int argc, char *argv[]) +{ + symver_log("start"); + + reloc_symver_0100(); + + symver_log("t_status = %d", t_status); + symver_log("end"); + + return t_status; +} \ No newline at end of file diff --git a/libc-test/src/functionalext/symver/reloc_symver_dso.c b/libc-test/src/functionalext/symver/reloc_symver_dso.c new file mode 100644 index 0000000000000000000000000000000000000000..6e01ae1dd571f6c182c00248b3c98b9574a142c0 --- /dev/null +++ b/libc-test/src/functionalext/symver/reloc_symver_dso.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dso_no_symver.h" +#include "dso_easy_symver.h" + +void test_func() +{ + (void)dso_no_symver(); + (void)dso_easy_symver(); +} \ No newline at end of file diff --git a/libc-test/src/functionalext/symver/test_src_functionalext_symver.gni b/libc-test/src/functionalext/symver/test_src_functionalext_symver.gni index 864ddfbdf2783e3f967b8adc3aea5bd617ea724e..7d3a408f3df4e321e8a7fca046896973e842a3b0 100644 --- a/libc-test/src/functionalext/symver/test_src_functionalext_symver.gni +++ b/libc-test/src/functionalext/symver/test_src_functionalext_symver.gni @@ -16,4 +16,5 @@ functionalext_symver_list = [ "dlvsym", "dynlink_default", "dynlink", + "reloc_symver", ] diff --git a/libc-test/test_template.gni b/libc-test/test_template.gni index e61b53cc4729daf71cab21f8b6787ed159bd9c05..1576f02455fdbf8dd69c0e4cfce8359fa3ec4cec 100644 --- a/libc-test/test_template.gni +++ b/libc-test/test_template.gni @@ -265,6 +265,10 @@ template("test_sharedlib") { ldflags += [ "-Wl,--version-script=${_version_script}" ] } + if (defined(invoker.deps)) { + deps = invoker.deps + } + libs = [ "//${out_test_dir}/src/common/libtest.a" ] output_name = "${target_name}" diff --git a/porting/linux/user/ldso/dynlink.c b/porting/linux/user/ldso/dynlink.c index 21af124272ff9a9258889c0977a7b4e1dbf08ea8..5fac1028d114194d90d37e294d7a08333afab561 100644 --- a/porting/linux/user/ldso/dynlink.c +++ b/porting/linux/user/ldso/dynlink.c @@ -82,7 +82,8 @@ struct td_index { struct verinfo { const char *s; const char *v; - Verneed *verneed; + bool use_vna_hash; + uint32_t vna_hash; }; struct dso { @@ -462,45 +463,23 @@ static int search_vec(size_t *v, size_t *r, size_t key) return 1; } -static int check_verneed(Verdef *def, int vsym, struct verinfo *verinfo) +static int check_vna_hash(Verdef *def, int16_t vsym, uint32_t vna_hash) { int matched = 0; - Verneed *verneed = verinfo->verneed; vsym &= 0x7fff; + Verdef *verdef = def; for(;;) { - Vernaux *vernaux = (Vernaux *)((char *)verneed + verneed->vn_aux); - - for (size_t cnt = 0; cnt < verneed->vn_cnt; cnt++) { - Verdef *verdef = def; - /* find the version of symbol for verneed. */ - for(;;) { - if (vernaux->vna_hash == verdef->vd_hash) { - if ((verdef->vd_ndx & 0x7fff) == vsym) { - matched = 1; - } - break; - } - - if (verdef->vd_next == 0) { - break; - } - - verdef = (Verdef *)((char *)verdef + verdef->vd_next); - } - - if (matched) { - break; + if ((verdef->vd_ndx & 0x7fff) == vsym) { + if (vna_hash == verdef->vd_hash) { + matched = 1; } - - vernaux = (Vernaux *)((char *)vernaux + vernaux->vna_next); + break; } - - if (verneed->vn_next == 0) { + if (verdef->vd_next == 0) { break; } - - verneed = (Verneed *)((char *)verneed + verneed->vn_next); + verdef = (Verdef *)((char *)verdef + verdef->vd_next); } return matched; @@ -517,12 +496,13 @@ static int check_verinfo(Verdef *def, int16_t *versym, uint32_t index, struct ve } } - int vsym = versym[index]; + int16_t vsym = versym[index]; - /* if the verneed is not null , find the verneed symbol. */ - Verneed *verneed = verinfo->verneed; - if (verneed) { - return check_verneed(def, vsym, verinfo); + /* find the verneed symbol. */ + if (verinfo->use_vna_hash) { + if (vsym != VER_NDX_LOCAL && versym != VER_NDX_GLOBAL) { + return check_vna_hash(def, vsym, verinfo->vna_hash); + } } /* if the version length is zero and vsym not less than zero, then library hava default version symbol. */ @@ -748,10 +728,52 @@ static inline struct symdef find_sym2(struct dso *dso, struct verinfo *verinfo, static struct symdef find_sym(struct dso *dso, const char *s, int need_def) { - struct verinfo verinfo = { .s = s, .v = "", .verneed = dso->verneed }; + struct verinfo verinfo = { .s = s, .v = "", .use_vna_hash = false }; return find_sym2(dso, &verinfo, need_def, 0, NULL); } +static bool get_vna_hash(struct dso *dso, int sym_index, uint32_t *vna_hash) +{ + if (!dso->versym || !dso->verneed) { + return false; + } + + uint16_t vsym = dso->versym[sym_index]; + if (vsym == VER_NDX_LOCAL || vsym == VER_NDX_GLOBAL) { + return false; + } + + bool result = false; + Verneed *verneed = dso->verneed; + Vernaux *vernaux; + vsym &= 0x7fff; + + for(;;) { + vernaux = (Vernaux *)((char *)verneed + verneed->vn_aux); + + for (size_t cnt = 0; cnt < verneed->vn_cnt; cnt++) { + if ((vernaux->vna_other & 0x7fff) == vsym) { + result = true; + *vna_hash = vernaux->vna_hash; + break; + } + + vernaux = (Vernaux *)((char *)vernaux + vernaux->vna_next); + } + + if (result) { + break; + } + + if (verneed->vn_next == 0) { + break; + } + + verneed = (Verneed *)((char *)verneed + verneed->vn_next); + } + return result; +} + static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) { unsigned char *base = dso->base; @@ -802,7 +824,8 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri sym = syms + sym_index; name = strings + sym->st_name; ctx = type==REL_COPY ? head->syms_next : head; - struct verinfo vinfo = { .s = name, .v = "", .verneed = dso->verneed }; + struct verinfo vinfo = { .s = name, .v = "" }; + vinfo.use_vna_hash = get_vna_hash(dso, sym_index, &vinfo.vna_hash); def = (sym->st_info>>4) == STB_LOCAL ? (struct symdef){ .dso = dso, .sym = sym } : find_sym2(ctx, &vinfo, type==REL_PLT, 0, dso->namespace); @@ -3044,7 +3067,7 @@ static void *do_dlsym(struct dso *p, const char *s, const char *v, void *ra) ns = caller->namespace; } } - struct verinfo verinfo = { .s = s, .v = v, .verneed = NULL }; + struct verinfo verinfo = { .s = s, .v = v, .use_vna_hash = false }; struct symdef def = find_sym2(p, &verinfo, 0, use_deps, ns); if (!def.sym) { error("Symbol not found: %s, version: %s", s, strlen(v) > 0 ? v : "null");