public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: "H.J. Lu" <hjl.tools@gmail.com>
To: Dave Korn <dave.korn.cygwin@gmail.com>
Cc: "binutils@sourceware.org" <binutils@sourceware.org>
Subject: Re: [PATCH,trunk+2.21.1] Fix link order problem with LD plugin API.
Date: Sat, 29 Jan 2011 02:01:00 -0000	[thread overview]
Message-ID: <AANLkTik6PH6WTFq_yRy1ceLwOu0u+t_LuRv4wyCCwgsk@mail.gmail.com> (raw)
In-Reply-To: <AANLkTino6tHjPdxZAaixhPfJKEX-mLeH8KaA5GkmDRFn@mail.gmail.com>

[-- 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 { } {

  reply	other threads:[~2011-01-29  2:01 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-29  1:23 Dave Korn
2011-01-29  1:45 ` H.J. Lu
2011-01-29  2:01   ` H.J. Lu [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AANLkTik6PH6WTFq_yRy1ceLwOu0u+t_LuRv4wyCCwgsk@mail.gmail.com \
    --to=hjl.tools@gmail.com \
    --cc=binutils@sourceware.org \
    --cc=dave.korn.cygwin@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).