FreeBSD/contrib/binutils/bfd/elflink.c
/* Add symbols from an ELF archive file to the linker hash table.  We
   don't use _bfd_generic_link_add_archive_symbols because of a
   problem which arises on UnixWare.  The UnixWare libc.so is an
   archive which includes an entry libc.so.1 which defines a bunch of
   symbols.  The libc.so archive also includes a number of other
   object files, which also define symbols, some of which are the same
   as those defined in libc.so.1.  Correct linking requires that we
   consider each object file in turn, and include it if it defines any
   symbols we need.  _bfd_generic_link_add_archive_symbols does not do
   this; it looks through the list of undefined symbols, and includes
   any object file which defines them.  When this algorithm is used on
   UnixWare, it winds up pulling in libc.so.1 early and defining a
   bunch of symbols.  This means that some of the other objects in the
   archive are not included in the link, which is incorrect since they
   precede libc.so.1 in the archive.

   Fortunately, ELF archive handling is simpler than that done by
   _bfd_generic_link_add_archive_symbols, which has to allow for a.out
   oddities.  In ELF, if we find a symbol in the archive map, and the
   symbol is currently undefined, we know that we must pull in that
   object file.

   Unfortunately, we do have to make multiple passes over the symbol
   table until nothing further is resolved.  */
Add symbols from an ELF archive file to the linker hash table.  We
don't use _bfd_generic_link_add_archive_symbols because of a
problem which arises on UnixWare.  The UnixWare libc.so is an
archive which includes an entry libc.so.1 which defines a bunch of
symbols.  The libc.so archive also includes a number of other
object files, which also define symbols, some of which are the same
as those defined in libc.so.1.  Correct linking requires that we
consider each object file in turn, and include it if it defines any
symbols we need.  _bfd_generic_link_add_archive_symbols does not do
this; it looks through the list of undefined symbols, and includes
any object file which defines them.  When this algorithm is used on
UnixWare, it winds up pulling in libc.so.1 early and defining a
bunch of symbols.  This means that some of the other objects in the
archive are not included in the link, which is incorrect since they
precede libc.so.1 in the archive.

Fortunately, ELF archive handling is simpler than that done by
_bfd_generic_link_add_archive_symbols, which has to allow for a.out
oddities.  In ELF, if we find a symbol in the archive map, and the
symbol is currently undefined, we know that we must pull in that
object file.

Unfortunately, we do have to make multiple passes over the symbol
table until nothing further is resolved.
Add symbols from an ELF archive file to the linker hash table . We don ' t use _bfd_generic_link_add_archive_symbols because of a problem which arises on UnixWare . The UnixWare libc . so is an archive which includes an entry libc . so . 1 which defines a bunch of symbols . The libc . so archive also includes a number of other object files which also define symbols some of which are the same as those defined in libc . so . 1 . Correct linking requires that we consider each object file in turn and include it if it defines any symbols we need . _bfd_generic_link_add_archive_symbols does not do this ; it looks through the list of undefined symbols and includes any object file which defines them . When this algorithm is used on UnixWare it winds up pulling in libc . so . 1 early and defining a bunch of symbols . This means that some of the other objects in the archive are not included in the link which is incorrect since they precede libc . so . 1 in the archive . Fortunately ELF archive handling is simpler than that done by _bfd_generic_link_add_archive_symbols which has to allow for a . out oddities . In ELF if we find a symbol in the archive map and the symbol is currently undefined we know that we must pull in that object file . Unfortunately we do have to make multiple passes over the symbol table until nothing further is resolved .
static bfd_boolean
elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
{
  symindex c;
  bfd_boolean *defined = NULL;
  bfd_boolean *included = NULL;
  carsym *symdefs;
  bfd_boolean loop;
  bfd_size_type amt;
  const struct elf_backend_data *bed;
  struct elf_link_hash_entry * (*archive_symbol_lookup)
    (bfd *, struct bfd_link_info *, const char *);
  if (! bfd_has_map (abfd))
    {
      if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
	return TRUE;
      bfd_set_error (bfd_error_no_armap);
      return FALSE;
    }
  c = bfd_ardata (abfd)->symdef_count;
  if (c == 0)
    return TRUE;
  amt = c;
  amt *= sizeof (bfd_boolean);
  defined = bfd_zmalloc (amt);
  included = bfd_zmalloc (amt);
  if (defined == NULL || included == NULL)
    goto error_return;
  symdefs = bfd_ardata (abfd)->symdefs;
  bed = get_elf_backend_data (abfd);
  archive_symbol_lookup = bed->elf_backend_archive_symbol_lookup;
  do
    {
      file_ptr last;
      symindex i;
      carsym *symdef;
      carsym *symdefend;
      loop = FALSE;
      last = -1;
      symdef = symdefs;
      symdefend = symdef + c;
      for (i = 0; symdef < symdefend; symdef++, i++)
	{
	  struct elf_link_hash_entry *h;
	  bfd *element;
	  struct bfd_link_hash_entry *undefs_tail;
	  symindex mark;
	  if (defined[i] || included[i])
	    continue;
	  if (symdef->file_offset == last)
	    {
	      included[i] = TRUE;
	      continue;
	    }
	  h = archive_symbol_lookup (abfd, info, symdef->name);
	  if (h == (struct elf_link_hash_entry *) 0 - 1)
	    goto error_return;
	  if (h == NULL)
	    continue;
	  if (h->root.type == bfd_link_hash_common)
	    {
	      if (! elf_link_is_defined_archive_symbol (abfd, symdef))
		continue;
	    }
	  else if (h->root.type != bfd_link_hash_undefined)
	    {
	      if (h->root.type != bfd_link_hash_undefweak)
		defined[i] = TRUE;
	      continue;
	    }
	  element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
	  if (element == NULL)
	    goto error_return;
	  if (! bfd_check_format (element, bfd_object))
	    goto error_return;
	  if (element->archive_pass != 0)
	    {
	      bfd_set_error (bfd_error_bad_value);
	      goto error_return;
	    }
	  element->archive_pass = 1;
	  undefs_tail = info->hash->undefs_tail;
	  if (! (*info->callbacks->add_archive_element) (info, element,
							 symdef->name))
	    goto error_return;
	  if (! bfd_link_add_symbols (element, info))
	    goto error_return;
	  if (undefs_tail != info->hash->undefs_tail)
	    loop = TRUE;
	  mark = i;
	  do
	    {
	      included[mark] = TRUE;
	      if (mark == 0)
		break;
	      --mark;
	    }
	  while (symdefs[mark].file_offset == symdef->file_offset);
	  last = symdef->file_offset;
	}
    }
  while (loop);
  free (defined);
  free (included);
  return TRUE;
 error_return:
  if (defined != NULL)
    free (defined);
  if (included != NULL)
    free (included);
  return FALSE;
}
static bfd_boolean elf_link_add_archive_symbols ( bfd * abfd , struct bfd_link_info * info ) { symindex c ; bfd_boolean * defined = NULL ; bfd_boolean * included = NULL ; carsym * symdefs ; bfd_boolean loop ; bfd_size_type amt ; const struct elf_backend_data * bed ; struct elf_link_hash_entry * ( * archive_symbol_lookup ) ( bfd * , struct bfd_link_info * , const char * ) ; if ( ! bfd_has_map ( abfd ) ) { if ( bfd_openr_next_archived_file ( abfd , NULL ) == NULL ) return TRUE ; bfd_set_error ( bfd_error_no_armap ) ; return FALSE ; } c = bfd_ardata ( abfd ) -> symdef_count ; if ( c == 0 ) return TRUE ; amt = c ; amt *= sizeof ( bfd_boolean ) ; defined = bfd_zmalloc ( amt ) ; included = bfd_zmalloc ( amt ) ; if ( defined == NULL || included == NULL ) goto error_return ; symdefs = bfd_ardata ( abfd ) -> symdefs ; bed = get_elf_backend_data ( abfd ) ; archive_symbol_lookup = bed -> elf_backend_archive_symbol_lookup ; do { file_ptr last ; symindex i ; carsym * symdef ; carsym * symdefend ; loop = FALSE ; last = -1 ; symdef = symdefs ; symdefend = symdef + c ; for ( i = 0 ; symdef < symdefend ; symdef ++ , i ++ ) { struct elf_link_hash_entry * h ; bfd * element ; struct bfd_link_hash_entry * undefs_tail ; symindex mark ; if ( defined [ i ] || included [ i ] ) continue ; if ( symdef -> file_offset == last ) { included [ i ] = TRUE ; continue ; } h = archive_symbol_lookup ( abfd , info , symdef -> name ) ; if ( h == ( struct elf_link_hash_entry * ) 0 - 1 ) goto error_return ; if ( h == NULL ) continue ; if ( h -> root . type == bfd_link_hash_common ) { if ( ! elf_link_is_defined_archive_symbol ( abfd , symdef ) ) continue ; } else if ( h -> root . type != bfd_link_hash_undefined ) { if ( h -> root . type != bfd_link_hash_undefweak ) defined [ i ] = TRUE ; continue ; } element = _bfd_get_elt_at_filepos ( abfd , symdef -> file_offset ) ; if ( element == NULL ) goto error_return ; if ( ! bfd_check_format ( element , bfd_object ) ) goto error_return ; if ( element -> archive_pass != 0 ) { bfd_set_error ( bfd_error_bad_value ) ; goto error_return ; } element -> archive_pass = 1 ; undefs_tail = info -> hash -> undefs_tail ; if ( ! ( * info -> callbacks -> add_archive_element ) ( info , element , symdef -> name ) ) goto error_return ; if ( ! bfd_link_add_symbols ( element , info ) ) goto error_return ; if ( undefs_tail != info -> hash -> undefs_tail ) loop = TRUE ; mark = i ; do { included [ mark ] = TRUE ; if ( mark == 0 ) break ; -- mark ; } while ( symdefs [ mark ] . file_offset == symdef -> file_offset ) ; last = symdef -> file_offset ; } } while ( loop ) ; free ( defined ) ; free ( included ) ; return TRUE ; error_return : if ( defined != NULL ) free ( defined ) ; if ( included != NULL ) free ( included ) ; return FALSE ; }
Add symbols from an ELF archive file to the linker hash table.
Add symbols from an ELF archive file to the linker hash table .
/* An empty archive is a special case.  */ /* Keep track of all symbols we know to be already defined, and all
     files we know to be already included.  This is to speed up the
     second and subsequent passes.  */ /* We currently have a common symbol.  The archive map contains
		 a reference to this symbol, so we may want to include it.  We
		 only want to include it however, if this archive element
		 contains a definition of the symbol, not just another common
		 declaration of it.

		 Unfortunately some archivers (including GNU ar) will put
		 declarations of common symbols into their archive maps, as
		 well as real definitions, so we cannot just go by the archive
		 map alone.  Instead we must read in the element's symbol
		 table and check that to see what kind of symbol definition
		 this is.  */ /* We need to include this archive member.  */ /* Doublecheck that we have not included this object
	     already--it should be impossible, but there may be
	     something wrong with the archive.  */ /* If there are any new undefined symbols, we need to make
	     another pass through the archive in order to see whether
	     they can be defined.  FIXME: This isn't perfect, because
	     common symbols wind up on undefs_tail and because an
	     undefined symbol which is defined later on in this pass
	     does not require another pass.  This isn't a bug, but it
	     does make the code less efficient than it could be.  */ /* Look backward to mark all symbols from this object file
	     which we have already seen in this pass.  */ /* We mark subsequent symbols from this object file as we go
	     on through the loop.  */