2003-03-27 H.J. Lu * elf/dl-lookup.c (_dl_lookup_symbol): Stop the search of the current value is defined. Continue the search for the real definition instead of starting from scratch if it is undefined. (_dl_lookup_symbol_skip): Likewise. (_dl_lookup_versioned_symbol): Likewise. (_dl_lookup_versioned_symbol_skip): Likewise. --- elf/dl-lookup.c.protected 2003-03-26 08:22:01.000000000 -0800 +++ elf/dl-lookup.c 2003-03-27 11:01:51.000000000 -0800 @@ -271,9 +271,24 @@ _dl_lookup_symbol (const char *undef_nam protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; if (__builtin_expect (protected != 0, 0)) { - /* It is very tricky. We need to figure out what value to - return for the protected symbol. */ - if (type_class == ELF_RTYPE_CLASS_PLT) + /* When we get here, there are 3 possibilities: + + 1. current_value has a real definition. + 2. current_value has a definition from a copy relocation. + 3. current_value doesn't have any definition, which may be the + case for an ELF_RTYPE_CLASS_PLT relocation. + + For the protected symbol, we need to make sure that the + definition from undef_map is used. + + If it is defined and not from a copy relocation, we make sure + the definition from undef_map is used. + + FIXME: We can't tell if a definition is from a copy relocation + or not. */ + if (type_class == ELF_RTYPE_CLASS_PLT + || (current_value.s + && current_value.s->st_shndx != SHN_UNDEF)) { if (current_value.s != NULL && current_value.m != undef_map) { @@ -285,7 +300,14 @@ _dl_lookup_symbol (const char *undef_nam { struct sym_val protected_value = { NULL, NULL }; - for (scope = symbol_scope; *scope; ++scope) + /* Now, current_value is either undefined or from a copy + relocation. We continue the search for the real + definition, using ELF_RTYPE_CLASS_PLT to skip undefined + symbols. + + FIXME: How do we skip a definition from a copy + relocation? */ + for (; *scope; ++scope) if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, 0, flags, NULL, ELF_RTYPE_CLASS_PLT)) @@ -368,24 +390,53 @@ _dl_lookup_symbol_skip (const char *unde if (__builtin_expect (protected != 0, 0)) { - /* It is very tricky. We need to figure out what value to - return for the protected symbol. */ - struct sym_val protected_value = { NULL, NULL }; - - if (i >= (*scope)->r_nlist - || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, - i, DL_LOOKUP_RETURN_NEWEST, skip_map, - ELF_RTYPE_CLASS_PLT)) - while (*++scope) - if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, - 0, DL_LOOKUP_RETURN_NEWEST, skip_map, - ELF_RTYPE_CLASS_PLT)) - break; + /* When we get here, there are 3 possibilities: - if (protected_value.s != NULL && protected_value.m != undef_map) + 1. current_value has a real definition. + 2. current_value has a definition from a copy relocation. + 3. current_value doesn't have any definition, which may be the + case for an ELF_RTYPE_CLASS_PLT relocation. + + For the protected symbol, we need to make sure that the + definition from undef_map is used. + + If it is defined and not from a copy relocation, we make sure + the definition from undef_map is used. + + FIXME: We can't tell if a definition is from a copy relocation + or not. */ + if (current_value.s && current_value.s->st_shndx != SHN_UNDEF) { - current_value.s = *ref; - current_value.m = undef_map; + if (current_value.s != NULL && current_value.m != undef_map) + { + current_value.s = *ref; + current_value.m = undef_map; + } + } + else + { + struct sym_val protected_value = { NULL, NULL }; + + /* Now, current_value is either undefined or from a copy + relocation. We continue the search for the real + definition, using ELF_RTYPE_CLASS_PLT to skip undefined + symbols. + + FIXME: How do we skip a definition from a copy + relocation? */ + while (*++scope) + if (_dl_do_lookup (undef_name, hash, *ref, + &protected_value, *scope, 0, + DL_LOOKUP_RETURN_NEWEST, + skip_map, ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s != NULL + && protected_value.m != undef_map) + { + current_value.s = *ref; + current_value.m = undef_map; + } } } @@ -476,9 +527,24 @@ _dl_lookup_versioned_symbol (const char if (__builtin_expect (protected != 0, 0)) { - /* It is very tricky. We need to figure out what value to - return for the protected symbol. */ - if (type_class == ELF_RTYPE_CLASS_PLT) + /* When we get here, there are 3 possibilities: + + 1. current_value has a real definition. + 2. current_value has a definition from a copy relocation. + 3. current_value doesn't have any definition, which may be the + case for an ELF_RTYPE_CLASS_PLT relocation. + + For the protected symbol, we need to make sure that the + definition from undef_map is used. + + If it is defined and not from a copy relocation, we make sure + the definition from undef_map is used. + + FIXME: We can't tell if a definition is from a copy relocation + or not. */ + if (type_class == ELF_RTYPE_CLASS_PLT + || (current_value.s + && current_value.s->st_shndx != SHN_UNDEF)) { if (current_value.s != NULL && current_value.m != undef_map) { @@ -490,7 +556,14 @@ _dl_lookup_versioned_symbol (const char { struct sym_val protected_value = { NULL, NULL }; - for (scope = symbol_scope; *scope; ++scope) + /* Now, current_value is either undefined or from a copy + relocation. We continue the search for the real + definition, using ELF_RTYPE_CLASS_PLT to skip undefined + symbols. + + FIXME: How do we skip a definition from a copy + relocation? */ + for (; *scope; ++scope) if (_dl_do_lookup_versioned (undef_name, hash, *ref, &protected_value, *scope, 0, version, NULL, @@ -588,24 +661,53 @@ _dl_lookup_versioned_symbol_skip (const if (__builtin_expect (protected != 0, 0)) { - /* It is very tricky. We need to figure out what value to - return for the protected symbol. */ - struct sym_val protected_value = { NULL, NULL }; - - if (i >= (*scope)->r_nlist - || !_dl_do_lookup_versioned (undef_name, hash, *ref, - &protected_value, *scope, i, version, - skip_map, ELF_RTYPE_CLASS_PLT)) - while (*++scope) - if (_dl_do_lookup_versioned (undef_name, hash, *ref, - &protected_value, *scope, 0, version, - skip_map, ELF_RTYPE_CLASS_PLT)) - break; + /* When we get here, there are 3 possibilities: - if (protected_value.s != NULL && protected_value.m != undef_map) + 1. current_value has a real definition. + 2. current_value has a definition from a copy relocation. + 3. current_value doesn't have any definition, which may be the + case for an ELF_RTYPE_CLASS_PLT relocation. + + For the protected symbol, we need to make sure that the + definition from undef_map is used. + + If it is defined and not from a copy relocation, we make sure + the definition from undef_map is used. + + FIXME: We can't tell if a definition is from a copy relocation + or not. */ + if (current_value.s && current_value.s->st_shndx != SHN_UNDEF) { - current_value.s = *ref; - current_value.m = undef_map; + if (current_value.s != NULL && current_value.m != undef_map) + { + current_value.s = *ref; + current_value.m = undef_map; + } + } + else + { + struct sym_val protected_value = { NULL, NULL }; + + /* Now, current_value is either undefined or from a copy + relocation. We continue the search for the real + definition, using ELF_RTYPE_CLASS_PLT to skip undefined + symbols. + + FIXME: How do we skip a definition from a copy + relocation? */ + while (*++scope) + if (_dl_do_lookup_versioned (undef_name, hash, *ref, + &protected_value, *scope, 0, + version, skip_map, + ELF_RTYPE_CLASS_PLT)) + break; + + if (protected_value.s != NULL + && protected_value.m != undef_map) + { + current_value.s = *ref; + current_value.m = undef_map; + } } }