+2000-01-03  Martin v. Loewis  <loewis@informatik.hu-berlin.de>
+
+       * elflink.c (_bfd_elf_link_record_dynamic_symbol): Process symbol
+       visibility.
+       * elflink.h (elf_link_add_object_symbols): Combine visibilities.
+       * elf.c (bfd_elf_print_symbol): Interpret st_other as visibility.
+
 1999-12-29  Richard Henderson  <rth@cygnus.com>
 
        * elflink.h (bfd_elf,size_dynamic_sections): Don't export all
 
        CONST char *section_name;
        CONST char *name = NULL;
        struct elf_backend_data *bed;
+       unsigned char st_other;
        
        section_name = symbol->section ? symbol->section->name : "(*none*)";
 
          }
 
        /* If the st_other field is not zero, print it.  */
-       if (((elf_symbol_type *) symbol)->internal_elf_sym.st_other != 0)
-         fprintf (file, " 0x%02x",
-                  ((unsigned int)
-                   ((elf_symbol_type *) symbol)->internal_elf_sym.st_other));
+       st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other;
+       
+       switch (st_other)
+         {
+         case 0: break;
+         case STV_INTERNAL:  fprintf (file, " .internal");  break;
+         case STV_HIDDEN:    fprintf (file, " .hidden");    break;
+         case STV_PROTECTED: fprintf (file, " .protected"); break;
+         default:
+           /* Some other non-defined flags are also present, so print
+              everything hex.  */
+           fprintf (file, " 0x%02x", (unsigned int) st_other);
+         }
 
        fprintf (file, " %s", name);
       }
 
       boolean copy;
       bfd_size_type indx;
 
+      /* XXX: The ABI draft says the linker must turn hidden and
+        internal symbols into STB_LOCAL symbols when producing the
+        DSO. However, if ld.so honors st_other in the dynamic table,
+        this would not be necessary.  */
+      switch (ELF_ST_VISIBILITY (h->other))
+       {
+       case STV_INTERNAL:
+       case STV_HIDDEN:
+         /* This symbol must be defined in the shared object or
+            executable.  */
+         if (h->root.type == bfd_link_hash_undefined)
+           {
+             bfd * abfd = h->root.u.undef.abfd;
+             char * name = h->root.root.string;
+             
+             (*info->callbacks->undefined_symbol)
+               (info, name, abfd, bfd_und_section_ptr, 0);
+           }
+         
+         h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
+         break;
+         
+       default:
+         break;
+       }
+
       h->dynindx = elf_hash_table (info)->dynsymcount;
       ++elf_hash_table (info)->dynsymcount;
 
 
              h->type = ELF_ST_TYPE (sym.st_info);
            }
 
-         if (sym.st_other != 0
-             && (definition || h->other == 0))
-           h->other = sym.st_other;
+         /* If st_other has a processor-specific meaning, specific code
+            might be needed here.  */
+         if (sym.st_other != 0)
+           {
+             /* Combine visibilities, using the most constraining one.  */
+             unsigned char hvis   = ELF_ST_VISIBILITY (h->other);
+             unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other);
+             
+             if (symvis && (hvis > symvis || hvis == 0))
+               h->other = sym.st_other;
+             
+             /* If neither has visibility, use the st_other of the
+                definition.  This is an arbitrary choice, since the
+                other bits have no general meaning.  */
+             if (!symvis && !hvis
+                 && (definition || h->other == 0))
+               h->other = sym.st_other;
+           }
 
          /* Set a flag in the hash table entry indicating the type of
             reference or definition we just found.  Keep a count of