public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
@ 2011-01-29  1:23 Dave Korn
  2011-01-29  1:45 ` H.J. Lu
  0 siblings, 1 reply; 14+ messages in thread
From: Dave Korn @ 2011-01-29  1:23 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 3217 bytes --]


    Hi list,

  This patch updates the existing plugin API in LD to correct the effective
link order of the files added by the plugin.  (It does not deal with the need
for pass-throughs; that is a separate and orthogonal issue that I will tackle
in a subsequent patch.  I hope that the combination of these two fixes should
address all the same issues HJ's two-stage linking approach was designed to fix.)

  At the moment added files and libraries are simply concatenated onto the end
of the statement list.  This is more-or-less the same as adding them onto the
end of the command-line; this means that their contributions get merged into
sections after all the non-IR files, including in particular crtend.o.  That's
pretty serious when it results in something like this:

> .eh_frame       0x00404000      0x200
>  *(.eh_frame)
>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>  .eh_frame      0x00404058       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>  .eh_frame      0x004040b4       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccF5bqWv.lto.o

because it breaks EH!

  The attached patch doesn't implement two-stage linking, but takes the
approach Cary described(*) in GOLD:

> On 03/12/2010 18:46, Cary Coutant wrote:
> 
>> I should have remembered that I already dealt with this problem long
>> ago -- gold defers the layout of all real objects that follow the
>> first claimed IR file until after the replacement files have been laid
>> out. With respect to physical layout of the sections, this effectively
>> makes the link order equivalent to putting the replacement files in
>> the place of the first IR file. No "endcap" option is necessary.

  In LD, there's nothing to "defer", as layout hasn't begun yet.  All we need
to do is add the replacement files into the middle of the existing statement
list, immediately after the first claimed IR file.  Complicated only slightly
by the fact that there are in fact three separate singly-linked chains through
the list of statements, that's what this patch does, and it results in the
correct result:

> .eh_frame       0x00404000      0x200
>  *(.eh_frame)
>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>  .eh_frame      0x00404058       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccfuGGNR.lto.o
>  .eh_frame      0x004040c0       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o

ld/ChangeLog:

2011-01-29  Dave Korn  <dave.korn.cygwin@gmail.com>

	* ldlang.c (lang_process): After adding and opening new input files
	passed from plugin, splice them into correct place in statement list
	chains to preserve critical link order.
	(lang_list_insert_after): New helper function.
	(lang_list_remove_tail): Likewise.

  Built and tested on i686-pc-cygwin.  I'm running a subset of the G++/GCC
testsuites to sanity-check it as well, and I'll put it through a cycle or two
on one of the cfarm machines while I'm at it.

  Assuming all that shows it working, OK to commit this to trunk, and after a
few days to settle in (and submit another plugin-related patch or two) to the
branch?

    cheers,
      DaveK


[-- Attachment #2: ld.bfd-plugin-link-order.diff --]
[-- Type: text/x-c, Size: 5425 bytes --]

Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.360
diff -p -u -r1.360 ldlang.c
--- ld/ldlang.c	14 Jan 2011 02:18:22 -0000	1.360
+++ ld/ldlang.c	29 Jan 2011 00:42:09 -0000
@@ -85,6 +85,11 @@ static void print_statement_list (lang_s
 static void print_statements (void);
 static void print_input_section (asection *, bfd_boolean);
 static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
+static void lang_list_insert_after (lang_statement_list_type *destlist,
+				    lang_statement_list_type *srclist,
+				    lang_statement_union_type **field);
+static void lang_list_remove_tail (lang_statement_list_type *destlist,
+				   lang_statement_list_type *origlist);
 static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
@@ -6420,21 +6425,54 @@ lang_process (void)
   open_input_bfds (statement_list.head, FALSE);
 
 #ifdef ENABLE_PLUGINS
+  if (plugin_active_plugins_p ())
     {
-      union lang_statement_union **listend;
+      lang_statement_list_type added;
+      lang_statement_list_type files, inputfiles;
       /* Now all files are read, let the plugin(s) decide if there
 	 are any more to be added to the link before we call the
-	 emulation's after_open hook.  */
-      listend = statement_list.tail;
-      ASSERT (!*listend);
+	 emulation's after_open hook.  We create a private list of
+	 input statements for this purpose, which we will eventually
+	 insert into the global statment list after the first claimed
+	 file.  */
+      added = *stat_ptr;
+      /* We need to manipulate all three chains in synchrony.  */
+      files = file_chain;
+      inputfiles = input_file_chain;
       if (plugin_call_all_symbols_read ())
 	einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
 	       plugin_error_plugin ());
-      /* If any new files were added, they will be on the end of the
-	 statement list, and we can open them now by getting open_input_bfds
-	 to carry on from where it ended last time.  */
-      if (*listend)
-	open_input_bfds (*listend, FALSE);
+      /* Open any newly added files, updating the file chains.  */
+      open_input_bfds (added.head, FALSE);
+      /* Restore the global list pointer now they have all been added.  */
+      lang_list_remove_tail (stat_ptr, &added);
+      /* And detach the fresh ends of the file lists.  */
+      lang_list_remove_tail (&file_chain, &files);
+      lang_list_remove_tail (&input_file_chain, &inputfiles);
+      /* Were any new files added?  */
+      if (added.head != NULL)
+	{
+	  /* If so, we will insert them into the statement list immediately
+	     after the first input file that was claimed by the plugin.  */
+	  lang_input_statement_type *claim1;
+	  /* Locate first claimed input file.  */
+	  for (claim1 = (lang_input_statement_type *) input_file_chain.head;
+	       claim1 != NULL;
+	       claim1 = (lang_input_statement_type *) claim1->next_real_file)
+	    if (claim1->claimed)
+	      break;
+	  /* If a plugin adds input files without having claimed any, we
+	     don't really have a good idea where to place them.  Just putting
+	     them at the start or end of the list is liable to leave them
+	     outside the crtbegin...crtend range.  */
+	  ASSERT (claim1 != NULL);
+	  /* Splice the new statement list into the old one after claim1.  */
+	  lang_list_insert_after (stat_ptr, &added, &claim1->header.next);
+	  /* Likewise for the file chains.  */
+	  lang_list_insert_after (&file_chain, &files, &claim1->next);
+	  lang_list_insert_after (&input_file_chain, &inputfiles,
+				  &claim1->next_real_file);
+	}
     }
 #endif /* ENABLE_PLUGINS */
 
@@ -6857,6 +6895,50 @@ lang_statement_append (lang_statement_li
   list->tail = field;
 }
 
+/* Insert SRCLIST into DESTLIST after given element by chaining
+   on FIELD as the next-pointer.  (Counterintuitively does not need
+   a pointer to the actual after-node itself, just its chain field.)  */
+
+static void
+lang_list_insert_after (lang_statement_list_type *destlist,
+			lang_statement_list_type *srclist,
+			lang_statement_union_type **field)
+{
+  /* Are we adding at the very end of the list?  */
+  if (*field == NULL)
+    {
+      /* (*field == NULL) should be same as (destlist->tail == field),
+	  if not then the element isn't really in the DESTLIST.  */
+      ASSERT (destlist->tail == field);
+      /* Yes, append to and update tail pointer.  */
+      *(destlist->tail) = srclist->head;
+      destlist->tail = srclist->tail;
+    }
+  else
+    {
+      /* We're inserting in the middle somewhere.  */
+      *(srclist->tail) = *field;
+      *field = srclist->head;
+    }
+}
+
+/* Detach new nodes added to DESTLIST since the time ORIGLIST
+   was taken as a copy of it and leave them in ORIGLIST.  */
+
+static void
+lang_list_remove_tail (lang_statement_list_type *destlist,
+		       lang_statement_list_type *origlist)
+{
+  union lang_statement_union **savetail;
+  /* Check that ORIGLIST really is an earlier state of DESTLIST.  */
+  ASSERT (origlist->head == destlist->head);
+  savetail = origlist->tail;
+  origlist->head = *(savetail);
+  origlist->tail = destlist->tail;
+  destlist->tail = savetail;
+  *savetail = NULL;
+}
+
 /* Set the output format type.  -oformat overrides scripts.  */
 
 void

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  1:23 [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API Dave Korn
@ 2011-01-29  1:45 ` H.J. Lu
  2011-01-29  2:01   ` H.J. Lu
  0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2011-01-29  1:45 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

On Fri, Jan 28, 2011 at 5:48 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
>
>    Hi list,
>
>  This patch updates the existing plugin API in LD to correct the effective
> link order of the files added by the plugin.  (It does not deal with the need
> for pass-throughs; that is a separate and orthogonal issue that I will tackle
> in a subsequent patch.  I hope that the combination of these two fixes should
> address all the same issues HJ's two-stage linking approach was designed to fix.)
>
>  At the moment added files and libraries are simply concatenated onto the end
> of the statement list.  This is more-or-less the same as adding them onto the
> end of the command-line; this means that their contributions get merged into
> sections after all the non-IR files, including in particular crtend.o.  That's
> pretty serious when it results in something like this:
>
>> .eh_frame       0x00404000      0x200
>>  *(.eh_frame)
>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>  .eh_frame      0x00404058       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>>  .eh_frame      0x004040b4       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccF5bqWv.lto.o
>
> because it breaks EH!
>
>  The attached patch doesn't implement two-stage linking, but takes the
> approach Cary described(*) in GOLD:
>
>> On 03/12/2010 18:46, Cary Coutant wrote:
>>
>>> I should have remembered that I already dealt with this problem long
>>> ago -- gold defers the layout of all real objects that follow the
>>> first claimed IR file until after the replacement files have been laid
>>> out. With respect to physical layout of the sections, this effectively
>>> makes the link order equivalent to putting the replacement files in
>>> the place of the first IR file. No "endcap" option is necessary.
>
>  In LD, there's nothing to "defer", as layout hasn't begun yet.  All we need
> to do is add the replacement files into the middle of the existing statement
> list, immediately after the first claimed IR file.  Complicated only slightly
> by the fact that there are in fact three separate singly-linked chains through
> the list of statements, that's what this patch does, and it results in the
> correct result:
>
>> .eh_frame       0x00404000      0x200
>>  *(.eh_frame)
>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>  .eh_frame      0x00404058       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccfuGGNR.lto.o
>>  .eh_frame      0x004040c0       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>
> ld/ChangeLog:
>
> 2011-01-29  Dave Korn  <dave.korn.cygwin@gmail.com>
>
>        * ldlang.c (lang_process): After adding and opening new input files
>        passed from plugin, splice them into correct place in statement list
>        chains to preserve critical link order.
>        (lang_list_insert_after): New helper function.
>        (lang_list_remove_tail): Likewise.
>
>  Built and tested on i686-pc-cygwin.  I'm running a subset of the G++/GCC
> testsuites to sanity-check it as well, and I'll put it through a cycle or two
> on one of the cfarm machines while I'm at it.
>

On hjl/lto-mixed branch, I added a dozen LTO tests.  They are tested
if GCC supports LTO.  You should try your ld changes on those new
LTO tests.  You can ignore those mixed IR failures. But other LTO tests
should pass.  I can post a patch for LTO testcases if you want.

-- 
H.J.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  1:45 ` H.J. Lu
@ 2011-01-29  2:01   ` H.J. Lu
  2011-01-29  2:05     ` H.J. Lu
  0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2011-01-29  2:01 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 4268 bytes --]

On Fri, Jan 28, 2011 at 5:45 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Jan 28, 2011 at 5:48 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
>>
>>    Hi list,
>>
>>  This patch updates the existing plugin API in LD to correct the effective
>> link order of the files added by the plugin.  (It does not deal with the need
>> for pass-throughs; that is a separate and orthogonal issue that I will tackle
>> in a subsequent patch.  I hope that the combination of these two fixes should
>> address all the same issues HJ's two-stage linking approach was designed to fix.)
>>
>>  At the moment added files and libraries are simply concatenated onto the end
>> of the statement list.  This is more-or-less the same as adding them onto the
>> end of the command-line; this means that their contributions get merged into
>> sections after all the non-IR files, including in particular crtend.o.  That's
>> pretty serious when it results in something like this:
>>
>>> .eh_frame       0x00404000      0x200
>>>  *(.eh_frame)
>>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>>  .eh_frame      0x00404058       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>>>  .eh_frame      0x004040b4       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccF5bqWv.lto.o
>>
>> because it breaks EH!
>>
>>  The attached patch doesn't implement two-stage linking, but takes the
>> approach Cary described(*) in GOLD:
>>
>>> On 03/12/2010 18:46, Cary Coutant wrote:
>>>
>>>> I should have remembered that I already dealt with this problem long
>>>> ago -- gold defers the layout of all real objects that follow the
>>>> first claimed IR file until after the replacement files have been laid
>>>> out. With respect to physical layout of the sections, this effectively
>>>> makes the link order equivalent to putting the replacement files in
>>>> the place of the first IR file. No "endcap" option is necessary.
>>
>>  In LD, there's nothing to "defer", as layout hasn't begun yet.  All we need
>> to do is add the replacement files into the middle of the existing statement
>> list, immediately after the first claimed IR file.  Complicated only slightly
>> by the fact that there are in fact three separate singly-linked chains through
>> the list of statements, that's what this patch does, and it results in the
>> correct result:
>>
>>> .eh_frame       0x00404000      0x200
>>>  *(.eh_frame)
>>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>>  .eh_frame      0x00404058       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccfuGGNR.lto.o
>>>  .eh_frame      0x004040c0       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>>
>> ld/ChangeLog:
>>
>> 2011-01-29  Dave Korn  <dave.korn.cygwin@gmail.com>
>>
>>        * ldlang.c (lang_process): After adding and opening new input files
>>        passed from plugin, splice them into correct place in statement list
>>        chains to preserve critical link order.
>>        (lang_list_insert_after): New helper function.
>>        (lang_list_remove_tail): Likewise.
>>
>>  Built and tested on i686-pc-cygwin.  I'm running a subset of the G++/GCC
>> testsuites to sanity-check it as well, and I'll put it through a cycle or two
>> on one of the cfarm machines while I'm at it.
>>
>
> On hjl/lto-mixed branch, I added a dozen LTO tests.  They are tested
> if GCC supports LTO.  You should try your ld changes on those new
> LTO tests.  You can ignore those mixed IR failures. But other LTO tests
> should pass.  I can post a patch for LTO testcases if you want.
>

Here is the new LTO tests.  The current LD in CVS failed:

FAIL: LTO 2
FAIL: ld-plugin/lto-4r-a
FAIL: ld-plugin/lto-4r-b
FAIL: ld-plugin/lto-4r-c
FAIL: ld-plugin/lto-4r-d
FAIL: LTO 3 symbol
FAIL: LTO 5 symbol
FAIL: LTO 4a
FAIL: LTO 4c
FAIL: LTO 4d
FAIL: LTO 10
FAIL: LTO 8

You can ignore

FAIL: ld-plugin/lto-4r-a
FAIL: ld-plugin/lto-4r-b
FAIL: ld-plugin/lto-4r-c
FAIL: ld-plugin/lto-4r-d
FAIL: LTO 3 symbol
FAIL: LTO 5 symbol
FAIL: LTO 4a
FAIL: LTO 4c
FAIL: LTO 4d
FAIL: LTO 10

But all other tests should pass.


-- 
H.J.

[-- Attachment #2: ld-lto-test-1.patch --]
[-- Type: text/plain, Size: 32482 bytes --]

diff --git a/ld/testsuite/ld-plugin/dummy.c b/ld/testsuite/ld-plugin/dummy.c
new file mode 100644
index 0000000..5c03287
--- /dev/null
+++ b/ld/testsuite/ld-plugin/dummy.c
@@ -0,0 +1 @@
+/* An empty file.  */
diff --git a/ld/testsuite/ld-plugin/dummy.s b/ld/testsuite/ld-plugin/dummy.s
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ld/testsuite/ld-plugin/dummy.s
@@ -0,0 +1 @@
+
diff --git a/ld/testsuite/ld-plugin/func1p.c b/ld/testsuite/ld-plugin/func1p.c
new file mode 100644
index 0000000..917dcbb
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func1p.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("protected")))
+func1 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func2.c b/ld/testsuite/ld-plugin/func2.c
new file mode 100644
index 0000000..d233fcf
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func2.c
@@ -0,0 +1,7 @@
+
+extern int retval;
+
+int func2 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func2i.c b/ld/testsuite/ld-plugin/func2i.c
new file mode 100644
index 0000000..00d7cdd
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func2i.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("internal")))
+func2 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func3h.c b/ld/testsuite/ld-plugin/func3h.c
new file mode 100644
index 0000000..525de63
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func3h.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("hidden")))
+func3 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/lto-10.out b/ld/testsuite/ld-plugin/lto-10.out
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-10.out
@@ -0,0 +1 @@
+hello
diff --git a/ld/testsuite/ld-plugin/lto-10a.c b/ld/testsuite/ld-plugin/lto-10a.c
new file mode 100644
index 0000000..93d57b5
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-10a.c
@@ -0,0 +1,6 @@
+extern int foo(void);
+
+int main(void)
+{
+  return foo();
+}
diff --git a/ld/testsuite/ld-plugin/lto-10b.c b/ld/testsuite/ld-plugin/lto-10b.c
new file mode 100644
index 0000000..507055b
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-10b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int foo(void)
+{
+  printf ("hello\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-10r.d b/ld/testsuite/ld-plugin/lto-10r.d
new file mode 100644
index 0000000..689e6ec
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-10r.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-10a.o tmpdir/lto-10b.o
+#source: dummy.s
+#nm: -p
+
+#...
+[0-9a-f]+ C __gnu_lto_v.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-11.out b/ld/testsuite/ld-plugin/lto-11.out
new file mode 100644
index 0000000..899682a
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-11.out
@@ -0,0 +1,2 @@
+Hello from foo!
+Hello from bar!
diff --git a/ld/testsuite/ld-plugin/lto-11a.c b/ld/testsuite/ld-plugin/lto-11a.c
new file mode 100644
index 0000000..5193972
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-11a.c
@@ -0,0 +1,9 @@
+extern void foo(void);
+extern void bar(void);
+
+int main(void)
+{
+  foo();
+  bar();
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-11b.c b/ld/testsuite/ld-plugin/lto-11b.c
new file mode 100644
index 0000000..62d61ec
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-11b.c
@@ -0,0 +1,6 @@
+extern int printf(const char *, ...);
+
+void foo(void)
+{
+  printf("Hello from %s!\n", __FUNCTION__);
+}
diff --git a/ld/testsuite/ld-plugin/lto-11c.c b/ld/testsuite/ld-plugin/lto-11c.c
new file mode 100644
index 0000000..8cd40b9
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-11c.c
@@ -0,0 +1,6 @@
+extern int printf(const char *, ...);
+
+void bar(void)
+{
+  printf("Hello from %s!\n", __FUNCTION__);
+}
diff --git a/ld/testsuite/ld-plugin/lto-12.out b/ld/testsuite/ld-plugin/lto-12.out
new file mode 100644
index 0000000..d86bac9
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-12.out
@@ -0,0 +1 @@
+OK
diff --git a/ld/testsuite/ld-plugin/lto-12a.c b/ld/testsuite/ld-plugin/lto-12a.c
new file mode 100644
index 0000000..30ff3d9
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-12a.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int value;
+
+int
+main (int argc, char **argv)
+{
+  int n = 10 * (argc + 1);
+  char *p = malloc (n);
+  __builtin_memcpy (p, argv[0], n);
+  if (value != -1)
+    abort ();
+  printf ("OK\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-12b.c b/ld/testsuite/ld-plugin/lto-12b.c
new file mode 100644
index 0000000..c2b00e4
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-12b.c
@@ -0,0 +1 @@
+int value = -1;
diff --git a/ld/testsuite/ld-plugin/lto-12c.c b/ld/testsuite/ld-plugin/lto-12c.c
new file mode 100644
index 0000000..ecd1bd4
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-12c.c
@@ -0,0 +1,15 @@
+#include <string.h>
+
+extern int value;
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+  char *d = (char *) dest;
+  const char *s = (const char *) src;
+
+  while (n--)
+    *d++ = *s++;
+
+  value = 1;
+  return dest;
+}
diff --git a/ld/testsuite/ld-plugin/lto-13.out b/ld/testsuite/ld-plugin/lto-13.out
new file mode 100644
index 0000000..3bd1f0e
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-13.out
@@ -0,0 +1,2 @@
+foo
+bar
diff --git a/ld/testsuite/ld-plugin/lto-13a.c b/ld/testsuite/ld-plugin/lto-13a.c
new file mode 100644
index 0000000..5193972
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-13a.c
@@ -0,0 +1,9 @@
+extern void foo(void);
+extern void bar(void);
+
+int main(void)
+{
+  foo();
+  bar();
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-13b.c b/ld/testsuite/ld-plugin/lto-13b.c
new file mode 100644
index 0000000..7c87a5e
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-13b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+bar (void)
+{
+  printf ("bar\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-13c.c b/ld/testsuite/ld-plugin/lto-13c.c
new file mode 100644
index 0000000..4859019
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-13c.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+foo (void)
+{
+  printf ("foo\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-1a.c b/ld/testsuite/ld-plugin/lto-1a.c
new file mode 100644
index 0000000..b775d0a
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-1a.c
@@ -0,0 +1,4 @@
+unsigned long long bar (unsigned long long y)
+{
+  return 30 / y;
+}
diff --git a/ld/testsuite/ld-plugin/lto-1b.c b/ld/testsuite/ld-plugin/lto-1b.c
new file mode 100644
index 0000000..8a961ef
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-1b.c
@@ -0,0 +1,8 @@
+extern unsigned long long bar (unsigned long long);
+
+int
+main (int argc, char **argv)
+{
+  unsigned long long d = bar ((unsigned long long) (argc + 1));
+  return d;
+}
diff --git a/ld/testsuite/ld-plugin/lto-2.c b/ld/testsuite/ld-plugin/lto-2.c
new file mode 100644
index 0000000..f0eacf4
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-2.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+int
+main (int argc, char **argv)
+{
+  int d = atoi (argv[1]);
+  printf ("%f\n", sin (d));
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-3.d b/ld/testsuite/ld-plugin/lto-3.d
new file mode 100644
index 0000000..c3a9a16
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3.d
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f]+ T foo
+#...
diff --git a/ld/testsuite/ld-plugin/lto-3.out b/ld/testsuite/ld-plugin/lto-3.out
new file mode 100644
index 0000000..a69f8f3
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3.out
@@ -0,0 +1,2 @@
+hello foo
+hello bar
diff --git a/ld/testsuite/ld-plugin/lto-3a.c b/ld/testsuite/ld-plugin/lto-3a.c
new file mode 100644
index 0000000..5193972
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3a.c
@@ -0,0 +1,9 @@
+extern void foo(void);
+extern void bar(void);
+
+int main(void)
+{
+  foo();
+  bar();
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-3b.c b/ld/testsuite/ld-plugin/lto-3b.c
new file mode 100644
index 0000000..c24f6d4
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3b.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void foo(void)
+{
+  printf ("hello foo\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-3c.c b/ld/testsuite/ld-plugin/lto-3c.c
new file mode 100644
index 0000000..95b3bc0
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3c.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void bar(void)
+{
+  printf ("hello bar\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-3r.d b/ld/testsuite/ld-plugin/lto-3r.d
new file mode 100644
index 0000000..1d1befe
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-3r.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-3b.o
+#source: dummy.s
+#nm: -p
+
+#...
+[0-9a-f]+ C __gnu_lto_v.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-4.out b/ld/testsuite/ld-plugin/lto-4.out
new file mode 100644
index 0000000..8d8cc92
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4.out
@@ -0,0 +1,2 @@
+hello bar
+hello foo
diff --git a/ld/testsuite/ld-plugin/lto-4a.c b/ld/testsuite/ld-plugin/lto-4a.c
new file mode 100644
index 0000000..2d07cf5
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4a.c
@@ -0,0 +1,7 @@
+extern void foo(void);
+
+int main(void)
+{
+  foo();
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-4b.c b/ld/testsuite/ld-plugin/lto-4b.c
new file mode 100644
index 0000000..bb4a68b
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4b.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+extern void bar (void);
+
+void foo(void)
+{
+  bar ();
+  printf ("hello foo\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-4c.c b/ld/testsuite/ld-plugin/lto-4c.c
new file mode 100644
index 0000000..317e6fc
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4c.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void bar (void)
+{
+  printf ("hello bar\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-4r-a.d b/ld/testsuite/ld-plugin/lto-4r-a.d
new file mode 100644
index 0000000..c618cff
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4r-a.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-4a.o tmpdir/lto-4b.o tmpdir/lto-4c.o
+#source: dummy.s
+#objdump: -h
+
+#...
+.* .gnu_object_only.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-4r-b.d b/ld/testsuite/ld-plugin/lto-4r-b.d
new file mode 100644
index 0000000..07d71cb
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4r-b.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-4a.o tmpdir/lto-4b.o
+#source: dummy.s
+#objdump: -h
+
+#...
+.* .gnu_object_only.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-4r-c.d b/ld/testsuite/ld-plugin/lto-4r-c.d
new file mode 100644
index 0000000..ada50c0
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4r-c.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-4r-b.o tmpdir/lto-4c.o
+#source: dummy.s
+#objdump: -h
+
+#...
+.* .gnu_object_only.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-4r-d.d b/ld/testsuite/ld-plugin/lto-4r-d.d
new file mode 100644
index 0000000..d4c5852
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-4r-d.d
@@ -0,0 +1,7 @@
+#ld: -r --whole-archive tmpdir/liblto-4.a
+#source: dummy.s
+#objdump: -h
+
+#...
+.* .gnu_object_only.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-5.d b/ld/testsuite/ld-plugin/lto-5.d
new file mode 100644
index 0000000..c3a9a16
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-5.d
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f]+ T foo
+#...
diff --git a/ld/testsuite/ld-plugin/lto-5.out b/ld/testsuite/ld-plugin/lto-5.out
new file mode 100644
index 0000000..dfbb215
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-5.out
@@ -0,0 +1 @@
+hello foo
diff --git a/ld/testsuite/ld-plugin/lto-5a.c b/ld/testsuite/ld-plugin/lto-5a.c
new file mode 100644
index 0000000..2d07cf5
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-5a.c
@@ -0,0 +1,7 @@
+extern void foo(void);
+
+int main(void)
+{
+  foo();
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-5b.c b/ld/testsuite/ld-plugin/lto-5b.c
new file mode 100644
index 0000000..c24f6d4
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-5b.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void foo(void)
+{
+  printf ("hello foo\n");
+}
diff --git a/ld/testsuite/ld-plugin/lto-5r.d b/ld/testsuite/ld-plugin/lto-5r.d
new file mode 100644
index 0000000..43e9a5c
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-5r.d
@@ -0,0 +1,7 @@
+#ld: -r tmpdir/lto-5a.o tmpdir/lto-5b.o
+#source: dummy.s
+#nm: -p
+
+#...
+[0-9a-f]+ C __gnu_lto_v.*
+#pass
diff --git a/ld/testsuite/ld-plugin/lto-6.c b/ld/testsuite/ld-plugin/lto-6.c
new file mode 100644
index 0000000..749e4e0
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-6.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+extern char _etext[];
+
+int main(void)
+{
+  printf ("%p: %d\n", _etext, _etext[0]);
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-7.out b/ld/testsuite/ld-plugin/lto-7.out
new file mode 100644
index 0000000..d86bac9
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-7.out
@@ -0,0 +1 @@
+OK
diff --git a/ld/testsuite/ld-plugin/lto-7a.c b/ld/testsuite/ld-plugin/lto-7a.c
new file mode 100644
index 0000000..d277a43
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-7a.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int foo = -1;
+
+extern void bar ();
+
+int
+main (int argc, char **argv)
+{
+  bar ();
+  printf ("OK\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-7b.c b/ld/testsuite/ld-plugin/lto-7b.c
new file mode 100644
index 0000000..1798130
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-7b.c
@@ -0,0 +1,8 @@
+extern int foo;
+
+static void
+__attribute__ ((unused, constructor))
+set_foo (void)
+{
+  foo = 30;
+}
diff --git a/ld/testsuite/ld-plugin/lto-7c.c b/ld/testsuite/ld-plugin/lto-7c.c
new file mode 100644
index 0000000..5236f57
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-7c.c
@@ -0,0 +1,9 @@
+extern int foo;
+extern int foo2;
+
+static void
+__attribute__ ((unused, constructor))
+set_foo (void)
+{
+  foo = foo2;
+}
diff --git a/ld/testsuite/ld-plugin/lto-7d.c b/ld/testsuite/ld-plugin/lto-7d.c
new file mode 100644
index 0000000..7fc1ff1
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-7d.c
@@ -0,0 +1,11 @@
+#include <stdlib.h>
+
+extern int foo;
+int foo2 = 2;
+
+void
+bar (void)
+{
+  if (foo != 30)
+    abort ();
+}
diff --git a/ld/testsuite/ld-plugin/lto-8.out b/ld/testsuite/ld-plugin/lto-8.out
new file mode 100644
index 0000000..35c5d69
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-8.out
@@ -0,0 +1 @@
+baz: 42
diff --git a/ld/testsuite/ld-plugin/lto-8a.c b/ld/testsuite/ld-plugin/lto-8a.c
new file mode 100644
index 0000000..6901fb3
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-8a.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+void baz(int i)
+{ 
+  printf ("baz: %d\n", i);
+}
+
+int main(void)
+{
+  foo(42);
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-8b.c b/ld/testsuite/ld-plugin/lto-8b.c
new file mode 100644
index 0000000..3b6db5f
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-8b.c
@@ -0,0 +1,14 @@
+extern int bar(void) __attribute__((__visibility__("hidden"), __const__));
+extern void baz(int);
+
+void foo(char c)
+{
+  int i;
+
+  if (bar())
+    i = c;
+  else
+    i = c;
+
+  baz(i);
+}
diff --git a/ld/testsuite/ld-plugin/lto-9.cc b/ld/testsuite/ld-plugin/lto-9.cc
new file mode 100644
index 0000000..2a4dcde
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-9.cc
@@ -0,0 +1,9 @@
+struct Foooo {
+  virtual ~Foooo () { }
+};
+
+int main(void)
+{
+  Foooo t;
+  return 0;
+}
diff --git a/ld/testsuite/ld-plugin/lto-9.d b/ld/testsuite/ld-plugin/lto-9.d
new file mode 100644
index 0000000..4b5bcf8
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto-9.d
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f]+ . .*Foooo::Foooo.*
+#...
diff --git a/ld/testsuite/ld-plugin/lto.exp b/ld/testsuite/ld-plugin/lto.exp
new file mode 100644
index 0000000..0c49cec
--- /dev/null
+++ b/ld/testsuite/ld-plugin/lto.exp
@@ -0,0 +1,233 @@
+# Expect script for ld-plugin LTO tests
+#   Copyright 2011
+#   Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# These tests require plugin and LTO.
+if { ![check_plugin_api_available]
+     || ![check_lto_available] } {
+    return
+}
+
+# Simple LTO tests and generate input files for complex LTO tests.
+set lto_link_tests {
+  {"LTO 1"
+   "-O2 -flto -fuse-linker-plugin" "-flto -fuse-linker-plugin"
+   {lto-1a.c lto-1b.c} {} "lto-1.exe"}
+  {"Build libdummy.a 2"
+   "" "-O2 -flto -fuse-linker-plugin"
+   {lto-2.c} {} "libdummy.a"}
+  {"LTO 2"
+   "-static -O2 -flto -fuse-linker-plugin tmpdir/lto-2.o -lm" ""
+   {dummy.c} {} "lto-2.exe"}
+  {"Build libdummy.a 3a"
+   "" "-flto"
+   {lto-3a.c} {} "libdummy.a"}
+  {"Build libdummy.a 3c"
+   "" "-O2"
+   {lto-3c.c} {} "libdummy.a"}
+  {"Build liblto-3.a"
+   "" "-flto"
+   {lto-3b.c} {} "liblto-3.a"}
+  {"Build libdummy.a 4a"
+   "" "-flto"
+   {lto-4a.c} {} "libdummy.a"}
+  {"Build libdummy.a 4b"
+   "" "-O2"
+   {lto-4b.c} {} "libdummy.a"}
+  {"Build libdummy.a 4c"
+   "" "-O2"
+   {lto-4c.c} {} "libdummy.a"}
+  {"Build libdummy.a 5a"
+   "" "-flto"
+   {lto-5a.c} {} "libdummy.a"}
+  {"Build libdummy.a 5b"
+   "" "-flto"
+   {lto-5b.c} {} "libdummy.a"}
+  {"LTO 6"
+   "-O2 -flto -fuse-linker-plugin" ""
+   {lto-6.c} {} "lto-6.exe" "c"}
+  {"Build libdummy.a PR ld/12365"
+   "" "-flto -O2"
+   {pr12365a.c pr12365b.c pr12365c.c} {} "libdummy.a"}
+  {"Build libdummy.a 9"
+   "" "-O2 -flto"
+   {lto-9.cc} {} "libdummy.a"}
+  {"Build libdummy.a 10a"
+   "" "-O2"
+   {lto-10a.c} {} "libdummy.a"}
+  {"Build libdummy.a 10b"
+   "" "-O2 -flto"
+   {lto-10b.c} {} "libdummy.a"}
+  {"Build libdummy.a 11a"
+   "" "-O -flto"
+   {lto-11a.c} {} "libdummy.a"}
+  {"Build libdummy.a 11b"
+   "" "-O -flto"
+   {lto-11b.c} {} "libdummy.a"}
+  {"Build libdummy.a 11c"
+   "" "-O"
+   {lto-11c.c} {} "libdummy.a"}
+  {"Build liblto-12.a"
+   "" "-O2 -flto"
+   {lto-12c.c} {} "liblto-12.a"}
+  {"Build libdummy.a 12"
+   "" "-O2 -flto"
+   {lto-12a.c lto-12b.c} {} "libdummy.a"}
+  {"Build libdummy.a 13"
+   "" "-O2 -flto"
+   {lto-13a.c lto-13b.c} {} "libdummy.a"}
+  {"Build liblto-13.a"
+   "" "-O2"
+   {lto-13c.c} {} "liblto-13.a"}
+}
+
+# Generate input files for complex LTO tests for ELF.
+set lto_link_elf_tests {
+  {"Build libdummy.a 7"
+   "" "-flto -O2"
+   {lto-7a.c lto-7b.c lto-7c.c} {} "libdummy.a"}
+  {"Build liblto-7.so"
+   "-shared" "-O2 -fpic"
+   {lto-7d.c} {} "liblto-7.so" "c"}
+  {"Build libdummy.a 8a"
+   "" "-O2"
+   {lto-8a.c} {} "libdummy.a"}
+  {"Build libdummy.a 8b"
+   "" "-flto -O2"
+   {lto-8b.c} {} "libdummy.a"}
+}
+
+# Check final symbols in executables.
+set lto_link_symbol_tests {
+  {"LTO 3 symbol"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/liblto-3.a" ""
+   {dummy.c} {{"nm" {} "lto-3.d"}} "lto-3.exe" "c"}
+  {"LTO 5 symbol"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-5.o" ""
+   {dummy.c} {{"nm" {} "lto-5.d"}} "lto-5.exe" "c"}
+  {"LTO 9 symbol"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-9.o" ""
+   {dummy.c} {{"nm" {-C} "lto-9.d"}} "lto-9.exe" "c++"}
+}
+
+# LTO run-time tests.
+set lto_run_tests {
+  {"LTO 3a"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/liblto-3.a" ""
+   {dummy.c} "lto-3b.exe" "lto-3.out" "" "c"}
+  {"LTO 3b"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o tmpdir/lto-3.o" ""
+   {dummy.c} "lto-3c.exe" "lto-3.out" "" "c"}
+  {"LTO 3c"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-3a.o tmpdir/lto-3c.o -Wl,--whole-archive tmpdir/liblto-3.a -Wl,--no-whole-archive tmpdir/liblto-3.a" ""
+   {dummy.c} "lto-3d.exe" "lto-3.out" "" "c"}
+  {"LTO 4a"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-a.o" ""
+   {dummy.c} "lto-4a.exe" "lto-4.out" "" "c"}
+  {"LTO 4c"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-c.o" ""
+   {dummy.c} "lto-4c.exe" "lto-4.out" "" "c"}
+  {"LTO 4d"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-d.o" ""
+   {dummy.c} "lto-4d.exe" "lto-4.out" "" "c"}
+  {"LTO 5"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-5.o" ""
+   {dummy.c} "lto-5.exe" "lto-5.out" "" "c"}
+  {"LTO 10"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-10.o" ""
+   {dummy.c} "lto-10.exe" "lto-10.out" "" "c"}
+  {"LTO 11"
+   "-O -flto -fuse-linker-plugin tmpdir/liblto-11.a" ""
+   {dummy.c} "lto-11.exe" "lto-11.out" "" "c"}
+  {"LTO 12a"
+   "-O -flto -fuse-linker-plugin tmpdir/lto-12a.o tmpdir/liblto-12.a tmpdir/lto-12b.o" ""
+   {dummy.c} "lto-12a.exe" "lto-12.out" "" "c"}
+  {"LTO 12b"
+   "-O -flto -fuse-linker-plugin tmpdir/lto-12a.o tmpdir/lto-12b.o tmpdir/liblto-12.a" ""
+   {dummy.c} "lto-12b.exe" "lto-12.out" "" "c"}
+  {"LTO 13"
+   "-O -flto -fuse-linker-plugin tmpdir/lto-13a.o tmpdir/liblto-13.a tmpdir/lto-13b.o" ""
+   {dummy.c} "lto-13.exe" "lto-13.out" "" "c"}
+}
+
+# LTO run-time tests for ELF
+set lto_run_elf_tests {
+  {"LTO 7"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-7b.o tmpdir/lto-7c.o tmpdir/lto-7a.o tmpdir/liblto-7.so" ""
+   {dummy.c} "lto-7.exe" "lto-7.out" "" "c"}
+  {"LTO 8"
+   "-O2 -flto -fuse-linker-plugin tmpdir/lto-8b.o tmpdir/lto-8a.o" ""
+   {dummy.c} "lto-8.exe" "lto-8.out" "" "c"}
+}
+
+run_cc_link_tests $lto_link_tests
+
+if { [is_elf_format] } {
+    run_cc_link_tests $lto_link_elf_tests
+}
+
+set testname "Build liblto-4.a"
+remote_file host delete "tmpdir/liblto-4.a"
+set catch_output [run_host_cmd "$ar" "rc tmpdir/liblto-4.a tmpdir/lto-4a.o tmpdir/lto-4b.o tmpdir/lto-4c.o"]
+if {![string match "" $catch_output]} {
+    unresolved $testname
+    return
+}
+
+set testname "Build liblto-11.a"
+remote_file host delete "tmpdir/liblto-11.a"
+set catch_output [run_host_cmd "$ar" "rc tmpdir/liblto-11.a tmpdir/lto-11a.o tmpdir/lto-11b.o tmpdir/lto-11c.o"]
+if {![string match "" $catch_output]} {
+    unresolved $testname
+    return
+}
+
+# Check exported LTO linker errors.
+set testname "PR ld/12365"
+set exec_output [run_host_cmd "$CC" "-O2 -flto -fuse-linker-plugin tmpdir/pr12365a.o tmpdir/pr12365b.o tmpdir/pr12365c.o"]
+if { [ regexp "undefined reference to `my_bcopy'" $exec_output ] } {
+    pass $testname
+} {
+    fail $testname
+}
+
+# Run "ld -r" to generate inputs for complex LTO tests.
+run_dump_test "lto-3r"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-3.o"
+run_dump_test "lto-4r-a"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-4r-a.o"
+run_dump_test "lto-4r-b"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-4r-b.o"
+run_dump_test "lto-4r-c"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-4r-c.o"
+run_dump_test "lto-4r-d"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-4r-d.o"
+run_dump_test "lto-5r"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-5.o"
+run_dump_test "lto-10r"
+remote_exec host "mv" "tmpdir/dump tmpdir/lto-10.o"
+
+run_cc_link_tests $lto_link_symbol_tests
+
+run_ld_link_exec_tests [] $lto_run_tests
+
+if { [is_elf_format] } {
+    run_ld_link_exec_tests [] $lto_run_elf_tests
+}
diff --git a/ld/testsuite/ld-plugin/plugin-7.d b/ld/testsuite/ld-plugin/plugin-7.d
index 75f25e0..ee7a6eb 100644
--- a/ld/testsuite/ld-plugin/plugin-7.d
+++ b/ld/testsuite/ld-plugin/plugin-7.d
@@ -19,7 +19,8 @@ tv\[16\]: LDPT_OPTION 'registerallsymbolsread'
 tv\[17\]: LDPT_OPTION 'registercleanup'
 tv\[18\]: LDPT_OPTION 'claim:tmpdir/func.o'
 tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
-tv\[20\]: LDPT_NULL value        0x0 \(0\)
+tv\[20\]: LDPT_OPTION 'add:tmpdir/func.o'
+tv\[21\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin-8.d b/ld/testsuite/ld-plugin/plugin-8.d
index e72b039..a4db899 100644
--- a/ld/testsuite/ld-plugin/plugin-8.d
+++ b/ld/testsuite/ld-plugin/plugin-8.d
@@ -21,7 +21,9 @@ tv\[18\]: LDPT_OPTION 'claim:tmpdir/func.o'
 tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
 tv\[20\]: LDPT_OPTION 'sym:_?func2::0:0:0'
 tv\[21\]: LDPT_OPTION 'dumpresolutions'
-tv\[22\]: LDPT_NULL value        0x0 \(0\)
+tv\[22\]: LDPT_OPTION 'add:tmpdir/func.o'
+tv\[23\]: LDPT_OPTION 'add:tmpdir/func2.o'
+tv\[24\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin-9.d b/ld/testsuite/ld-plugin/plugin-9.d
index b74f4a6..a4db899 100644
--- a/ld/testsuite/ld-plugin/plugin-9.d
+++ b/ld/testsuite/ld-plugin/plugin-9.d
@@ -22,7 +22,8 @@ tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
 tv\[20\]: LDPT_OPTION 'sym:_?func2::0:0:0'
 tv\[21\]: LDPT_OPTION 'dumpresolutions'
 tv\[22\]: LDPT_OPTION 'add:tmpdir/func.o'
-tv\[23\]: LDPT_NULL value        0x0 \(0\)
+tv\[23\]: LDPT_OPTION 'add:tmpdir/func2.o'
+tv\[24\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin.exp b/ld/testsuite/ld-plugin/plugin.exp
index 8952f1d..fd0f939 100644
--- a/ld/testsuite/ld-plugin/plugin.exp
+++ b/ld/testsuite/ld-plugin/plugin.exp
@@ -70,6 +70,7 @@ set plugin_nm_output ""
 if { $can_compile && \
 	(![ld_compile "$CC $CFLAGS" $srcdir/$subdir/main.c tmpdir/main.o] \
 	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/func.c tmpdir/func.o] \
+	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/func2.c tmpdir/func2.o] \
 	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/text.c tmpdir/text.o]) } {
     # Defer fail until we have list of tests set.
     set failed_compile 1
@@ -108,12 +109,15 @@ set plugin_tests [list \
     [list "plugin claimfile replace symbol" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
 			-plugin-opt sym:${_}func::0:0:0 \
+			-plugin-opt add:tmpdir/func.o \
     $testobjfiles $libs" "" "" {{ld plugin-7.d}} "main.x" ] \
     [list "plugin claimfile resolve symbol" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
 			-plugin-opt sym:${_}func::0:0:0 \
 			-plugin-opt sym:${_}func2::0:0:0 \
 			-plugin-opt dumpresolutions \
+			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func2.o \
     $testobjfiles $libs" "" "" {{ld plugin-8.d}} "main.x" ] \
     [list "plugin claimfile replace file" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
@@ -121,6 +125,7 @@ set plugin_tests [list \
 			-plugin-opt sym:${_}func2::0:0:0 \
 			-plugin-opt dumpresolutions \
 			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func2.o \
     $testobjfiles $libs" "" "" {{ld plugin-9.d}} "main.x" ] \
 ]
 
@@ -152,6 +157,10 @@ set plugin_extra_elf_tests [list \
 			-plugin-opt sym:${_}func2::0:2:0 \
 			-plugin-opt sym:${_}func3::0:3:0 \
 			-plugin-opt dumpresolutions \
+			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func1p.o \
+			-plugin-opt add:tmpdir/func2i.o \
+			-plugin-opt add:tmpdir/func3h.o \
     $testobjfiles $libs" "" "" {{ld plugin-ignore.d} \
 				{readelf -s plugin-vis-1.d}} "main.x" ] \
 ]
@@ -170,7 +179,10 @@ if { !$can_compile || $failed_compile } {
 
 run_ld_link_tests $plugin_tests
 
-if { [is_elf_format] } {
+if { [is_elf_format] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func1p.c tmpdir/func1p.o] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func2i.c tmpdir/func2i.o] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func3h.c tmpdir/func3h.o] } {
     run_ld_link_tests $plugin_extra_elf_tests
 }
 
diff --git a/ld/testsuite/ld-plugin/pr12365a.c b/ld/testsuite/ld-plugin/pr12365a.c
new file mode 100644
index 0000000..a9bb6c6
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr12365a.c
@@ -0,0 +1,25 @@
+extern void abort(void);
+extern void main_test (void);
+extern void abort (void);
+int inside_main;
+
+int
+main ()
+{
+  inside_main = 1;
+  main_test ();
+  inside_main = 0;
+  return 0;
+}
+
+/* When optimizing, all the constant cases should have been
+   constant folded, so no calls to link_error should remain.
+   In any case, link_error should not be called.  */
+
+#ifndef __OPTIMIZE__
+void
+link_error (void)
+{
+  abort ();
+}
+#endif
diff --git a/ld/testsuite/ld-plugin/pr12365b.c b/ld/testsuite/ld-plugin/pr12365b.c
new file mode 100644
index 0000000..3e86e06
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr12365b.c
@@ -0,0 +1,47 @@
+#define ASMNAME(cname)  ASMNAME2 (__USER_LABEL_PREFIX__, cname)
+#define ASMNAME2(prefix, cname) STRING (prefix) cname
+#define STRING(x)    #x
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern void *memcpy (void *, const void *, size_t)
+  __asm (ASMNAME ("my_memcpy"));
+extern void bcopy (const void *, void *, size_t)
+  __asm (ASMNAME ("my_bcopy"));
+extern void *memset (void *, int, size_t)
+  __asm (ASMNAME ("my_memset"));
+extern void bzero (void *, size_t)
+  __asm (ASMNAME ("my_bzero"));
+extern int memcmp (const void *, const void *, size_t);
+
+struct A { char c[32]; } a = { "foobar" };
+char x[64] = "foobar", y[64];
+int i = 39, j = 6, k = 4;
+
+extern int inside_main;
+
+void
+main_test (void)
+{
+  struct A b = a;
+  struct A c = { { 'x' } };
+
+  inside_main = 1;
+  
+  if (memcmp (b.c, x, 32) || c.c[0] != 'x' || memcmp (c.c + 1, x + 32, 31))
+    abort ();
+  if (__builtin_memcpy (y, x, i) != y || memcmp (x, y, 64))
+    abort ();
+  if (memcpy (y + 6, x, j) != y + 6
+      || memcmp (x, y, 6) || memcmp (x, y + 6, 58))
+    abort ();
+  if (__builtin_memset (y + 2, 'X', k) != y + 2
+      || memcmp (y, "foXXXXfoobar", 13))
+    abort ();
+  bcopy (y + 1, y + 2, 6);
+  if (memcmp (y, "fooXXXXfobar", 13))
+    abort ();
+  __builtin_bzero (y + 4, 2);
+  if (memcmp (y, "fooX\0\0Xfobar", 13))
+    abort ();
+}
diff --git a/ld/testsuite/ld-plugin/pr12365c.c b/ld/testsuite/ld-plugin/pr12365c.c
new file mode 100644
index 0000000..2edd0ff
--- /dev/null
+++ b/ld/testsuite/ld-plugin/pr12365c.c
@@ -0,0 +1,79 @@
+extern void abort (void);
+extern int inside_main;
+typedef __SIZE_TYPE__ size_t;
+
+#define TEST_ABORT if (inside_main) abort()
+
+void *
+my_memcpy (void *d, const void *s, size_t n)
+{
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  while (n--)
+    *dst++ = *src++;
+  return (char *) d;
+}
+
+void
+my_bcopy (const void *s, void *d, size_t n)
+{
+  char *dst = (char *) d;
+  const char *src = (const char *) s;
+  if (src >= dst)
+    while (n--)
+      *dst++ = *src++;
+  else
+    {
+      dst += n;
+      src += n;
+      while (n--)
+        *--dst = *--src;
+    }
+}
+
+void *
+my_memset (void *d, int c, size_t n)
+{
+  char *dst = (char *) d;
+  while (n--)
+    *dst++ = c;
+  return (char *) d;
+}
+
+void
+my_bzero (void *d, size_t n)
+{
+  char *dst = (char *) d;
+  while (n--)
+    *dst++ = '\0';
+}
+
+void *
+memcpy (void *d, const void *s, size_t n)
+{
+  void *result = my_memcpy (d, s, n);
+  TEST_ABORT;
+  return result;
+}
+
+void
+bcopy (const void *s, void *d, size_t n)
+{
+  my_bcopy (s, d, n);
+  TEST_ABORT;
+}
+
+void *
+memset (void *d, int c, size_t n)
+{
+  void *result = my_memset (d, c, n);
+  TEST_ABORT;
+  return result;
+}
+
+void
+bzero (void *d, size_t n)
+{
+  my_bzero (d, n);
+  TEST_ABORT;
+}
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 48e9635..74bad74 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -1461,6 +1461,34 @@ proc check_plugin_api_available { } {
     return $plugin_api_available_saved
 }
 
+# Returns true if the target compiler supports LTO
+proc check_lto_available { } {
+    global lto_available_saved
+    global CC
+    if {![info exists lto_available_saved]} {
+	# Check if gcc supports -flto -fuse-linker-plugin
+	if { [which $CC] == 0 } {
+	    set lto_available_saved 0
+	    return 0
+	}
+	set basename "lto"
+	set src ${basename}[pid].c
+	set output ${basename}[pid].s
+	set f [open $src "w"]
+	puts $f ""
+	close $f
+	set status [remote_exec host $CC "-S -flto -fuse-linker-plugin $src -o $output"]
+	if { [lindex $status 0] == 0 } {
+	    set lto_available_saved 1
+	} else {
+	    set lto_available_saved 0
+	}
+	file delete $src
+	file delete $output
+    }
+    return $lto_available_saved
+}
+
 # Check if the assembler supports CFI statements.
 
 proc check_as_cfi { } {

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  2:01   ` H.J. Lu
@ 2011-01-29  2:05     ` H.J. Lu
  2011-01-29  2:11       ` Dave Korn
  2011-01-29  4:11       ` Dave Korn
  0 siblings, 2 replies; 14+ messages in thread
From: H.J. Lu @ 2011-01-29  2:05 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

On Fri, Jan 28, 2011 at 6:01 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Jan 28, 2011 at 5:45 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Fri, Jan 28, 2011 at 5:48 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
>>>
>>>    Hi list,
>>>
>>>  This patch updates the existing plugin API in LD to correct the effective
>>> link order of the files added by the plugin.  (It does not deal with the need
>>> for pass-throughs; that is a separate and orthogonal issue that I will tackle
>>> in a subsequent patch.  I hope that the combination of these two fixes should
>>> address all the same issues HJ's two-stage linking approach was designed to fix.)
>>>
>>>  At the moment added files and libraries are simply concatenated onto the end
>>> of the statement list.  This is more-or-less the same as adding them onto the
>>> end of the command-line; this means that their contributions get merged into
>>> sections after all the non-IR files, including in particular crtend.o.  That's
>>> pretty serious when it results in something like this:
>>>
>>>> .eh_frame       0x00404000      0x200
>>>>  *(.eh_frame)
>>>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>>>  .eh_frame      0x00404058       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>>>>  .eh_frame      0x004040b4       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccF5bqWv.lto.o
>>>
>>> because it breaks EH!
>>>
>>>  The attached patch doesn't implement two-stage linking, but takes the
>>> approach Cary described(*) in GOLD:
>>>
>>>> On 03/12/2010 18:46, Cary Coutant wrote:
>>>>
>>>>> I should have remembered that I already dealt with this problem long
>>>>> ago -- gold defers the layout of all real objects that follow the
>>>>> first claimed IR file until after the replacement files have been laid
>>>>> out. With respect to physical layout of the sections, this effectively
>>>>> makes the link order equivalent to putting the replacement files in
>>>>> the place of the first IR file. No "endcap" option is necessary.
>>>
>>>  In LD, there's nothing to "defer", as layout hasn't begun yet.  All we need
>>> to do is add the replacement files into the middle of the existing statement
>>> list, immediately after the first claimed IR file.  Complicated only slightly
>>> by the fact that there are in fact three separate singly-linked chains through
>>> the list of statements, that's what this patch does, and it results in the
>>> correct result:
>>>
>>>> .eh_frame       0x00404000      0x200
>>>>  *(.eh_frame)
>>>>  .eh_frame      0x00404000       0x58 /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtbegin.o
>>>>  .eh_frame      0x00404058       0x68 /win/c/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ccfuGGNR.lto.o
>>>>  .eh_frame      0x004040c0       0x5c /gnu/gcc/obj-clean-r169274/gcc/testsuite/g++/../../crtend.o
>>>
>>> ld/ChangeLog:
>>>
>>> 2011-01-29  Dave Korn  <dave.korn.cygwin@gmail.com>
>>>
>>>        * ldlang.c (lang_process): After adding and opening new input files
>>>        passed from plugin, splice them into correct place in statement list
>>>        chains to preserve critical link order.
>>>        (lang_list_insert_after): New helper function.
>>>        (lang_list_remove_tail): Likewise.
>>>
>>>  Built and tested on i686-pc-cygwin.  I'm running a subset of the G++/GCC
>>> testsuites to sanity-check it as well, and I'll put it through a cycle or two
>>> on one of the cfarm machines while I'm at it.
>>>
>>
>> On hjl/lto-mixed branch, I added a dozen LTO tests.  They are tested
>> if GCC supports LTO.  You should try your ld changes on those new
>> LTO tests.  You can ignore those mixed IR failures. But other LTO tests
>> should pass.  I can post a patch for LTO testcases if you want.
>>
>
> Here is the new LTO tests.  The current LD in CVS failed:
>
> FAIL: LTO 2
> FAIL: ld-plugin/lto-4r-a
> FAIL: ld-plugin/lto-4r-b
> FAIL: ld-plugin/lto-4r-c
> FAIL: ld-plugin/lto-4r-d
> FAIL: LTO 3 symbol
> FAIL: LTO 5 symbol
> FAIL: LTO 4a
> FAIL: LTO 4c
> FAIL: LTO 4d
> FAIL: LTO 10
> FAIL: LTO 8
>
> You can ignore
>
> FAIL: ld-plugin/lto-4r-a
> FAIL: ld-plugin/lto-4r-b
> FAIL: ld-plugin/lto-4r-c
> FAIL: ld-plugin/lto-4r-d
> FAIL: LTO 3 symbol
> FAIL: LTO 5 symbol
> FAIL: LTO 4a
> FAIL: LTO 4c
> FAIL: LTO 4d
> FAIL: LTO 10
>
> But all other tests should pass.
>


I run your patch on those new LTO tests. I got relevant failures:

FAIL: LTO 2
FAIL: LTO 11
FAIL: LTO 8

Your patch doesn't fix any failures and introduce a new one.

-- 
H.J.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  2:05     ` H.J. Lu
@ 2011-01-29  2:11       ` Dave Korn
  2011-01-29  2:45         ` H.J. Lu
  2011-01-29  4:11       ` Dave Korn
  1 sibling, 1 reply; 14+ messages in thread
From: Dave Korn @ 2011-01-29  2:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils

On 29/01/2011 02:05, H.J. Lu wrote:

> I run your patch on those new LTO tests. I got relevant failures:
> 
> FAIL: LTO 2
> FAIL: LTO 11
> FAIL: LTO 8
> 
> Your patch doesn't fix any failures and introduce a new one.
> 

  Thanks for the testcases; I'll see what's going on and respin the patch as
needed.

    cheers,
      DaveK

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  2:11       ` Dave Korn
@ 2011-01-29  2:45         ` H.J. Lu
  2011-01-29  2:59           ` Dave Korn
  0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2011-01-29  2:45 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

On Fri, Jan 28, 2011 at 6:37 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
> On 29/01/2011 02:05, H.J. Lu wrote:
>
>> I run your patch on those new LTO tests. I got relevant failures:
>>
>> FAIL: LTO 2
>> FAIL: LTO 11
>> FAIL: LTO 8
>>
>> Your patch doesn't fix any failures and introduce a new one.
>>
>
>  Thanks for the testcases; I'll see what's going on and respin the patch as
> needed.

If you want to fix linker plugin without 2 stage linking, I think you
should follow
this gold patch:

http://sourceware.org/ml/binutils/2011-01/msg00270.html



-- 
H.J.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  2:45         ` H.J. Lu
@ 2011-01-29  2:59           ` Dave Korn
  0 siblings, 0 replies; 14+ messages in thread
From: Dave Korn @ 2011-01-29  2:59 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils

On 29/01/2011 02:45, H.J. Lu wrote:
> On Fri, Jan 28, 2011 at 6:37 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
>> On 29/01/2011 02:05, H.J. Lu wrote:
>>
>>> I run your patch on those new LTO tests. I got relevant failures:
>>>
>>> FAIL: LTO 2
>>> FAIL: LTO 11
>>> FAIL: LTO 8
>>>
>>> Your patch doesn't fix any failures and introduce a new one.
>>>
>>  Thanks for the testcases; I'll see what's going on and respin the patch as
>> needed.
> 
> If you want to fix linker plugin without 2 stage linking, I think you
> should follow
> this gold patch:
> 
> http://sourceware.org/ml/binutils/2011-01/msg00270.html

  Yes, I agree; that's the follow-on I mentioned I'd do next.

    cheers,
      DaveK

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  2:05     ` H.J. Lu
  2011-01-29  2:11       ` Dave Korn
@ 2011-01-29  4:11       ` Dave Korn
  2011-01-29  4:41         ` H.J. Lu
  1 sibling, 1 reply; 14+ messages in thread
From: Dave Korn @ 2011-01-29  4:11 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils

On 29/01/2011 02:05, H.J. Lu wrote:

> I run your patch on those new LTO tests. I got relevant failures:
> 
> FAIL: LTO 2
> FAIL: LTO 11
> FAIL: LTO 8
> 
> Your patch doesn't fix any failures and introduce a new one.

  It's not too bad.  The new fail is the assert firing where it can't find a
node to insert after when the only claimed objects come from a library; at the
moment it's checking the claimed flag only for the overall archive, which is
never set.  I'll just make it check the claimed flag for the archive members
and place the added files after the original archive in that case.

  LTO 2 passes both before and after on PE-COFF, and LTO 8 is ELF-only, so I'm
building the whole thing up on cfarm to see what's going on with those.  You
didn't mention your target - x86_64-linux, I'm guessing?

    cheers,
      DaveK

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
  2011-01-29  4:11       ` Dave Korn
@ 2011-01-29  4:41         ` H.J. Lu
  2011-01-31  1:57           ` [PATCH,take 2,trunk+2.21.1] " Dave Korn
  0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2011-01-29  4:41 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

On Fri, Jan 28, 2011 at 8:37 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
> On 29/01/2011 02:05, H.J. Lu wrote:
>
>> I run your patch on those new LTO tests. I got relevant failures:
>>
>> FAIL: LTO 2
>> FAIL: LTO 11
>> FAIL: LTO 8
>>
>> Your patch doesn't fix any failures and introduce a new one.
>
>  It's not too bad.  The new fail is the assert firing where it can't find a
> node to insert after when the only claimed objects come from a library; at the
> moment it's checking the claimed flag only for the overall archive, which is
> never set.  I'll just make it check the claimed flag for the archive members
> and place the added files after the original archive in that case.
>
>  LTO 2 passes both before and after on PE-COFF, and LTO 8 is ELF-only, so I'm
> building the whole thing up on cfarm to see what's going on with those.  You
> didn't mention your target - x86_64-linux, I'm guessing?
>

I tested it on Linux/x86.

-- 
H.J.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH,take 2,trunk+2.21.1] Re: Fix link order problem with LD plugin API.
  2011-01-29  4:41         ` H.J. Lu
@ 2011-01-31  1:57           ` Dave Korn
  2011-02-03  5:12             ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Dave Korn @ 2011-01-31  1:57 UTC (permalink / raw)
  To: H.J. Lu; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 2800 bytes --]

On 29/01/2011 04:41, H.J. Lu wrote:
> On Fri, Jan 28, 2011 at 8:37 PM, Dave Korn wrote:
>> On 29/01/2011 02:05, H.J. Lu wrote:
>>
>>> I run your patch on those new LTO tests. I got relevant failures:
>>>
>>> FAIL: LTO 2
>>> FAIL: LTO 11
>>> FAIL: LTO 8
>>>
>>> Your patch doesn't fix any failures and introduce a new one.
>>  It's not too bad.  The new fail is the assert firing where it can't find a
>> node to insert after when the only claimed objects come from a library; at the
>> moment it's checking the claimed flag only for the overall archive, which is
>> never set.  I'll just make it check the claimed flag for the archive members
>> and place the added files after the original archive in that case.
>>
>>  LTO 2 passes both before and after on PE-COFF, and LTO 8 is ELF-only, so I'm
>> building the whole thing up on cfarm to see what's going on with those.  You
>> didn't mention your target - x86_64-linux, I'm guessing?
>>
> 
> I tested it on Linux/x86.

  Right you are.  This updated version is cleverer about where it inserts the
replacement files into the statement list and file chains.

ld/ChangeLog:

2011-01-29  Dave Korn  <...

	* ldlang.h (lang_input_statement_type): Add new 'claim_archive' flag.
	* ldmain.c (add_archive_element): Set it if the member is claimed.
	* ldlang.c (new_afile): Initialise claim_archive and claimed members.
	(find_replacements_insert_point): New helper function.
	(lang_process): After adding and opening replacement files passed
	from plugin, splice them into correct place in statement list and
	file chains to preserve critical link order.
	(lang_list_insert_after): New helper function.
	(lang_list_remove_tail): Likewise.

  I tested this one on i686-unknown-linux-gnu.  LTO 2 still fails, because
there's no pass-through for -lm.  LTO 8 still fails, because we're still
generating undefined references to symbols from the original IR file's symtab
that aren't supplied by the replacement file, which runs afoul of the elf linker:

>   /* If a non-weak symbol with non-default visibility is not defined
>      locally, it is a fatal error.  */

... despite the fact that there are no references to the symbol in question.

  Neither of those is to do with the link order though, so this patch wouldn't
be expected to fix them.  The one real bug, LTO 11 is OK now.

  On i686-pc-cygwin, LTO 2 and LTO 11 pass (as in fact do LTO 7 and LTO 8;
they're not as ELF-specific as all that, after all).  I've run
g++.dg/stackalign.exp from the gcc testsuite, and all the EH failures I was
previously experiencing are fixed.  I'll run a full C/C++ testsuite later.

  I also tested it on x86_64-unknown-linux-gnu, including your ld-lto tests
and a gcc testsuite run (c,c++ only); no regressions in any of that.

  OK now?

    cheers,
      DaveK



[-- Attachment #2: ld.bfd-plugin-link-order-take2.diff --]
[-- Type: text/x-c, Size: 8387 bytes --]

Index: ld/ldlang.h
===================================================================
RCS file: /cvs/src/src/ld/ldlang.h,v
retrieving revision 1.95
diff -p -u -r1.95 ldlang.h
--- ld/ldlang.h	13 Jan 2011 13:34:54 -0000	1.95
+++ ld/ldlang.h	31 Jan 2011 00:41:22 -0000
@@ -290,6 +290,9 @@ typedef struct lang_input_statement_stru
   /* Set if the file was claimed by a plugin.  */
   unsigned int claimed : 1;
 
+  /* Set if the file was claimed from an archive.  */
+  unsigned int claim_archive : 1;
+
 } lang_input_statement_type;
 
 typedef struct
Index: ld/ldmain.c
===================================================================
RCS file: /cvs/src/src/ld/ldmain.c,v
retrieving revision 1.148
diff -p -u -r1.148 ldmain.c
--- ld/ldmain.c	14 Jan 2011 12:37:17 -0000	1.148
+++ ld/ldmain.c	31 Jan 2011 00:41:22 -0000
@@ -834,6 +834,7 @@ add_archive_element (struct bfd_link_inf
 	      /* Substitute the dummy BFD.  */
 	      input->the_bfd = file.handle;
 	      input->claimed = TRUE;
+	      input->claim_archive = TRUE;
 	      bfd_make_readable (input->the_bfd);
 	      *subsbfd = input->the_bfd;
 	    }
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.360
diff -p -u -r1.360 ldlang.c
--- ld/ldlang.c	14 Jan 2011 02:18:22 -0000	1.360
+++ ld/ldlang.c	31 Jan 2011 00:41:23 -0000
@@ -85,6 +85,11 @@ static void print_statement_list (lang_s
 static void print_statements (void);
 static void print_input_section (asection *, bfd_boolean);
 static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
+static void lang_list_insert_after (lang_statement_list_type *destlist,
+				    lang_statement_list_type *srclist,
+				    lang_statement_union_type **field);
+static void lang_list_remove_tail (lang_statement_list_type *destlist,
+				   lang_statement_list_type *origlist);
 static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
@@ -1126,6 +1131,8 @@ new_afile (const char *name,
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
   p->missing_file = FALSE;
+  p->claimed = FALSE;
+  p->claim_archive = FALSE;
 
   lang_statement_append (&input_file_chain,
 			 (lang_statement_union_type *) p,
@@ -6394,6 +6401,38 @@ lang_relax_sections (bfd_boolean need_la
     }
 }
 
+/* Find the insert point for the plugin's replacement files.  We
+   place them after the first claimed real object file, or if the
+   first claimed object is an archive member, after the last real
+   object file immediately preceding the archive.  In the event
+   no objects have been claimed at all, we return the first dummy
+   object file on the list as the insert point; that works, but
+   the callee must be careful when relinking the file_chain as it
+   is not actually on that chain, only the statement_list and the
+   input_file list; in that case, the replacement files must be
+   inserted at the head of the file_chain.  */
+
+static lang_input_statement_type *
+find_replacements_insert_point (void)
+{
+  lang_input_statement_type *claim1, *lastobject;
+  lastobject = &input_file_chain.head->input_statement;
+  for (claim1 = &file_chain.head->input_statement;
+       claim1 != NULL;
+       claim1 = &claim1->next->input_statement)
+    {
+      if (claim1->claimed)
+	return claim1->claim_archive ? lastobject : claim1;
+      /* Update lastobject if this is a real object file.  */
+      if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+	lastobject = claim1;
+    }
+  /* No files were claimed by the plugin.  Choose the last object
+     file found on the list (maybe the first, dummy entry) as the
+     insert point.  */
+  return lastobject;
+}
+
 void
 lang_process (void)
 {
@@ -6420,21 +6459,54 @@ lang_process (void)
   open_input_bfds (statement_list.head, FALSE);
 
 #ifdef ENABLE_PLUGINS
+  if (plugin_active_plugins_p ())
     {
-      union lang_statement_union **listend;
+      lang_statement_list_type added;
+      lang_statement_list_type files, inputfiles;
       /* Now all files are read, let the plugin(s) decide if there
 	 are any more to be added to the link before we call the
-	 emulation's after_open hook.  */
-      listend = statement_list.tail;
-      ASSERT (!*listend);
+	 emulation's after_open hook.  We create a private list of
+	 input statements for this purpose, which we will eventually
+	 insert into the global statment list after the first claimed
+	 file.  */
+      added = *stat_ptr;
+      /* We need to manipulate all three chains in synchrony.  */
+      files = file_chain;
+      inputfiles = input_file_chain;
       if (plugin_call_all_symbols_read ())
 	einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
 	       plugin_error_plugin ());
-      /* If any new files were added, they will be on the end of the
-	 statement list, and we can open them now by getting open_input_bfds
-	 to carry on from where it ended last time.  */
-      if (*listend)
-	open_input_bfds (*listend, FALSE);
+      /* Open any newly added files, updating the file chains.  */
+      open_input_bfds (added.head, FALSE);
+      /* Restore the global list pointer now they have all been added.  */
+      lang_list_remove_tail (stat_ptr, &added);
+      /* And detach the fresh ends of the file lists.  */
+      lang_list_remove_tail (&file_chain, &files);
+      lang_list_remove_tail (&input_file_chain, &inputfiles);
+      /* Were any new files added?  */
+      if (added.head != NULL)
+	{
+	  /* If so, we will insert them into the statement list immediately
+	     after the first input file that was claimed by the plugin.  */
+	  lang_input_statement_type *claim1 = find_replacements_insert_point ();
+	  /* If a plugin adds input files without having claimed any, we
+	     don't really have a good idea where to place them.  Just putting
+	     them at the start or end of the list is liable to leave them
+	     outside the crtbegin...crtend range.  */
+	  ASSERT (claim1 != NULL);
+	  /* Splice the new statement list into the old one after claim1.  */
+	  lang_list_insert_after (stat_ptr, &added, &claim1->header.next);
+	  /* Likewise for the file chains.  */
+	  lang_list_insert_after (&input_file_chain, &inputfiles,
+				  &claim1->next_real_file);
+	  /* We must be careful when relinking file_chain; we may need to
+	     insert the new files at the head of the list if the insert
+	     point chosen is the dummy first input file.  */
+	  if (claim1->filename)
+	    lang_list_insert_after (&file_chain, &files, &claim1->next);
+	  else
+	    lang_list_insert_after (&file_chain, &files, &file_chain.head);
+	}
     }
 #endif /* ENABLE_PLUGINS */
 
@@ -6857,6 +6929,50 @@ lang_statement_append (lang_statement_li
   list->tail = field;
 }
 
+/* Insert SRCLIST into DESTLIST after given element by chaining
+   on FIELD as the next-pointer.  (Counterintuitively does not need
+   a pointer to the actual after-node itself, just its chain field.)  */
+
+static void
+lang_list_insert_after (lang_statement_list_type *destlist,
+			lang_statement_list_type *srclist,
+			lang_statement_union_type **field)
+{
+  /* Are we adding at the very end of the list?  */
+  if (*field == NULL)
+    {
+      /* (*field == NULL) should imply (destlist->tail == field),
+	  if not then the element isn't really in the DESTLIST.  */
+      ASSERT (destlist->tail == field);
+      /* Yes, append to and update tail pointer.  */
+      *(destlist->tail) = srclist->head;
+      destlist->tail = srclist->tail;
+    }
+  else
+    {
+      /* We're inserting in the middle somewhere.  */
+      *(srclist->tail) = *field;
+      *field = srclist->head;
+    }
+}
+
+/* Detach new nodes added to DESTLIST since the time ORIGLIST
+   was taken as a copy of it and leave them in ORIGLIST.  */
+
+static void
+lang_list_remove_tail (lang_statement_list_type *destlist,
+		       lang_statement_list_type *origlist)
+{
+  union lang_statement_union **savetail;
+  /* Check that ORIGLIST really is an earlier state of DESTLIST.  */
+  ASSERT (origlist->head == destlist->head);
+  savetail = origlist->tail;
+  origlist->head = *(savetail);
+  origlist->tail = destlist->tail;
+  destlist->tail = savetail;
+  *savetail = NULL;
+}
+
 /* Set the output format type.  -oformat overrides scripts.  */
 
 void

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,take 2,trunk+2.21.1] Re: Fix link order problem with LD plugin API.
  2011-01-31  1:57           ` [PATCH,take 2,trunk+2.21.1] " Dave Korn
@ 2011-02-03  5:12             ` Alan Modra
  2011-02-03  5:44               ` Dave Korn
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2011-02-03  5:12 UTC (permalink / raw)
  To: Dave Korn; +Cc: H.J. Lu, binutils

On Mon, Jan 31, 2011 at 02:23:27AM +0000, Dave Korn wrote:
> 	* ldlang.h (lang_input_statement_type): Add new 'claim_archive' flag.
> 	* ldmain.c (add_archive_element): Set it if the member is claimed.
> 	* ldlang.c (new_afile): Initialise claim_archive and claimed members.
> 	(find_replacements_insert_point): New helper function.
> 	(lang_process): After adding and opening replacement files passed
> 	from plugin, splice them into correct place in statement list and
> 	file chains to preserve critical link order.
> 	(lang_list_insert_after): New helper function.
> 	(lang_list_remove_tail): Likewise.

OK.

> +  /* Are we adding at the very end of the list?  */
> +  if (*field == NULL)
> +    {
> +      /* (*field == NULL) should imply (destlist->tail == field),
> +	  if not then the element isn't really in the DESTLIST.  */
> +      ASSERT (destlist->tail == field);
> +      /* Yes, append to and update tail pointer.  */
> +      *(destlist->tail) = srclist->head;
> +      destlist->tail = srclist->tail;
> +    }
> +  else
> +    {
> +      /* We're inserting in the middle somewhere.  */
> +      *(srclist->tail) = *field;
> +      *field = srclist->head;
> +    }

Maybe this instead?

  *(srclist->tail) = *field;
  *field = srclist->head;
  if (destlist->tail == field)
    destlist->tail = srclist->tail;

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,take 2,trunk+2.21.1] Re: Fix link order problem with LD plugin API.
  2011-02-03  5:12             ` Alan Modra
@ 2011-02-03  5:44               ` Dave Korn
  2011-02-03 13:28                 ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Dave Korn @ 2011-02-03  5:44 UTC (permalink / raw)
  To: Dave Korn, H.J. Lu, binutils

On 03/02/2011 05:11, Alan Modra wrote:
> On Mon, Jan 31, 2011 at 02:23:27AM +0000, Dave Korn wrote:
>> 	* ldlang.h (lang_input_statement_type): Add new 'claim_archive' flag.
>> 	* ldmain.c (add_archive_element): Set it if the member is claimed.
>> 	* ldlang.c (new_afile): Initialise claim_archive and claimed members.
>> 	(find_replacements_insert_point): New helper function.
>> 	(lang_process): After adding and opening replacement files passed
>> 	from plugin, splice them into correct place in statement list and
>> 	file chains to preserve critical link order.
>> 	(lang_list_insert_after): New helper function.
>> 	(lang_list_remove_tail): Likewise.
> 
> OK.
> 
>> +  /* Are we adding at the very end of the list?  */
>> +  if (*field == NULL)
>> +    {
>> +      /* (*field == NULL) should imply (destlist->tail == field),
>> +	  if not then the element isn't really in the DESTLIST.  */
>> +      ASSERT (destlist->tail == field);
>> +      /* Yes, append to and update tail pointer.  */
>> +      *(destlist->tail) = srclist->head;
>> +      destlist->tail = srclist->tail;
>> +    }
>> +  else
>> +    {
>> +      /* We're inserting in the middle somewhere.  */
>> +      *(srclist->tail) = *field;
>> +      *field = srclist->head;
>> +    }
> 
> Maybe this instead?
> 
>   *(srclist->tail) = *field;
>   *field = srclist->head;
>   if (destlist->tail == field)
>     destlist->tail = srclist->tail;

  Seems like a good plan.  I notice that I omitted #ifdef ENABLE_PLUGINS
guards around those new functions, which, being static, will cause unused
warnings.  Respin shortly, along with a series of other patches (in
particular, something to get rid of those stray left-over symbols when the IR
symtabs in the input files mention something that ltrans subsequently decides
it can optimise away.)

    cheers,
      DaveK


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,take 2,trunk+2.21.1] Re: Fix link order problem with LD plugin API.
  2011-02-03  5:44               ` Dave Korn
@ 2011-02-03 13:28                 ` Alan Modra
  2011-02-05  1:56                   ` Alan Modra
  0 siblings, 1 reply; 14+ messages in thread
From: Alan Modra @ 2011-02-03 13:28 UTC (permalink / raw)
  To: Dave Korn; +Cc: H.J. Lu, binutils

On Thu, Feb 03, 2011 at 06:10:26AM +0000, Dave Korn wrote:
> particular, something to get rid of those stray left-over symbols when the IR
> symtabs in the input files mention something that ltrans subsequently decides
> it can optimise away.)

Good.  That can hide, at least until runtime, lto bugs.  I've been
poking a little at one today where a function was mentioned in the IR,
called in the final object, but not emitted.  So ld quite happily sent
the call to an IR symbol.

I have this in my tree to expose that particular problem, but haven't
tested it properly yet.  Results in

../../gcc-curr/gcc/xgcc -B../../gcc-curr/gcc/ -w -O2 -m32 -flto abs-2.i abs-2-lib.i main.i -lm
`main_test' referenced in section `.text.startup' of /tmp/ccBT9axe.ltrans0.ltrans.o: defined in discarded section `.text' of /tmp/ccgfeeJG.o.ironly\x04
collect2: ld returned 1 exit status


Index: ld/plugin.c
===================================================================
RCS file: /cvs/src/src/ld/plugin.c,v
retrieving revision 1.22
diff -u -p -r1.22 plugin.c
--- ld/plugin.c	22 Jan 2011 10:16:29 -0000	1.22
+++ ld/plugin.c	3 Feb 2011 13:23:50 -0000
@@ -243,8 +243,8 @@ plugin_get_ir_dummy_bfd (const char *nam
   sec = bfd_make_section_old_way (abfd, ".text");
   bfd_set_section_flags (abfd, sec,
 			 (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
-			  | SEC_ALLOC | SEC_LOAD | SEC_KEEP));
-  sec->output_section = sec;
+			  | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE));
+  sec->output_section = NULL;
   sec->output_offset = 0;
   return abfd;
 }


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH,take 2,trunk+2.21.1] Re: Fix link order problem with LD plugin API.
  2011-02-03 13:28                 ` Alan Modra
@ 2011-02-05  1:56                   ` Alan Modra
  0 siblings, 0 replies; 14+ messages in thread
From: Alan Modra @ 2011-02-05  1:56 UTC (permalink / raw)
  To: Dave Korn; +Cc: binutils

On Thu, Feb 03, 2011 at 11:58:35PM +1030, Alan Modra wrote:
> Good.  That can hide, at least until runtime, lto bugs.  I've been
> poking a little at one today where a function was mentioned in the IR,
> called in the final object, but not emitted.  So ld quite happily sent
> the call to an IR symbol.
> 
> I have this in my tree to expose that particular problem, but haven't
> tested it properly yet.  Results in
> 
> ../../gcc-curr/gcc/xgcc -B../../gcc-curr/gcc/ -w -O2 -m32 -flto abs-2.i abs-2-lib.i main.i -lm
> `main_test' referenced in section `.text.startup' of /tmp/ccBT9axe.ltrans0.ltrans.o: defined in discarded section `.text' of /tmp/ccgfeeJG.o.ironly\x04
> collect2: ld returned 1 exit status

With this patch I get these failures

FAIL: plugin claimfile replace symbol
FAIL: plugin claimfile resolve symbol
FAIL: plugin set symbol visibility

The problem is that these tests result in "func" having no real
definition, just an IR one.  Also, in the last test none of the IR
symbols will be emitted in the final object, which makes it a little
dificult to check their visibilities.

However, unless I'm missing something, we really do want that
a) a reloc against an IR only sym should give an error, and
b) IR only syms should not be emitted in the final object.

So, what should I do here?

	* plugin.c (plugin_get_ir_dummy_bfd): Set SEC_EXCLUDE on dummy
	.text section, use newer bfd_make_section variant.  Error handling.
	Correct setting of gp size.
	(asymbol_from_plugin_symbol): Properly cast last arg of concat.
	(message): Likewise for ACONCAT.
	(get_symbols): Formatting.

Index: ld/plugin.c
===================================================================
RCS file: /cvs/src/src/ld/plugin.c,v
retrieving revision 1.22
diff -u -p -r1.22 plugin.c
--- ld/plugin.c	22 Jan 2011 10:16:29 -0000	1.22
+++ ld/plugin.c	4 Feb 2011 01:41:40 -0000
@@ -229,24 +229,29 @@ plugin_opt_plugin_arg (const char *arg)
 bfd *
 plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
 {
-  asection *sec;
   bfd *abfd;
 
   bfd_use_reserved_id = 1;
-  abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *)NULL),
+  abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
 		     srctemplate);
-  bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
-  bfd_make_writable (abfd);
-  bfd_copy_private_bfd_data (srctemplate, abfd);
-  bfd_set_gp_size (abfd, bfd_get_gp_size (abfd));
-  /* Create a minimal set of sections to own the symbols.  */
-  sec = bfd_make_section_old_way (abfd, ".text");
-  bfd_set_section_flags (abfd, sec,
-			 (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
-			  | SEC_ALLOC | SEC_LOAD | SEC_KEEP));
-  sec->output_section = sec;
-  sec->output_offset = 0;
-  return abfd;
+  if (abfd != NULL)
+    {
+      bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
+      bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate));
+      if (bfd_make_writable (abfd)
+	  && bfd_copy_private_bfd_data (srctemplate, abfd))
+	{
+	  flagword flags;
+
+	  /* Create a section to own the symbols.  */
+	  flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
+		   | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE);
+	  if (bfd_make_section_anyway_with_flags (abfd, ".text", flags) != NULL)
+	    return abfd;
+	}
+    }
+  einfo (_("could not create dummy IR bfd: %F%E\n"));
+  return NULL;
 }
 
 /* Check if the BFD passed in is an IR dummy object file.  */
@@ -273,7 +278,7 @@ asymbol_from_plugin_symbol (bfd *abfd, a
 
   asym->the_bfd = abfd;
   asym->name = (ldsym->version
-		? concat (ldsym->name, "@", ldsym->version, NULL)
+		? concat (ldsym->name, "@", ldsym->version, (const char *) NULL)
 		: ldsym->name);
   asym->value = 0;
   switch (ldsym->def)
@@ -488,16 +493,17 @@ get_symbols (const void *handle, int nsy
       /* Find out which section owns the symbol.  Since it's not undef,
 	 it must have an owner; if it's not a common symbol, both defs
 	 and weakdefs keep it in the same place. */
-      owner_sec = (blhe->type == bfd_link_hash_common)
-	? blhe->u.c.p->section
-	: blhe->u.def.section;
+      owner_sec = (blhe->type == bfd_link_hash_common
+		   ? blhe->u.c.p->section
+		   : blhe->u.def.section);
 
       /* We need to know if the sym is referenced from non-IR files.  Or
 	 even potentially-referenced, perhaps in a future final link if
 	 this is a partial one, perhaps dynamically at load-time if the
 	 symbol is externally visible.  */
-      ironly = !is_visible_from_outside (&syms[n], owner_sec, blhe)
-	&& !bfd_hash_lookup (non_ironly_hash, syms[n].name, FALSE, FALSE);
+      ironly = (!is_visible_from_outside (&syms[n], owner_sec, blhe)
+		&& bfd_hash_lookup (non_ironly_hash, syms[n].name,
+				    FALSE, FALSE) == NULL);
 
       /* If it was originally undefined or common, then it has been
 	 resolved; determine how.  */
@@ -535,9 +541,9 @@ get_symbols (const void *handle, int nsy
 	}
 
       /* Was originally def, weakdef, or common, but has been pre-empted.  */
-      syms[n].resolution = is_ir_dummy_bfd (owner_sec->owner)
-	? LDPR_PREEMPTED_IR
-	: LDPR_PREEMPTED_REG;
+      syms[n].resolution = (is_ir_dummy_bfd (owner_sec->owner)
+			    ? LDPR_PREEMPTED_IR
+			    : LDPR_PREEMPTED_REG);
     }
   return LDPS_OK;
 }
@@ -595,9 +601,8 @@ message (int level, const char *format, 
     case LDPL_ERROR:
     default:
 	{
-	  char *newfmt = ACONCAT ((level == LDPL_FATAL
-				   ? "%P%F: " : "%P%X: ",
-				   format, "\n", NULL));
+	  char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ",
+				   format, "\n", (const char *) NULL));
 	  fflush (stdout);
 	  vfinfo (stderr, newfmt, args, TRUE);
 	  fflush (stderr);

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2011-02-05  1:56 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-29  1:23 [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API Dave Korn
2011-01-29  1:45 ` H.J. Lu
2011-01-29  2:01   ` H.J. Lu
2011-01-29  2:05     ` H.J. Lu
2011-01-29  2:11       ` Dave Korn
2011-01-29  2:45         ` H.J. Lu
2011-01-29  2:59           ` Dave Korn
2011-01-29  4:11       ` Dave Korn
2011-01-29  4:41         ` H.J. Lu
2011-01-31  1:57           ` [PATCH,take 2,trunk+2.21.1] " Dave Korn
2011-02-03  5:12             ` Alan Modra
2011-02-03  5:44               ` Dave Korn
2011-02-03 13:28                 ` Alan Modra
2011-02-05  1:56                   ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).