ld -r frustration

Alan Modra amodra@bigpond.net.au
Tue Jul 27 15:11:00 GMT 2004


Every so often I get a bug report about TOC overflow when linking on
PowerPC64 Linux.  With the automatic multiple TOC support in GNU ld,
this ought not happen very often;  You need a single object file to
exceed the 64k TOC limit.  However, people use "ld -r" to combine
object files, sometimes very many object files.  So they end up with
a TOC section that's too big.  "Too bad", I say.  "Don't use ld -r".

That's not the ideal solution, especially considering that tools
like libtool use "ld -r" to work around command line limits when
linking huge numbers of object files.  What we really need is a
"ld -r" that doesn't do any merging of sections, or a final link
stage that can undo the effects of "ld -r".  The latter would need
quite a bit of work, and probably not be very robust.  I'm leaning
towards the idea of making "ld -r" behave like "ar cr" on PowerPC64.

The only trick needed is that when using the resulting archive in a
final link we want the linker to behave as if --whole-archive were in
effect.  ie. the archive needs to be tagged specially in some way that
the linker can recognise.  I could do that quite easily by twiddling
the magic string at the start of an archive.  What's more, you could
handle the whole business of making "ld -r" invoke "ar cr" and twiddle
the magic string in a shell script.

Comments?  Better ideas?

The binutils hack will look something like the following (untested!)

Index: bfd/archive.c
===================================================================
RCS file: /cvs/src/src/bfd/archive.c,v
retrieving revision 1.31
diff -u -p -r1.31 archive.c
--- bfd/archive.c	19 May 2004 14:46:59 -0000	1.31
+++ bfd/archive.c	27 Jul 2004 15:09:22 -0000
@@ -581,6 +581,11 @@ bfd_generic_archive_p (bfd *abfd)
       return NULL;
     }
 
+  /* Recognise a magic string starting with '#' too.  These are
+     archives that ld will link as if --whole-archive was given.  */
+  if (armag[0] == '#')
+    armag[0] = '!';
+
 #ifdef GNU960
   if (strncmp (armag, BFD_GNU960_ARMAG (abfd), SARMAG) != 0)
     return 0;
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.160
diff -u -p -r1.160 ldlang.c
--- ld/ldlang.c	23 Jul 2004 16:32:53 -0000	1.160
+++ ld/ldlang.c	27 Jul 2004 15:09:24 -0000
@@ -1368,6 +1368,14 @@ load_symbols (lang_input_statement_type 
       break;
 
     case bfd_archive:
+      if (!entry->whole_archive)
+	{
+	  char magic;
+	  if (bfd_seek (entry->the_bfd, 0, SEEK_SET) == 0
+	      && bfd_bread (&magic, 1, entry->the_bfd) == 1
+	      && magic == '#')
+	    entry->whole_archive = 1;
+	}
       if (entry->whole_archive)
 	{
 	  bfd *member = NULL;

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre



More information about the Binutils mailing list