This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: GNU-ld behaviour does not match native linker behaviour


Hi Ian,

: You should be able to change the behaviour very easily.  In
: elf_link_add_archive_symbols, just before the comment
:     /* We need to include this archive member.  */
: it checks the symbol in the archive map.  Right now it only includes
: the archive member if the symbol is undefined.  You should be able to
: change it to include the archive member if the symbol is common.

Well that is what my patch does.  But the problem is that we still
only want to include the archive element if it contains the
*definition* of (the contents of) a common symbol, and not just
another (common) declaration of it.  Thus the code has to open up the
element, scan its symbol table, determine what kind of declaration of
the symbol this is, and only then can the decision be made as to
whether the element should be included in the link...

For reference purposes here is my current version of the patch.

Cheers
	Nick

Index: bfd/elflink.h
===================================================================
RCS file: /cvs/cvsfiles/devo/bfd/elflink.h,v
retrieving revision 1.107.4.1
diff -p -r1.107.4.1 elflink.h
*** elflink.h	1998/09/26 19:44:37	1.107.4.1
--- elflink.h	1999/12/01 16:11:55
*************** elf_bfd_link_add_symbols (abfd, info)
*** 72,77 ****
--- 72,164 ----
  }
  
  
+ /* Search the symbol table of the archive element of the archive ABFD
+    which contains the symbol SYMDEF and determine if it is defined there.  */
+ static boolean
+ elf_link_is_defined_archive_symbol (abfd, symdef)
+      bfd * abfd;
+      carsym * symdef;
+ {
+   Elf_Internal_Shdr * hdr;
+   Elf_External_Sym *  esym;
+   Elf_External_Sym *  esymend;
+   Elf_External_Sym *  buf = NULL;
+   size_t symcount;
+   size_t extsymcount;
+   size_t extsymoff;
+   boolean result = false;
+   
+   abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+   if (abfd == (bfd *) NULL)
+     return false;
+ 
+   if (! bfd_check_format (abfd, bfd_object))
+     return false;
+ 
+   if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
+     hdr = &elf_tdata (abfd)->symtab_hdr;
+   else
+     hdr = &elf_tdata (abfd)->dynsymtab_hdr;
+ 
+   symcount = hdr->sh_size / sizeof (Elf_External_Sym);
+ 
+   /* The sh_info field of the symtab header tells us where the
+      external symbols start.  We don't care about the local
+      symbols at this point.  */
+   if (elf_bad_symtab (abfd))
+     {
+       extsymcount = symcount;
+       extsymoff = 0;
+     }
+   else
+     {
+       extsymcount = symcount - hdr->sh_info;
+       extsymoff = hdr->sh_info;
+     }
+ 
+   buf = ((Elf_External_Sym *)
+ 	 bfd_malloc (extsymcount * sizeof (Elf_External_Sym)));
+   if (buf == NULL && extsymcount != 0)
+     return false;
+ 
+   if (bfd_seek (abfd,
+ 		hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym),
+ 		SEEK_SET) != 0
+       || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd)
+ 	  != extsymcount * sizeof (Elf_External_Sym)))
+     {
+       free (buf);
+       return false;
+     }
+ 
+   esymend = buf + extsymcount;
+   for (esym = buf;
+        esym < esymend;
+        esym++)
+     {
+       Elf_Internal_Sym sym;
+       const char * name;
+ 
+       elf_swap_symbol_in (abfd, esym, & sym);
+ 
+       name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name);
+       if (name == (const char *) NULL)
+ 	break;
+ 
+       if (strcmp (name, symdef->name) == 0)
+ 	{
+ 	  result =
+ 	    (ELF_ST_BIND (sym.st_info) == STB_GLOBAL)
+ 	    && (sym.st_shndx != SHN_UNDEF);
+ 	  break;
+ 	}
+     }
+ 
+   free (buf);
+   
+   return result;
+ }
+ 
  /* 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
*************** elf_link_add_archive_symbols (abfd, info
*** 191,205 ****
  	  if (h == NULL)
  	    continue;
  
! 	  if (h->root.type != bfd_link_hash_undefined)
  	    {
  	      if (h->root.type != bfd_link_hash_undefweak)
  		defined[i] = true;
  	      continue;
  	    }
  
  	  /* We need to include this archive member.  */
- 
  	  element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
  	  if (element == (bfd *) NULL)
  	    goto error_return;
--- 278,300 ----
  	  if (h == NULL)
  	    continue;
  
! 	  if (info->link_in_archive_definitions_of_commons
! 	      && h->root.type == bfd_link_hash_common)
  	    {
+ 	      /* If this archive element contains a definition of a common symbol
+ 		 then we need to include it.  If it just contains another common
+ 		 definition of the symbol, then we do not.  */
+ 	      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;
  	    }
  
  	  /* We need to include this archive member.  */
  	  element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
  	  if (element == (bfd *) NULL)
  	    goto error_return;

Index: include/bfdlink.h
===================================================================
RCS file: /cvs/cvsfiles/devo/include/bfdlink.h,v
retrieving revision 1.32
diff -p -r1.32 bfdlink.h
*** bfdlink.h	1997/05/24 15:29:33	1.32
--- bfdlink.h	1999/12/01 16:11:57
*************** struct bfd_link_info
*** 193,198 ****
--- 193,203 ----
       on the output file, but may be checked when reading the input
       files.  */
    boolean traditional_format;
+   /* true if an archive element should be included in a link if it
+      defines a symbol which up until that point had only been defined
+      as a common symbol.  This is necessary when linking together
+      archives made up of FORTRAN generated objects.  */
+   boolean link_in_archive_definitions_of_commons;
    /* Which symbols to strip.  */
    enum bfd_link_strip strip;
    /* Which local symbols to discard.  */

Index: ld/ldmain.c
===================================================================
RCS file: /cvs/cvsfiles/devo/ld/ldmain.c,v
retrieving revision 1.157
diff -p -r1.157 ldmain.c
*** ldmain.c	1998/07/02 02:52:31	1.157
--- ldmain.c	1999/12/01 16:11:55
*************** main (argc, argv)
*** 206,211 ****
--- 206,212 ----
    link_info.symbolic = false;
    link_info.static_link = false;
    link_info.traditional_format = false;
+   link_info.link_in_archive_definitions_of_commons = false;
    link_info.strip = strip_none;
    link_info.discard = discard_none;
    link_info.keep_memory = true;

Index: ld/lexsup.c
===================================================================
RCS file: /cvs/cvsfiles/devo/ld/lexsup.c,v
retrieving revision 1.97
diff -p -r1.97 lexsup.c
*** lexsup.c	1998/07/23 16:24:43	1.97
--- lexsup.c	1999/12/01 16:11:56
*************** int parsing_defsym = 0;
*** 114,119 ****
--- 114,121 ----
  #define OPTION_FORCE_EXE_SUFFIX		(OPTION_WRAP + 1)
  #define OPTION_GC_SECTIONS		(OPTION_FORCE_EXE_SUFFIX + 1)
  #define OPTION_NO_GC_SECTIONS		(OPTION_GC_SECTIONS + 1)
+ #define OPTION_FORTRAN_LINKING		(OPTION_NO_GC_SECTIONS + 1)
+ #define OPTION_NO_FORTRAN_LINKING	(OPTION_FORTRAN_LINKING + 1)
  
  /* The long options.  This structure is used for both the option
     parsing and the help text.  */
*************** static const struct ld_option ld_options
*** 261,266 ****
--- 263,272 ----
        '\0', NULL, N_("Generate embedded relocs"), TWO_DASHES},
    { {"force-exe-suffix", no_argument, NULL, OPTION_FORCE_EXE_SUFFIX},
        '\0', NULL, N_("Force generation of file with .exe suffix"), TWO_DASHES},
+   { {"fortran-linking", no_argument, NULL, OPTION_FORTRAN_LINKING},
+       '\0', NULL, N_("link library objects which define common symbols"), TWO_DASHES},
+   { {"no-fortran-linking", no_argument, NULL, OPTION_NO_FORTRAN_LINKING},
+       '\0', NULL, "Turn off --fortran-linking", TWO_DASHES},
    { {"help", no_argument, NULL, OPTION_HELP},
        '\0', NULL, N_("Print option help"), TWO_DASHES },
    { {"Map", required_argument, NULL, OPTION_MAP},
*************** the GNU General Public License.  This pr
*** 891,897 ****
  	  lang_leave_group ();
  	  ingroup = 0;
  	  break;
! 
  	}
      }
  
--- 897,908 ----
  	  lang_leave_group ();
  	  ingroup = 0;
  	  break;
! 	case OPTION_FORTRAN_LINKING:
! 	  link_info.link_in_archive_definitions_of_commons = true;
! 	  break;
! 	case OPTION_NO_FORTRAN_LINKING:
! 	  link_info.link_in_archive_definitions_of_commons = false;
! 	  break;
  	}
      }
  
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/cvsfiles/devo/ld/ld.texinfo,v
retrieving revision 1.154
diff -p -r1.154 ld.texinfo
*** ld.texinfo	1998/07/13 17:23:54	1.154
--- ld.texinfo	1999/12/01 16:11:57
*************** option is useful when using unmodified U
*** 401,406 ****
--- 401,427 ----
  Windows host, since some versions of Windows won't run an image unless
  it ends in a @code{.exe} suffix.
  
+ @kindex --fortran-linking
+ @cindex linking FORTRAN libraries
+ @item --fortran-linking
+ Forces the linker to include object files in libraries that contain
+ defintions of symbols which up until that point in the link has only be
+ seen as common symbols.  This is not the standard beahviour of a linker,
+ which would normally only include a library object file if it contained
+ a defintion of a symbol which up until that point had been undefined.
+ 
+ This option is necessary in order to correctly link libraries which
+ contain FORTRAN generated object files.  In FORTRAN the definition of
+ the contents of a global common object are seperate from the declaration
+ of the object itself, and if these happen in different object files,
+ then without this option it is possible to link in the declaration of
+ the common object without linking in the definition of its contents.
+ 
+ @kindex --no-fortran-linking
+ @item --no-fortran-linking
+ Turns off the behaviour enabled by a previous @samp{--fortran-linking}
+ command line switch.
+ 
  @kindex -g
  @item -g
  Ignored.  Provided for compatibility with other tools.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]