bfd/ 2008-12-23 H.J. Lu PR ld/9679 * elflink.c (elf_merge_st_other): New. (_bfd_elf_merge_symbol): Use it on skipped weak definitions and hide them if needed. (elf_link_add_object_symbols): Updated. ld/testsuite/ 2008-12-23 H.J. Lu PR ld/9679 * ld-elf/pr9679-1.c: New. * ld-elf/pr9679-2.c: Likewise. * ld-elf/pr9679.rd: Likewise. * ld-elf/shared.exp (build_tests): Add test for libpr9679.so. --- binutils/bfd/elflink.c.weak 2008-12-23 10:56:06.000000000 -0800 +++ binutils/bfd/elflink.c 2008-12-23 11:28:35.000000000 -0800 @@ -870,6 +870,54 @@ _bfd_elf_mark_dynamic_def_weak (struct e } } +/* Merge st_other field. */ + +static void +elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h, + Elf_Internal_Sym *isym, bfd_boolean definition, + bfd_boolean dynamic) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* If st_other has a processor-specific meaning, specific + code might be needed here. We never merge the visibility + attribute with the one from a dynamic object. */ + if (bed->elf_backend_merge_symbol_attribute) + (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, + dynamic); + + /* If this symbol has default visibility and the user has requested + we not re-export it, then mark it as hidden. */ + if (definition + && !dynamic + && (abfd->no_export + || (abfd->my_archive && abfd->my_archive->no_export)) + && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) + isym->st_other = (STV_HIDDEN + | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); + + if (!dynamic && ELF_ST_VISIBILITY (isym->st_other) != 0) + { + unsigned char hvis, symvis, other, nvis; + + /* Only merge the visibility. Leave the remainder of the + st_other field to elf_backend_merge_symbol_attribute. */ + other = h->other & ~ELF_ST_VISIBILITY (-1); + + /* Combine visibilities, using the most constraining one. */ + hvis = ELF_ST_VISIBILITY (h->other); + symvis = ELF_ST_VISIBILITY (isym->st_other); + if (! hvis) + nvis = symvis; + else if (! symvis) + nvis = hvis; + else + nvis = hvis < symvis ? hvis : symvis; + + h->other = other | nvis; + } +} + /* This function is called when we want to define a new symbol. It handles the various cases which arise when we find a definition in a dynamic object, or when there is already a definition in a @@ -1386,7 +1434,22 @@ _bfd_elf_merge_symbol (bfd *abfd, /* Skip weak definitions of symbols that are already defined. */ if (newdef && olddef && newweak) - *skip = TRUE; + { + *skip = TRUE; + + /* Merge st_other. If the symbol already has a dynamic index, + but visibility says it should not be visible, turn it into a + local symbol. */ + elf_merge_st_other (abfd, h, sym, newdef, newdyn); + if (h->dynindx != -1) + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_INTERNAL: + case STV_HIDDEN: + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + break; + } + } /* If the old symbol is from a dynamic object, and the new symbol is a definition which is not from a dynamic object, then the new @@ -4288,42 +4351,8 @@ elf_link_add_object_symbols (bfd *abfd, h->type = ELF_ST_TYPE (isym->st_info); } - /* If st_other has a processor-specific meaning, specific - code might be needed here. We never merge the visibility - attribute with the one from a dynamic object. */ - if (bed->elf_backend_merge_symbol_attribute) - (*bed->elf_backend_merge_symbol_attribute) (h, isym, definition, - dynamic); - - /* If this symbol has default visibility and the user has requested - we not re-export it, then mark it as hidden. */ - if (definition && !dynamic - && (abfd->no_export - || (abfd->my_archive && abfd->my_archive->no_export)) - && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) - isym->st_other = (STV_HIDDEN - | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); - - if (ELF_ST_VISIBILITY (isym->st_other) != 0 && !dynamic) - { - unsigned char hvis, symvis, other, nvis; - - /* Only merge the visibility. Leave the remainder of the - st_other field to elf_backend_merge_symbol_attribute. */ - other = h->other & ~ELF_ST_VISIBILITY (-1); - - /* Combine visibilities, using the most constraining one. */ - hvis = ELF_ST_VISIBILITY (h->other); - symvis = ELF_ST_VISIBILITY (isym->st_other); - if (! hvis) - nvis = symvis; - else if (! symvis) - nvis = hvis; - else - nvis = hvis < symvis ? hvis : symvis; - - h->other = other | nvis; - } + /* Merge st_other field. */ + elf_merge_st_other (abfd, h, isym, definition, dynamic); /* Set a flag in the hash table entry indicating the type of reference or definition we just found. Keep a count of --- binutils/ld/testsuite/ld-elf/pr9679-1.c.weak 2008-12-23 11:31:31.000000000 -0800 +++ binutils/ld/testsuite/ld-elf/pr9679-1.c 2008-12-23 11:22:20.000000000 -0800 @@ -0,0 +1,5 @@ +int +foo (void) +{ + return 1; +} --- binutils/ld/testsuite/ld-elf/pr9679-2.c.weak 2008-12-23 11:31:34.000000000 -0800 +++ binutils/ld/testsuite/ld-elf/pr9679-2.c 2008-12-23 11:22:29.000000000 -0800 @@ -0,0 +1,13 @@ +extern int foo (void) __attribute__((weak,__visibility__ ("hidden"))); + +int +foo (void) +{ + return 1; +} + +int +bar (void) +{ + return foo (); +} --- binutils/ld/testsuite/ld-elf/pr9679.rd.weak 2008-12-23 11:28:53.000000000 -0800 +++ binutils/ld/testsuite/ld-elf/pr9679.rd 2008-12-23 11:29:42.000000000 -0800 @@ -0,0 +1,5 @@ +Symbol table '\.dynsym' contains [0-9]+ entries: + +Num: +Value +Size Type +Bind +Vis +Ndx Name +#... + +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +LOCAL +HIDDEN +[0-9]+ +foo +#... --- binutils/ld/testsuite/ld-elf/shared.exp.weak 2008-12-23 10:56:06.000000000 -0800 +++ binutils/ld/testsuite/ld-elf/shared.exp 2008-12-23 11:27:53.000000000 -0800 @@ -145,6 +145,9 @@ set build_tests { "-shared tmpdir/pr9676-4.o -Ltmpdir -lpr9676-3 -Wl,--start-group -lpr9676-1 -lpr9676-2 -Wl,--end-group" "-fPIC" {dummy.c} {{readelf {-s} pr9676.rd}} "libpr9676-4a.so"} + {"Build libpr9679.so" + "-shared" "-fPIC -O0" + {pr9679-1.c pr9679-2.c} {{readelf {-s} pr9679.rd}} "libpr9679.so"} } set run_tests {