aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.linux5
-rwxr-xr-xbfd/configure26
-rw-r--r--bfd/configure.ac4
-rw-r--r--bfd/version.m42
-rwxr-xr-xbinutils/configure20
-rwxr-xr-xgas/configure20
-rwxr-xr-xgprof/configure20
-rwxr-xr-xld/configure20
-rw-r--r--patches/README37
-rw-r--r--patches/binutils-lto-mixed.patch3342
-rw-r--r--patches/binutils-pr12639.patch104
-rw-r--r--patches/binutils-pr14675.patch197
-rw-r--r--patches/binutils-pr17729.patch592
-rw-r--r--patches/binutils-secondary.patch2197
-rw-r--r--patches/binutils-sharable.patch1305
15 files changed, 7835 insertions, 56 deletions
diff --git a/ChangeLog.linux b/ChangeLog.linux
new file mode 100644
index 0000000..6bf4e0a
--- /dev/null
+++ b/ChangeLog.linux
@@ -0,0 +1,5 @@
+2013-11-04 H.J. Lu <hjl.tools@gmail.com>
+
+ * bfd/configure.in (ACX_PKGVERSION): Pass "Linux/GNU Binutils".
+ (ACX_BUGURL): Add mailto:hjl.tools@gmail.com.
+ * bfd/configure: Regenerated.
diff --git a/bfd/configure b/bfd/configure
index f7a9e81..419a0de 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for bfd 2.25.51.
+# Generated by GNU Autoconf 2.64 for bfd 2.25.51.0.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -556,8 +556,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='bfd'
PACKAGE_TARNAME='bfd'
-PACKAGE_VERSION='2.25.51'
-PACKAGE_STRING='bfd 2.25.51'
+PACKAGE_VERSION='2.25.51.0.1'
+PACKAGE_STRING='bfd 2.25.51.0.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1349,7 +1349,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures bfd 2.25.51 to adapt to many kinds of systems.
+\`configure' configures bfd 2.25.51.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1420,7 +1420,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of bfd 2.25.51:";;
+ short | recursive ) echo "Configuration of bfd 2.25.51.0.1:";;
esac
cat <<\_ACEOF
@@ -1460,7 +1460,7 @@ Optional Packages:
--with-separate-debug-dir=DIR
Look for global separate debug info in DIR
[default=LIBDIR/debug]
- --with-pkgversion=PKG Use PKG in the version string in place of "GNU
+ --with-pkgversion=PKG Use PKG in the version string in place of "Linux/GNU
Binutils"
--with-bugurl=URL Direct users to URL to report a bug
--with-zlib include zlib support (auto/yes/no) default=auto
@@ -1541,7 +1541,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-bfd configure 2.25.51
+bfd configure 2.25.51.0.1
generated by GNU Autoconf 2.64
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2183,7 +2183,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by bfd $as_me 2.25.51, which was
+It was created by bfd $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
@@ -3991,7 +3991,7 @@ fi
# Define the identity of the package.
PACKAGE='bfd'
- VERSION='2.25.51'
+ VERSION='2.25.51.0.1'
cat >>confdefs.h <<_ACEOF
@@ -12206,7 +12206,7 @@ if test "${with_pkgversion+set}" = set; then :
*) PKGVERSION="($withval) " ;;
esac
else
- PKGVERSION="(GNU Binutils) "
+ PKGVERSION="(Linux/GNU Binutils) "
fi
@@ -12224,7 +12224,7 @@ if test "${with_bugurl+set}" = set; then :
;;
esac
else
- BUGURL="http://www.sourceware.org/bugzilla/"
+ BUGURL="http://www.sourceware.org/bugzilla/ and mailto:hjl.tools@gmail.com"
fi
@@ -16569,7 +16569,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by bfd $as_me 2.25.51, which was
+This file was extended by bfd $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -16633,7 +16633,7 @@ Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-bfd config.status 2.25.51
+bfd config.status 2.25.51.0.1
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 1b709dc..349e706 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -123,8 +123,8 @@ if test $want_elf_stt_common = true; then
[Define if we may generate symbols with ELF's STT_COMMON type])
fi
-ACX_PKGVERSION([GNU Binutils])
-ACX_BUGURL([http://www.sourceware.org/bugzilla/])
+ACX_PKGVERSION([Linux/GNU Binutils])
+ACX_BUGURL([http://www.sourceware.org/bugzilla/ and mailto:hjl.tools@gmail.com])
AM_BINUTILS_WARNINGS
diff --git a/bfd/version.m4 b/bfd/version.m4
index 0f2f235..58ece25 100644
--- a/bfd/version.m4
+++ b/bfd/version.m4
@@ -1 +1 @@
-m4_define([BFD_VERSION], [2.25.51])
+m4_define([BFD_VERSION], [2.25.51.0.1])
diff --git a/binutils/configure b/binutils/configure
index b960c19..30e51f0 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for binutils 2.25.51.
+# Generated by GNU Autoconf 2.64 for binutils 2.25.51.0.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -556,8 +556,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='binutils'
PACKAGE_TARNAME='binutils'
-PACKAGE_VERSION='2.25.51'
-PACKAGE_STRING='binutils 2.25.51'
+PACKAGE_VERSION='2.25.51.0.1'
+PACKAGE_STRING='binutils 2.25.51.0.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1333,7 +1333,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures binutils 2.25.51 to adapt to many kinds of systems.
+\`configure' configures binutils 2.25.51.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1404,7 +1404,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of binutils 2.25.51:";;
+ short | recursive ) echo "Configuration of binutils 2.25.51.0.1:";;
esac
cat <<\_ACEOF
@@ -1525,7 +1525,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-binutils configure 2.25.51
+binutils configure 2.25.51.0.1
generated by GNU Autoconf 2.64
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2167,7 +2167,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by binutils $as_me 2.25.51, which was
+It was created by binutils $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
@@ -3975,7 +3975,7 @@ fi
# Define the identity of the package.
PACKAGE='binutils'
- VERSION='2.25.51'
+ VERSION='2.25.51.0.1'
cat >>confdefs.h <<_ACEOF
@@ -15165,7 +15165,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by binutils $as_me 2.25.51, which was
+This file was extended by binutils $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15229,7 +15229,7 @@ Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-binutils config.status 2.25.51
+binutils config.status 2.25.51.0.1
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/gas/configure b/gas/configure
index 75d8a52..6f87593 100755
--- a/gas/configure
+++ b/gas/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for gas 2.25.51.
+# Generated by GNU Autoconf 2.64 for gas 2.25.51.0.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -556,8 +556,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='gas'
PACKAGE_TARNAME='gas'
-PACKAGE_VERSION='2.25.51'
-PACKAGE_STRING='gas 2.25.51'
+PACKAGE_VERSION='2.25.51.0.1'
+PACKAGE_STRING='gas 2.25.51.0.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1320,7 +1320,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gas 2.25.51 to adapt to many kinds of systems.
+\`configure' configures gas 2.25.51.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1391,7 +1391,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gas 2.25.51:";;
+ short | recursive ) echo "Configuration of gas 2.25.51.0.1:";;
esac
cat <<\_ACEOF
@@ -1505,7 +1505,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-gas configure 2.25.51
+gas configure 2.25.51.0.1
generated by GNU Autoconf 2.64
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -1915,7 +1915,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gas $as_me 2.25.51, which was
+It was created by gas $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
@@ -3723,7 +3723,7 @@ fi
# Define the identity of the package.
PACKAGE='gas'
- VERSION='2.25.51'
+ VERSION='2.25.51.0.1'
cat >>confdefs.h <<_ACEOF
@@ -15061,7 +15061,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by gas $as_me 2.25.51, which was
+This file was extended by gas $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15125,7 +15125,7 @@ Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-gas config.status 2.25.51
+gas config.status 2.25.51.0.1
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/gprof/configure b/gprof/configure
index 80c9aaf..4b85836 100755
--- a/gprof/configure
+++ b/gprof/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for gprof 2.25.51.
+# Generated by GNU Autoconf 2.64 for gprof 2.25.51.0.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -556,8 +556,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='gprof'
PACKAGE_TARNAME='gprof'
-PACKAGE_VERSION='2.25.51'
-PACKAGE_STRING='gprof 2.25.51'
+PACKAGE_VERSION='2.25.51.0.1'
+PACKAGE_STRING='gprof 2.25.51.0.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1299,7 +1299,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gprof 2.25.51 to adapt to many kinds of systems.
+\`configure' configures gprof 2.25.51.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1370,7 +1370,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gprof 2.25.51:";;
+ short | recursive ) echo "Configuration of gprof 2.25.51.0.1:";;
esac
cat <<\_ACEOF
@@ -1476,7 +1476,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-gprof configure 2.25.51
+gprof configure 2.25.51.0.1
generated by GNU Autoconf 2.64
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -1841,7 +1841,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gprof $as_me 2.25.51, which was
+It was created by gprof $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
@@ -3649,7 +3649,7 @@ fi
# Define the identity of the package.
PACKAGE='gprof'
- VERSION='2.25.51'
+ VERSION='2.25.51.0.1'
cat >>confdefs.h <<_ACEOF
@@ -12706,7 +12706,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by gprof $as_me 2.25.51, which was
+This file was extended by gprof $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12770,7 +12770,7 @@ Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-gprof config.status 2.25.51
+gprof config.status 2.25.51.0.1
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/ld/configure b/ld/configure
index 8a7bd20..210d90e 100755
--- a/ld/configure
+++ b/ld/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for ld 2.25.51.
+# Generated by GNU Autoconf 2.64 for ld 2.25.51.0.1.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
@@ -556,8 +556,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='ld'
PACKAGE_TARNAME='ld'
-PACKAGE_VERSION='2.25.51'
-PACKAGE_STRING='ld 2.25.51'
+PACKAGE_VERSION='2.25.51.0.1'
+PACKAGE_STRING='ld 2.25.51.0.1'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1347,7 +1347,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures ld 2.25.51 to adapt to many kinds of systems.
+\`configure' configures ld 2.25.51.0.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1418,7 +1418,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of ld 2.25.51:";;
+ short | recursive ) echo "Configuration of ld 2.25.51.0.1:";;
esac
cat <<\_ACEOF
@@ -1541,7 +1541,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-ld configure 2.25.51
+ld configure 2.25.51.0.1
generated by GNU Autoconf 2.64
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2250,7 +2250,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by ld $as_me 2.25.51, which was
+It was created by ld $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
$ $0 $@
@@ -4059,7 +4059,7 @@ fi
# Define the identity of the package.
PACKAGE='ld'
- VERSION='2.25.51'
+ VERSION='2.25.51.0.1'
cat >>confdefs.h <<_ACEOF
@@ -17594,7 +17594,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by ld $as_me 2.25.51, which was
+This file was extended by ld $as_me 2.25.51.0.1, which was
generated by GNU Autoconf 2.64. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -17658,7 +17658,7 @@ Report bugs to the package provider."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
-ld config.status 2.25.51
+ld config.status 2.25.51.0.1
configured by $0, generated by GNU Autoconf 2.64,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/patches/README b/patches/README
new file mode 100644
index 0000000..8bd659e
--- /dev/null
+++ b/patches/README
@@ -0,0 +1,37 @@
+#! /bin/sh
+
+# If you don't use rpm, you can use this file to apply additional Linux
+# patches. At the top level of the binutils source tree, do
+#
+# /bin/sh patches/README
+#
+# You may have to do
+#
+# cd bfd
+# make headers
+#
+# if the build fails.
+
+dir=`dirname $0`
+clean=$1
+
+patches="
+ binutils-sharable.patch
+ binutils-lto-mixed.patch
+ binutils-pr12639.patch
+ binutils-secondary.patch
+ binutils-pr17729.patch
+ binutils-pr14675.patch
+"
+
+for p in $patches
+do
+ if [ ! -n "$clean" ]
+ then
+ suffix=$(echo $p | sed -e "s/.*-\([^-]\+\).patch/\1/")
+ backup="-b --suffix .$suffix"
+ fi
+ patch --follow-symlinks -E -p1 $backup < $dir/$p || exit 1
+done
+find -name "*.orig" | xargs rm -fv
+find -name "*.gmo" | xargs rm -fv
diff --git a/patches/binutils-lto-mixed.patch b/patches/binutils-lto-mixed.patch
new file mode 100644
index 0000000..72444d4
--- /dev/null
+++ b/patches/binutils-lto-mixed.patch
@@ -0,0 +1,3342 @@
+From 27ef344287a7b58062e7f92c1eaefc5a54d75650 Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 4 Nov 2013 09:17:45 -0800
+Subject: [PATCH] Add lto and none-lto input support for ld -r
+
+This patch adds lto and none-lto input support for ld -r so that
+LTO can be used with ld -r without Makefile changes. It is useful
+for Linux kernel build with LTO.
+---
+ ChangeLog.lto-mixed | 315 ++++++++++++
+ bfd/bfd-in2.h | 22 +
+ bfd/bfd.c | 47 ++
+ bfd/elf.c | 1 +
+ bfd/elflink.c | 17 +
+ bfd/format.c | 34 +-
+ bfd/opncls.c | 66 +++
+ bfd/plugin.c | 162 +++++-
+ bfd/plugin.h | 2 +
+ bfd/section.c | 3 +
+ binutils/objcopy.c | 28 +-
+ binutils/readelf.c | 1 +
+ gas/testsuite/gas/elf/section9.d | 1 +
+ gas/testsuite/gas/elf/section9.s | 2 +
+ include/bfdlink.h | 6 +
+ include/elf/common.h | 1 +
+ ld/emultempl/aarch64elf.em | 6 +-
+ ld/emultempl/alphaelf.em | 2 +-
+ ld/emultempl/armelf.em | 6 +-
+ ld/emultempl/elf32.em | 39 +-
+ ld/emultempl/ppc64elf.em | 6 +-
+ ld/emultempl/spuelf.em | 6 +-
+ ld/ldfile.c | 2 +
+ ld/ldlang.c | 1029 ++++++++++++++++++++++++++++++++++++-
+ ld/ldlang.h | 45 +-
+ ld/ldlex.h | 1 +
+ ld/ldmain.c | 78 +--
+ ld/ldmain.h | 2 +
+ ld/lexsup.c | 6 +
+ ld/plugin.c | 36 +-
+ ld/plugin.h | 3 +
+ ld/scripttempl/armbpabi.sc | 2 +-
+ ld/scripttempl/elf.sc | 2 +-
+ ld/scripttempl/elf32sh-symbian.sc | 2 +-
+ ld/scripttempl/elf64hppa.sc | 2 +-
+ ld/scripttempl/elfxtensa.sc | 2 +-
+ ld/scripttempl/mep.sc | 2 +-
+ ld/scripttempl/pe.sc | 1 +
+ ld/scripttempl/pep.sc | 1 +
+ ld/testsuite/ld-plugin/lto-10.out | 1 +
+ ld/testsuite/ld-plugin/lto-10a.c | 6 +
+ ld/testsuite/ld-plugin/lto-10b.c | 7 +
+ ld/testsuite/ld-plugin/lto-10r.d | 7 +
+ ld/testsuite/ld-plugin/lto-4.out | 2 +
+ ld/testsuite/ld-plugin/lto-4a.c | 7 +
+ ld/testsuite/ld-plugin/lto-4b.c | 9 +
+ ld/testsuite/ld-plugin/lto-4c.c | 6 +
+ ld/testsuite/ld-plugin/lto-4r-a.d | 7 +
+ ld/testsuite/ld-plugin/lto-4r-b.d | 7 +
+ ld/testsuite/ld-plugin/lto-4r-c.d | 7 +
+ ld/testsuite/ld-plugin/lto-4r-d.d | 7 +
+ ld/testsuite/ld-plugin/lto.exp | 59 +++
+ ld/testsuite/ld-plugin/pr12365a.c | 25 +
+ ld/testsuite/ld-plugin/pr12365b.c | 47 ++
+ ld/testsuite/ld-plugin/pr12365c.c | 79 +++
+ ld/testsuite/ld-plugin/pr14918.c | 5 +
+ ld/testsuite/ld-plugin/pr14918.d | 4 +
+ 57 files changed, 2170 insertions(+), 111 deletions(-)
+ create mode 100644 ChangeLog.lto-mixed
+ create mode 100644 ld/testsuite/ld-plugin/lto-10.out
+ create mode 100644 ld/testsuite/ld-plugin/lto-10a.c
+ create mode 100644 ld/testsuite/ld-plugin/lto-10b.c
+ create mode 100644 ld/testsuite/ld-plugin/lto-10r.d
+ create mode 100644 ld/testsuite/ld-plugin/lto-4.out
+ create mode 100644 ld/testsuite/ld-plugin/lto-4a.c
+ create mode 100644 ld/testsuite/ld-plugin/lto-4b.c
+ create mode 100644 ld/testsuite/ld-plugin/lto-4c.c
+ create mode 100644 ld/testsuite/ld-plugin/lto-4r-a.d
+ create mode 100644 ld/testsuite/ld-plugin/lto-4r-b.d
+ create mode 100644 ld/testsuite/ld-plugin/lto-4r-c.d
+ create mode 100644 ld/testsuite/ld-plugin/lto-4r-d.d
+ create mode 100644 ld/testsuite/ld-plugin/pr12365a.c
+ create mode 100644 ld/testsuite/ld-plugin/pr12365b.c
+ create mode 100644 ld/testsuite/ld-plugin/pr12365c.c
+ create mode 100644 ld/testsuite/ld-plugin/pr14918.c
+ create mode 100644 ld/testsuite/ld-plugin/pr14918.d
+
+diff --git a/ChangeLog.lto-mixed b/ChangeLog.lto-mixed
+new file mode 100644
+index 0000000..bdbabea
+--- /dev/null
++++ b/ChangeLog.lto-mixed
+@@ -0,0 +1,317 @@
++bfd/
++
++2014-03-07 H.J. Lu <hongjiu.lu@intel.com>
++
++ * format.c (bfd_check_format_matches): Don't check the plugin
++ target twice.
++
++2013-02-15 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlang.c (lang_finish): Take a bfd_boolean argument to support
++ object-only output.
++ (cmdline_emit_object_only_section): Pass TRUE to lang_finish.
++
++ * ldlang.h (lang_finish): Updated.
++
++ * ldmain.c (main): Pass FALSE to lang_finish.
++
++2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/14747
++ * elflink.c (_bfd_elf_fix_symbol_flags): Check symbol for linker
++ created section instead.
++
++2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/14747
++ * elflink.c (_bfd_elf_fix_symbol_flags): Never mark
++ _GLOBAL_OFFSET_TABLE_, _PROCEDURE_LINKAGE_TABLE_ nor _DYNAMIC
++ undefined.
++
++2012-06-28 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/14272
++ * elflink.c (_bfd_elf_fix_symbol_flags): Mark the plugin symbol
++ undefined if it is referenced from a non-IR file.
++
++2012-06-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ * plugin.c (add_symbols): Set tdata.plugin_data before calling
++ bfd_plugin_get_symbols_in_object_only.
++
++2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
++
++ * plugin.c (add_symbols): Call
++ bfd_plugin_get_symbols_in_object_only.
++ (bfd_plugin_get_symtab_upper_bound): Don't call
++ bfd_plugin_get_symbols_in_object_only.
++
++2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
++
++ * plugin.c (bfd_plugin_get_symbols_in_object_only): Optimized.
++
++2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
++
++ * plugin.c (bfd_plugin_get_symbols_in_object_only): Properly
++ remove the object only section file.
++
++2011-10-15 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/13298
++ * opncls.c (bfd_extract_object_only_section): New.
++
++ * plugin.c (add_symbols): Initialize object_only_syms and
++ object_only_nsyms.
++ (bfd_plugin_fake_text_section): New.
++ (bfd_plugin_fake_common_section): Likewise.
++ (bfd_plugin_get_symbols_in_object_only): Likewise.
++ (bfd_plugin_get_symtab_upper_bound): Call
++ bfd_plugin_get_symbols_in_object_only and add symbols from
++ object only section.
++ (bfd_plugin_canonicalize_symtab): Remove fake_section and
++ fake_common_section. Use bfd_plugin_fake_text_section and
++ bfd_plugin_fake_common_section. Set udata.p to NULL. Copy
++ symbols from object only section.
++
++ * plugin.h (plugin_data_struct): Add object_only_nsyms and
++ object_only_syms.
++
++ * bfd-in2.h: Regenerated.
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfd.c (bfd_lto_object_type): New.
++ (bfd): Add object_only_section and lto_type.
++ (bfd_group_signature): New.
++
++ * elf.c (special_sections_g): Add .gnu_object_only.
++
++ * format.c (bfd_set_lto_type): New.
++ (bfd_check_format_matches): Use it.
++
++ * section.c (GNU_OBJECT_ONLY_SECTION_NAME): New.
++
++ * bfd-in2.h: Regenerated.
++
++binutils/
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * objcopy.c (group_signature): Removed.
++ (is_strip_section): Replace group_signature with
++ bfd_group_signature.
++ (setup_section): Likewise.
++
++ * readelf.c (get_section_type_name): Handle SHT_GNU_OBJECT_ONLY.
++
++gas/testsuite/
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * gas/elf/section9.s: Add the .gnu_object_only test.
++ * gas/elf/section9.d: Updated.
++
++include/
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_info): Add emit_gnu_object_only and
++ emitting_gnu_object_only.
++
++include/elf/
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * common.h (SHT_GNU_OBJECT_ONLY): New.
++
++ld/
++
++2014-01-11 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlang.c (cmdline_add_object_only_section): Save BFD filename
++ to be used after bfd_close ().
++
++2012-10-20 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlang.c (lang_process): Replace trace_file_tries with
++ verbose.
++
++2012-08-14 H.J. Lu <hongjiu.lu@intel.com>
++
++ * emultempl/aarch64elf.em (gld${EMULATION_NAME}_finish): Renamed
++ to ...
++ (aarch64_finish): This. Replace finish_default with
++ gld${EMULATION_NAME}_finish.
++ (LDEMUL_FINISH): Set to aarch64_finish.
++
++2011-10-15 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/13298
++ * ldlang.c (cmdline_extract_object_only_section): Call
++ bfd_extract_object_only_section.
++
++2011-05-17 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlang.c (cmdline_remove_object_only_files): Return if
++ ENABLE_PLUGINS is undefined or plugin_save_temps is true.
++
++2011-05-15 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
++ * lexsup.c (ld_options): Add -plugin-save-temps.
++ (parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
++
++ * plugin.c (plugin_save_temps): New.
++ (plugin_call_cleanup): Don't call plugin cleanup_handler if
++ plugin_save_temps is true.
++
++ * plugin.h (plugin_save_temps): New.
++
++2011-05-14 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/12760
++ * ldmain.c (warning_callback): Don't warn plugin dummy.
++
++2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
++
++ * emultempl/alphaelf.em (alpha_finish): Replace finish_default
++ with gld${EMULATION_NAME}_finish.
++
++ * emultempl/armelf.em (gld${EMULATION_NAME}_finish): Renamed
++ to ...
++ (arm_finish): This. Replace finish_default with
++ gld${EMULATION_NAME}_finish.
++ (LDEMUL_FINISH): Set to arm_finish.
++
++ * emultempl/elf32.em (gld${EMULATION_NAME}_finish): New.
++ (orphan_init_done): Likewise.
++ (ld_${EMULATION_NAME}_emulation): Use gld${EMULATION_NAME}_finish.
++ (gld${EMULATION_NAME}_place_orphan): Initialize hold.
++
++ * emultempl/ppc64elf.em (gld${EMULATION_NAME}_finish): Renamed
++ to ...
++ (ppc_finish): This. Replace finish_default with
++ gld${EMULATION_NAME}_finish.
++ (LDEMUL_FINISH): Set to ppc_finish.
++
++ * emultempl/spuelf.em (gld${EMULATION_NAME}_finish): Renamed
++ to ...
++ (spu_finish): This. Replace finish_default with
++ gld${EMULATION_NAME}_finish.
++ (LDEMUL_FINISH): Set to spu_finish.
++
++ * ldfile.c (ldfile_try_open_bfd): Call
++ cmdline_check_object_only_section.
++
++ * ldlang.c: Include "ldwrite.h" and elf-bfd.h.
++ * ldlang.c (cmdline_object_only_file_list): New.
++ (cmdline_object_only_archive_list): Likewise.
++ (cmdline_temp_object_only_list): Likewise.
++ (cmdline_lists_init): Likewise.
++ (cmdline_list_new): Likewise.
++ (cmdline_list_append): Likewise.
++ (print_cmdline_list): Likewise.
++ (cmdline_on_object_only_archive_list_p): Likewise.
++ (cmdline_object_only_list_append): Likewise.
++ (cmdline_get_object_only_input_files): Likewise.
++ (cmdline_arg): Likewise.
++ (setup_section): Likewise.
++ (copy_section): Likewise.
++ (cmdline_fopen_temp): Likewise.
++ (cmdline_add_object_only_section): Likewise.
++ (cmdline_emit_object_only_section): Likewise.
++ (cmdline_extract_object_only_section): Likewise.
++ (cmdline_check_object_only_section): Likewise.
++ (cmdline_remove_object_only_files): Likewise.
++ (lang_init): Take a bfd_boolean argument to supprt object-only
++ output. Call cmdline_lists_init.
++ (load_symbols): Call cmdline_on_object_only_archive_list_p
++ to check if an archive member should be loaded.
++ (lang_process): Handle object-only link.
++
++ * ldlang.h (lang_init): Take a bfd_boolean argument.
++ (cmdline_enum_type): New.
++ (cmdline_header_type): Likewise.
++ (cmdline_file_type): Likewise.
++ (cmdline_bfd_type): Likewise.
++ (cmdline_union_type): Likewise.
++ (cmdline_list_type): Likewise.
++ (cmdline_emit_object_only_section): Likewise.
++ (cmdline_check_object_only_section): Likewise.
++ (cmdline_remove_object_only_files): Likewise.
++
++ * ldmain.c (main): Call xatexit with
++ cmdline_remove_object_only_files. Pass FALSE to lang_init.
++ Use ld_parse_linker_script. Set link_info.output_bfd to NULL
++ after close. Call cmdline_emit_object_only_section if needed.
++ (add_archive_element): Call cmdline_check_object_only_section.
++ (ld_parse_linker_script): New.
++
++ * ldmain.h (ld_parse_linker_script): New.
++
++ * plugin.c (plugin_maybe_claim): Call
++ cmdline_check_object_only_section on claimed IR files.
++
++ * scripttempl/armbpabi.sc: Also discard .gnu_object_only
++ sections.
++ * scripttempl/elf.sc: Likewise.
++ * scripttempl/elf32sh-symbian.sc: Likewise.
++ * scripttempl/elf64hppa.sc: Likewise.
++ * scripttempl/elfxtensa.sc: Likewise.
++ * scripttempl/mep.sc: Likewise.
++ * scripttempl/pe.sc: Likewise.
++ * scripttempl/pep.sc: Likewise.
++
++ld/testsuite/
++
++2014-03-07 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld-plugin/lto.exp: Add test for nm on mixed LTO/non-LTO object.
++
++2012-12-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/14918
++ * ld-plugin/lto.exp (lto_link_elf_tests): Add PR ld/14918 test.
++
++ * ld-plugin/pr14918.c: New file.
++ * ld-plugin/pr14918.d: Likewise.
++
++2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/12365
++ * ld-plugin/pr12365a.c: New file.
++ * ld-plugin/pr12365b.c: Likewise.
++ * ld-plugin/pr12365c.c: Likewise.
++
++ * ld-plugin/lto.exp (lto_link_tests): Prepare for the PR ld/12365
++ test.
++ Run the PR ld/12365 test.
++
++2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/12430
++ * ld-plugin/lto-10.out: New file.
++ * ld-plugin/lto-10a.c: Likewise.
++ * ld-plugin/lto-10b.c: Likewise.
++ * ld-plugin/lto-10r.d: Likewise.
++
++ * ld-plugin/lto.exp (lto_link_tests): Prepare for "LTO 10".
++ (lto_run_tests): Add "LTO 10".
++ Run lto-10r and create tmpdir/lto-10.o.
++
++2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR ld/12291
++ * ld-plugin/lto-4.out: Likewise.
++ * ld-plugin/lto-4a.c: Likewise.
++ * ld-plugin/lto-4b.c: Likewise.
++ * ld-plugin/lto-4c.c: Likewise.
++ * ld-plugin/lto-4r-a.d: Likewise.
++ * ld-plugin/lto-4r-b.d: Likewise.
++ * ld-plugin/lto-4r-c.d: Likewise.
++ * ld-plugin/lto-4r-d.d: Likewise.
++
++ * ld-plugin/lto.exp (lto_link_tests): Prepare for "LTO 4[acd]"
++ and "lto-4r-[abcd]" tests.
++ (lto_run_tests): Add "LTO 4[acd]" tests.
++ Build liblto-4.a. Run "lto-4r-[abcd]" tests.
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index 8c77c81..1387606 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -1083,6 +1083,9 @@ struct bfd_section *bfd_create_gnu_debuglink_section
+ bfd_boolean bfd_fill_in_gnu_debuglink_section
+ (bfd *abfd, struct bfd_section *sect, const char *filename);
+
++const char *bfd_extract_object_only_section
++ (bfd *abfd);
++
+ /* Extracted from libbfd.c. */
+
+ /* Byte swapping macros for user section data. */
+@@ -1636,6 +1639,9 @@ extern asection _bfd_std_section[4];
+ #define BFD_COM_SECTION_NAME "*COM*"
+ #define BFD_IND_SECTION_NAME "*IND*"
+
++/* GNU object-only section name. */
++#define GNU_OBJECT_ONLY_SECTION_NAME ".gnu_object_only"
++
+ /* Pointer to the common section. */
+ #define bfd_com_section_ptr (&_bfd_std_section[0])
+ /* Pointer to the undefined section. */
+@@ -6239,6 +6245,14 @@ enum bfd_direction
+ both_direction = 3
+ };
+
++enum bfd_lto_object_type
++ {
++ lto_non_object,
++ lto_non_ir_object,
++ lto_ir_object,
++ lto_mixed_object
++ };
++
+ struct bfd
+ {
+ /* The filename the application opened the BFD with. */
+@@ -6395,6 +6409,9 @@ struct bfd
+ /* Set if this is the linker output BFD. */
+ unsigned int is_linker_output : 1;
+
++ /* LTO object type. */
++ unsigned int lto_type : 2;
++
+ /* Currently my_archive is tested before adding origin to
+ anything. I believe that this can become always an add of
+ origin, with origin set to 0 for non archive files. */
+@@ -6416,6 +6433,9 @@ struct bfd
+ /* The last section on the section list. */
+ struct bfd_section *section_last;
+
++ /* The object-only section on the section list. */
++ struct bfd_section *object_only_section;
++
+ /* The number of sections. */
+ unsigned int section_count;
+
+@@ -6717,6 +6737,8 @@ void bfd_emul_set_commonpagesize (const char *, bfd_vma);
+
+ char *bfd_demangle (bfd *, const char *, int);
+
++asymbol *bfd_group_signature (asection *group, asymbol **isympp);
++
+ /* Extracted from archive.c. */
+ symindex bfd_get_next_mapent
+ (bfd *abfd, symindex previous, carsym **sym);
+diff --git a/bfd/bfd.c b/bfd/bfd.c
+index 8b60911..537433c 100644
+--- a/bfd/bfd.c
++++ b/bfd/bfd.c
+@@ -44,6 +44,14 @@ CODE_FRAGMENT
+ . both_direction = 3
+ . };
+ .
++.enum bfd_lto_object_type
++. {
++. lto_non_object,
++. lto_non_ir_object,
++. lto_ir_object,
++. lto_mixed_object
++. };
++.
+ .struct bfd
+ .{
+ . {* The filename the application opened the BFD with. *}
+@@ -200,6 +208,9 @@ CODE_FRAGMENT
+ . {* Set if this is the linker output BFD. *}
+ . unsigned int is_linker_output : 1;
+ .
++. {* LTO object type. *}
++. unsigned int lto_type : 2;
++.
+ . {* Currently my_archive is tested before adding origin to
+ . anything. I believe that this can become always an add of
+ . origin, with origin set to 0 for non archive files. *}
+@@ -221,6 +232,9 @@ CODE_FRAGMENT
+ . {* The last section on the section list. *}
+ . struct bfd_section *section_last;
+ .
++. {* The object-only section on the section list. *}
++. struct bfd_section *object_only_section;
++.
+ . {* The number of sections. *}
+ . unsigned int section_count;
+ .
+@@ -1923,3 +1937,36 @@ bfd_demangle (bfd *abfd, const char *name, int options)
+
+ return res;
+ }
++
++/*
++FUNCTION
++ bfd_group_signature
++
++SYNOPSIS
++ asymbol *bfd_group_signature (asection *group, asymbol **isympp);
++
++DESCRIPTION
++ Return a pointer to the symbol used as a signature for GROUP.
++*/
++
++asymbol *
++bfd_group_signature (asection *group, asymbol **isympp)
++{
++ bfd *abfd = group->owner;
++ Elf_Internal_Shdr *ghdr;
++
++ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
++ return NULL;
++
++ ghdr = &elf_section_data (group)->this_hdr;
++ if (ghdr->sh_link < elf_numsections (abfd))
++ {
++ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++ Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
++
++ if (symhdr->sh_type == SHT_SYMTAB
++ && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
++ return isympp[ghdr->sh_info - 1];
++ }
++ return NULL;
++}
+diff --git a/bfd/elf.c b/bfd/elf.c
+index 9dc6b6d..d52fe15 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -2100,6 +2100,7 @@ static const struct bfd_elf_special_section special_sections_g[] =
+ { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.lto_"), -1, SHT_PROGBITS, SHF_EXCLUDE },
+ { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
++ { STRING_COMMA_LEN (".gnu_object_only"), 0, SHT_GNU_OBJECT_ONLY, SHF_EXCLUDE },
+ { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 },
+ { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 },
+ { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 },
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+index 5e5af32..2602c56 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -2425,6 +2425,20 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
+ }
+ else
+ {
++ /* If a plugin symbol is referenced from a non-IR file, mark
++ the symbol as undefined, except for symbol for linker
++ created section. */
++ if (h->root.non_ir_ref
++ && (h->root.type == bfd_link_hash_defined
++ || h->root.type == bfd_link_hash_defweak)
++ && (h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0
++ && h->root.u.def.section->owner != NULL
++ && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0)
++ {
++ h->root.type = bfd_link_hash_undefined;
++ h->root.u.undef.abfd = h->root.u.def.section->owner;
++ }
++
+ /* Unfortunately, NON_ELF is only correct if the symbol
+ was first seen in a non-ELF file. Fortunately, if the symbol
+ was first seen in an ELF file, we're probably OK unless the
+diff --git a/bfd/format.c b/bfd/format.c
+index c4bc944..63ad2e6 100644
+--- a/bfd/format.c
++++ b/bfd/format.c
+@@ -179,6 +179,33 @@ bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve)
+ preserve->marker = NULL;
+ }
+
++/* Set lto_type in ABFD. */
++
++static void
++bfd_set_lto_type (bfd *abfd)
++{
++ if (abfd->format == bfd_object
++ && abfd->lto_type == lto_non_object
++ && (abfd->flags & (DYNAMIC | EXEC_P)) == 0)
++ {
++ asection *sec;
++ enum bfd_lto_object_type type = lto_non_ir_object;
++ for (sec = abfd->sections; sec != NULL; sec = sec->next)
++ {
++ if (strcmp (sec->name, GNU_OBJECT_ONLY_SECTION_NAME) == 0)
++ {
++ type = lto_mixed_object;
++ abfd->object_only_section = sec;
++ break;
++ }
++ else if (type != lto_ir_object
++ && strncmp (sec->name, ".gnu.lto_", 9) == 0)
++ type = lto_ir_object;
++ }
++ abfd->lto_type = type;
++ }
++}
++
+ /*
+ FUNCTION
+ bfd_check_format_matches
+@@ -203,6 +230,9 @@ bfd_boolean
+ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
+ {
+ extern const bfd_target binary_vec;
++#if BFD_SUPPORTS_PLUGINS
++ extern const bfd_target plugin_vec;
++#endif
+ const bfd_target * const *target;
+ const bfd_target **matching_vector = NULL;
+ const bfd_target *save_targ, *right_targ, *ar_right_targ, *match_targ;
+@@ -221,7 +251,10 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
+ }
+
+ if (abfd->format != bfd_unknown)
+- return abfd->format == format;
++ {
++ bfd_set_lto_type (abfd);
++ return abfd->format == format;
++ }
+
+ if (matching != NULL || *bfd_associated_vector != NULL)
+ {
+@@ -285,6 +318,13 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
+ || (*target)->match_priority > best_match)
+ continue;
+
++#if BFD_SUPPORTS_PLUGINS
++ /* Since the plugin target is explicitly specified when a BFD file
++ is opened, don't check it twice. */
++ if (*target == &plugin_vec)
++ continue;
++#endif
++
+ /* If we already tried a match, the bfd is modified and may
+ have sections attached, which will confuse the next
+ _bfd_check_format call. */
+@@ -449,6 +489,8 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
+ if (matching_vector)
+ free (matching_vector);
+
++ bfd_set_lto_type (abfd);
++
+ /* File position has moved, BTW. */
+ return TRUE;
+ }
+diff --git a/bfd/opncls.c b/bfd/opncls.c
+index a2a35f4..5873196 100644
+--- a/bfd/opncls.c
++++ b/bfd/opncls.c
+@@ -1692,3 +1692,69 @@ bfd_fill_in_gnu_debuglink_section (bfd *abfd,
+
+ return TRUE;
+ }
++
++/*
++FUNCTION
++ bfd_extract_object_only_section
++
++SYNOPSIS
++ const char *bfd_extract_object_only_section
++ (bfd *abfd);
++
++DESCRIPTION
++
++ Takes a @var{ABFD} and extract the .gnu_object_only section into
++ a temporary file.
++
++RETURNS
++ The name of the temporary file is returned if all is ok.
++ Otherwise <<NULL>> is returned and bfd_error is set.
++*/
++
++const char *
++bfd_extract_object_only_section (bfd *abfd)
++{
++ asection *sec = abfd->object_only_section;
++ const char *name;
++ FILE *file;
++ bfd_byte *memhunk = NULL;
++ size_t off, size;
++ bfd_error_type err;
++
++ /* Get a temporary object-only file. */
++ name = make_temp_file (".obj-only.o");
++
++ /* Open the object-only file. */
++ file = real_fopen (name, FOPEN_WB);
++ if (!bfd_get_full_section_contents (abfd, sec, &memhunk))
++ {
++ err = bfd_get_error ();
++
++loser:
++ free (memhunk);
++ fclose (file);
++ unlink (name);
++ bfd_set_error (err);
++ return NULL;
++ }
++
++ off = 0;
++ size = sec->size;
++ while (off != size)
++ {
++ size_t written, nwrite = size - off;
++
++ written = fwrite (memhunk + off, 1, nwrite, file);
++ if (written < nwrite && ferror (file))
++ {
++ err = bfd_error_system_call;
++ goto loser;
++ }
++
++ off += written;
++ }
++
++ free (memhunk);
++ fclose (file);
++ return name;
++}
+diff --git a/bfd/plugin.c b/bfd/plugin.c
+index c9d53c8..81ee80f 100644
+--- a/bfd/plugin.c
++++ b/bfd/plugin.c
+@@ -128,6 +128,139 @@ register_claim_file (ld_plugin_claim_file_handler handler)
+ return LDPS_OK;
+ }
+
++static asection bfd_plugin_fake_text_section
++ = BFD_FAKE_SECTION (bfd_plugin_fake_text_section, 0, 0, ".text", 0);
++static asection bfd_plugin_fake_common_section
++ = BFD_FAKE_SECTION (bfd_plugin_fake_common_section, SEC_IS_COMMON, 0,
++ NULL, 0);
++
++/* Get symbols from object only section. */
++
++static void
++bfd_plugin_get_symbols_in_object_only (bfd *abfd)
++{
++ struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
++ const char *object_only_file;
++ bfd *nbfd;
++ long storage;
++ long object_only_nsyms, added_nsyms, i;
++ asymbol **object_only_syms, **added_syms;
++
++ plugin_data->object_only_syms = NULL;
++ plugin_data->object_only_nsyms = 0;
++
++ if (abfd->sections == NULL && abfd->my_archive == NULL)
++ {
++ nbfd = bfd_openr (abfd->filename, NULL);
++ if (nbfd == NULL || !bfd_check_format (nbfd, bfd_object))
++ {
++ (*_bfd_error_handler)
++ (_("%s: failed to open to extract object only section: %s"),
++ abfd->filename, bfd_errmsg (bfd_get_error ()));
++ bfd_close (nbfd);
++ return;
++ }
++ }
++ else
++ {
++ if (!bfd_check_format (abfd, bfd_object))
++ {
++ (*_bfd_error_handler)
++ (_("%B: invalid file to extract object only section: %s"),
++ abfd, bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++ nbfd = abfd;
++ }
++
++ if (nbfd->lto_type == lto_mixed_object
++ && (nbfd->flags & HAS_SYMS) != 0)
++ {
++ object_only_file = bfd_extract_object_only_section (nbfd);
++ if (object_only_file == NULL)
++ (*_bfd_error_handler)
++ (_("%B: failed to extract object only section: %s"),
++ abfd, bfd_errmsg (bfd_get_error ()));
++ }
++ else
++ object_only_file = NULL;
++
++ /* Close the new bfd we just opened. */
++ if (nbfd != abfd)
++ bfd_close (nbfd);
++
++ /* Return if there is no object only section or there is no
++ symbol in object only section. */
++ if (!object_only_file)
++ return;
++
++ /* Open the file containing object only section. */
++ nbfd = bfd_openr (object_only_file, NULL);
++ if (!bfd_check_format (nbfd, bfd_object))
++ {
++ (*_bfd_error_handler)
++ (_("%B: failed to open object only section: %s"),
++ abfd, bfd_errmsg (bfd_get_error ()));
++ goto quit;
++ }
++
++ storage = bfd_get_symtab_upper_bound (nbfd);
++ if (storage <= 0)
++ {
++ if (storage < 0)
++ (*_bfd_error_handler)
++ (_("%B: failed to get symbol table in object only section: %s"),
++ abfd, bfd_errmsg (bfd_get_error ()));
++
++ goto quit;
++ }
++
++ object_only_syms = (asymbol **) bfd_malloc (storage);
++ object_only_nsyms = bfd_canonicalize_symtab (nbfd, object_only_syms);
++
++ /* FIXME: We waste some spaces if not all symbols are copied. */
++ added_syms = (asymbol **) bfd_alloc (abfd, storage);
++ added_nsyms = 0;
++
++ /* Copy only global symbols from object only section. */
++ for (i = 0; i < object_only_nsyms; i++)
++ {
++ asection *sec = object_only_syms[i]->section;
++ flagword flags = object_only_syms[i]->flags;
++ asymbol *s;
++
++ if (bfd_is_com_section (sec))
++ sec = &bfd_plugin_fake_common_section;
++ else if (bfd_is_und_section (sec))
++ ;
++ else if ((flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0)
++ sec = &bfd_plugin_fake_text_section;
++ else
++ continue;
++
++ s = bfd_alloc (abfd, sizeof (asymbol));
++ BFD_ASSERT (s);
++ added_syms[added_nsyms++] = s;
++
++ s->section = sec;
++ s->the_bfd = abfd;
++ s->name = xstrdup (object_only_syms[i]->name);
++ s->value = 0;
++ s->flags = flags;
++ s->udata.p = NULL;
++ }
++
++ plugin_data->object_only_syms = added_syms;
++ plugin_data->object_only_nsyms = added_nsyms;
++
++ free (object_only_syms);
++
++quit:
++ /* Close and remove the object only section file. */
++ bfd_close (nbfd);
++ unlink (object_only_file);
++}
++
+ static enum ld_plugin_status
+ add_symbols (void * handle,
+ int nsyms,
+@@ -140,10 +273,13 @@ add_symbols (void * handle,
+ plugin_data->nsyms = nsyms;
+ plugin_data->syms = syms;
+
+- if (nsyms != 0)
++ abfd->tdata.plugin_data = plugin_data;
++
++ bfd_plugin_get_symbols_in_object_only (abfd);
++
++ if ((nsyms + plugin_data->object_only_nsyms) != 0)
+ abfd->flags |= HAS_SYMS;
+
+- abfd->tdata.plugin_data = plugin_data;
+ return LDPS_OK;
+ }
+
+@@ -387,7 +523,8 @@ static long
+ bfd_plugin_get_symtab_upper_bound (bfd *abfd)
+ {
+ struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
+- long nsyms = plugin_data->nsyms;
++ /* Add symbols from object only section. */
++ long nsyms = plugin_data->nsyms + plugin_data->object_only_nsyms;
+
+ BFD_ASSERT (nsyms >= 0);
+
+@@ -421,12 +558,7 @@ bfd_plugin_canonicalize_symtab (bfd *abfd,
+ struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
+ long nsyms = plugin_data->nsyms;
+ const struct ld_plugin_symbol *syms = plugin_data->syms;
+- static asection fake_section;
+- static asection fake_common_section;
+- int i;
+-
+- fake_section.name = ".text";
+- fake_common_section.flags = SEC_IS_COMMON;
++ int i, j;
+
+ for (i = 0; i < nsyms; i++)
+ {
+@@ -439,10 +571,11 @@ bfd_plugin_canonicalize_symtab (bfd *abfd,
+ s->name = syms[i].name;
+ s->value = 0;
+ s->flags = convert_flags (&syms[i]);
++ s->udata.p = NULL;
+ switch (syms[i].def)
+ {
+ case LDPK_COMMON:
+- s->section = &fake_common_section;
++ s->section = &bfd_plugin_fake_common_section;
+ break;
+ case LDPK_UNDEF:
+ case LDPK_WEAKUNDEF:
+@@ -450,15 +583,18 @@ bfd_plugin_canonicalize_symtab (bfd *abfd,
+ break;
+ case LDPK_DEF:
+ case LDPK_WEAKDEF:
+- s->section = &fake_section;
++ s->section = &bfd_plugin_fake_text_section;
+ break;
+ default:
+ BFD_ASSERT (0);
+ }
+-
+- s->udata.p = (void *) &syms[i];
+ }
+
++ /* Copy symbols from object only section. */
++ nsyms += plugin_data->object_only_nsyms;
++ for (j = 0; j < plugin_data->object_only_nsyms; j++, i++)
++ alocation[i] = plugin_data->object_only_syms[j];
++
+ return nsyms;
+ }
+
+diff --git a/bfd/plugin.h b/bfd/plugin.h
+index 4f1d18b..0ec54bf 100644
+--- a/bfd/plugin.h
++++ b/bfd/plugin.h
+@@ -30,6 +30,8 @@ typedef struct plugin_data_struct
+ {
+ int nsyms;
+ const struct ld_plugin_symbol *syms;
++ int object_only_nsyms;
++ asymbol **object_only_syms;
+ }
+ plugin_data_struct;
+
+diff --git a/bfd/section.c b/bfd/section.c
+index b27539a..b3e0c3d 100644
+--- a/bfd/section.c
++++ b/bfd/section.c
+@@ -576,6 +576,9 @@ CODE_FRAGMENT
+ .#define BFD_COM_SECTION_NAME "*COM*"
+ .#define BFD_IND_SECTION_NAME "*IND*"
+ .
++.{* GNU object-only section name. *}
++.#define GNU_OBJECT_ONLY_SECTION_NAME ".gnu_object_only"
++.
+ .{* Pointer to the common section. *}
+ .#define bfd_com_section_ptr (&_bfd_std_section[0])
+ .{* Pointer to the undefined section. *}
+diff --git a/binutils/objcopy.c b/binutils/objcopy.c
+index 46fd8bc..81d3be9 100644
+--- a/binutils/objcopy.c
++++ b/binutils/objcopy.c
+@@ -1009,30 +1009,6 @@ is_specified_symbol (const char *name, htab_t htab)
+ return htab_find (htab, name) != NULL;
+ }
+
+-/* Return a pointer to the symbol used as a signature for GROUP. */
+-
+-static asymbol *
+-group_signature (asection *group)
+-{
+- bfd *abfd = group->owner;
+- Elf_Internal_Shdr *ghdr;
+-
+- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+- return NULL;
+-
+- ghdr = &elf_section_data (group)->this_hdr;
+- if (ghdr->sh_link < elf_numsections (abfd))
+- {
+- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+- Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
+-
+- if (symhdr->sh_type == SHT_SYMTAB
+- && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
+- return isympp[ghdr->sh_info - 1];
+- }
+- return NULL;
+-}
+-
+ /* Return TRUE if the section is a DWO section. */
+
+ static bfd_boolean
+@@ -1114,7 +1090,7 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ /* PR binutils/3181
+ If we are going to strip the group signature symbol, then
+ strip the group section too. */
+- gsym = group_signature (sec);
++ gsym = bfd_group_signature (sec, isympp);
+ if (gsym != NULL)
+ gname = gsym->name;
+ else
+@@ -2810,7 +2786,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+
+ if ((isection->flags & SEC_GROUP) != 0)
+ {
+- asymbol *gsym = group_signature (isection);
++ asymbol *gsym = bfd_group_signature (isection, isympp);
+
+ if (gsym != NULL)
+ {
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index 7463c55..e68ae19 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -3531,6 +3531,7 @@ get_section_type_name (unsigned int sh_type)
+ case 0x7ffffffd: return "AUXILIARY";
+ case 0x7fffffff: return "FILTER";
+ case SHT_GNU_LIBLIST: return "GNU_LIBLIST";
++ case SHT_GNU_OBJECT_ONLY: return "GNU_OBJECT_ONLY";
+
+ default:
+ if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC))
+diff --git a/gas/testsuite/gas/elf/section9.d b/gas/testsuite/gas/elf/section9.d
+index 1acf63e..bb66fa5 100644
+--- a/gas/testsuite/gas/elf/section9.d
++++ b/gas/testsuite/gas/elf/section9.d
+@@ -4,4 +4,5 @@
+ #...
+ [ ]*\[.*\][ ]+\.gnu\.lto_main[ ]+PROGBITS.*[ ]+E[ ]+.*
+ [ ]*\[.*\][ ]+\.gnu\.lto_\.pureconst[ ]+PROGBITS.*[ ]+E[ ]+.*
++[ ]*\[.*\][ ]+\.gnu_object_only[ ]+GNU_OBJECT_ONLY.*[ ]+E[ ]+.*
+ #pass
+diff --git a/gas/testsuite/gas/elf/section9.s b/gas/testsuite/gas/elf/section9.s
+index 6b8b107..abcdea1 100644
+--- a/gas/testsuite/gas/elf/section9.s
++++ b/gas/testsuite/gas/elf/section9.s
+@@ -2,3 +2,5 @@
+ .byte 0,0,0,0
+ .section .gnu.lto_.pureconst,"",%progbits
+ .byte 0,0,0,0
++ .section .gnu_object_only
++ .byte 0,0,0,0
+diff --git a/include/bfdlink.h b/include/bfdlink.h
+index 125683d..45a6a13 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -389,6 +389,12 @@ struct bfd_link_info
+ /* TRUE if ok to have multiple definition. */
+ unsigned int allow_multiple_definition: 1;
+
++ /* TRUE if .gnu_object_only section should be created. */
++ unsigned int emit_gnu_object_only: 1;
++
++ /* TRUE if .gnu_object_only section is being created. */
++ unsigned int emitting_gnu_object_only: 1;
++
+ /* TRUE if ok to have version with no definition. */
+ unsigned int allow_undefined_version: 1;
+
+diff --git a/include/elf/common.h b/include/elf/common.h
+index e8ae3ac..ed9d4d8 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -472,6 +472,7 @@
+ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes */
+ #define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table */
+ #define SHT_GNU_LIBLIST 0x6ffffff7 /* List of prelink dependencies */
++#define SHT_GNU_OBJECT_ONLY 0x6ffffff8 /* Object only */
+
+ /* The next three section types are defined by Solaris, and are named
+ SHT_SUNW*. We use them in GNU code, so we also define SHT_GNU*
+diff --git a/ld/emultempl/aarch64elf.em b/ld/emultempl/aarch64elf.em
+index 6134855..8b754a9 100644
+--- a/ld/emultempl/aarch64elf.em
++++ b/ld/emultempl/aarch64elf.em
+@@ -262,7 +262,7 @@ gld${EMULATION_NAME}_after_allocation (void)
+ }
+
+ static void
+-gld${EMULATION_NAME}_finish (void)
++aarch64_finish (void)
+ {
+ if (! link_info.relocatable)
+ {
+@@ -274,7 +274,7 @@ gld${EMULATION_NAME}_finish (void)
+ }
+ }
+
+- finish_default ();
++ gld${EMULATION_NAME}_finish ();
+ }
+
+ /* This is a convenient point to tell BFD about target specific flags.
+@@ -411,4 +411,4 @@ LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=aarch64_elf_create_output_section_statem
+ LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse
+
+ # Call the extra arm-elf function
+-LDEMUL_FINISH=gld${EMULATION_NAME}_finish
++LDEMUL_FINISH=aarch64_finish
+diff --git a/ld/emultempl/alphaelf.em b/ld/emultempl/alphaelf.em
+index a36fc7d..2d4a9f6 100644
+--- a/ld/emultempl/alphaelf.em
++++ b/ld/emultempl/alphaelf.em
+@@ -100,7 +100,7 @@ alpha_finish (void)
+ if (limit_32bit)
+ elf_elfheader (link_info.output_bfd)->e_flags |= EF_ALPHA_32BIT;
+
+- finish_default ();
++ gld${EMULATION_NAME}_finish ();
+ }
+ EOF
+
+diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
+index 34028ee..04f238b 100644
+--- a/ld/emultempl/armelf.em
++++ b/ld/emultempl/armelf.em
+@@ -363,7 +363,7 @@ gld${EMULATION_NAME}_after_allocation (void)
+ }
+
+ static void
+-gld${EMULATION_NAME}_finish (void)
++arm_finish (void)
+ {
+ struct bfd_link_hash_entry * h;
+
+@@ -386,7 +386,7 @@ gld${EMULATION_NAME}_finish (void)
+ }
+ }
+
+- finish_default ();
++ gld${EMULATION_NAME}_finish ();
+
+ if (thumb_entry_symbol)
+ {
+@@ -695,4 +695,4 @@ LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=arm_elf_create_output_section_statements
+ LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse
+
+ # Call the extra arm-elf function
+-LDEMUL_FINISH=gld${EMULATION_NAME}_finish
++LDEMUL_FINISH=arm_finish
+diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
+index 39b4ccd..3c44819 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -65,6 +65,7 @@ static void gld${EMULATION_NAME}_before_allocation (void);
+ static void gld${EMULATION_NAME}_after_allocation (void);
+ static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan
+ (asection *, const char *, int);
++static void gld${EMULATION_NAME}_finish (void);
+ EOF
+
+ if [ "x${USE_LIBPATH}" = xyes ] ; then
+@@ -1729,6 +1730,8 @@ output_rel_find (asection *sec, int isdyn)
+ return last;
+ }
+
++static int orphan_init_done = 0;
++
+ /* Place an orphan section. We use this to put random SHF_ALLOC
+ sections in the right segment. */
+
+@@ -1737,7 +1740,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+ const char *secname,
+ int constraint)
+ {
+- static struct orphan_save hold[] =
++ static struct orphan_save orig_hold[] =
+ {
+ { ".text",
+ SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
+@@ -1767,6 +1770,7 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+ SEC_HAS_CONTENTS,
+ 0, 0, 0, 0 },
+ };
++ static struct orphan_save hold[ARRAY_SIZE (orig_hold)];
+ enum orphan_save_index
+ {
+ orphan_text = 0,
+@@ -1779,7 +1783,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+ orphan_sdata,
+ orphan_nonalloc
+ };
+- static int orphan_init_done = 0;
+ struct orphan_save *place;
+ lang_output_section_statement_type *after;
+ lang_output_section_statement_type *os;
+@@ -1856,15 +1859,22 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+
+ if (!orphan_init_done)
+ {
+- struct orphan_save *ho;
++ struct orphan_save *ho, *horig;
+
+ for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho)
++ for (ho = hold, horig = orig_hold;
++ ho < hold + ARRAY_SIZE (hold);
++ ++ho, ++horig)
++ {
++ *ho = *horig;
++ if (ho->name != NULL)
+ if (ho->name != NULL)
+ {
+ ho->os = lang_output_section_find (ho->name);
+ if (ho->os != NULL && ho->os->flags == 0)
+ ho->os->flags = ho->flags;
+ }
++ }
+ orphan_init_done = 1;
+ }
+
+@@ -1936,6 +1946,27 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+ EOF
+ fi
+
++fragment <<EOF
++
++/* Final emulation specific call. */
++
++static void
++gld${EMULATION_NAME}_finish (void)
++{
++EOF
++if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then
++fragment <<EOF
++ /* Support the object-only output. */
++ if (link_info.emit_gnu_object_only)
++ orphan_init_done = 0;
++
++EOF
++fi
++fragment <<EOF
++ finish_default ();
++}
++EOF
++
+ if test x"$LDEMUL_AFTER_ALLOCATION" != xgld"$EMULATION_NAME"_after_allocation; then
+ fragment <<EOF
+
+@@ -2486,7 +2517,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
+ ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
+ "${EMULATION_NAME}",
+ "${OUTPUT_FORMAT}",
+- ${LDEMUL_FINISH-finish_default},
++ ${LDEMUL_FINISH-gld${EMULATION_NAME}_finish},
+ ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
+ ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-gld${EMULATION_NAME}_open_dynamic_archive},
+ ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
+diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em
+index d45fdac..0e93c79 100644
+--- a/ld/emultempl/ppc64elf.em
++++ b/ld/emultempl/ppc64elf.em
+@@ -515,7 +515,7 @@ gld${EMULATION_NAME}_after_allocation (void)
+ /* Final emulation specific call. */
+
+ static void
+-gld${EMULATION_NAME}_finish (void)
++ppc_finish (void)
+ {
+ char *msg = NULL;
+ char *line, *endline;
+@@ -546,7 +546,7 @@ gld${EMULATION_NAME}_finish (void)
+ free (msg);
+
+ ppc64_elf_restore_symbols (&link_info);
+- finish_default ();
++ gld${EMULATION_NAME}_finish ();
+ }
+
+
+@@ -868,6 +868,6 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
+ #
+ LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation
+ LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
+-LDEMUL_FINISH=gld${EMULATION_NAME}_finish
++LDEMUL_FINISH=ppc_finish
+ LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=ppc_create_output_section_statements
+ LDEMUL_NEW_VERS_PATTERN=gld${EMULATION_NAME}_new_vers_pattern
+diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em
+index 1b4d72f..8c8090c 100644
+--- a/ld/emultempl/spuelf.em
++++ b/ld/emultempl/spuelf.em
+@@ -416,7 +416,7 @@ spu_elf_relink (void)
+ /* Final emulation specific call. */
+
+ static void
+-gld${EMULATION_NAME}_finish (void)
++spu_finish (void)
+ {
+ if (is_spu_target ())
+ {
+@@ -432,7 +432,7 @@ gld${EMULATION_NAME}_finish (void)
+ einfo ("%P: --auto-overlay ignored with zero local store range\n");
+ }
+
+- finish_default ();
++ gld${EMULATION_NAME}_finish ();
+ }
+
+ static char *
+@@ -832,5 +832,5 @@ PARSE_AND_LIST_ARGS_CASES='
+
+ LDEMUL_AFTER_OPEN=spu_after_open
+ LDEMUL_BEFORE_ALLOCATION=spu_before_allocation
+-LDEMUL_FINISH=gld${EMULATION_NAME}_finish
++LDEMUL_FINISH=spu_finish
+ LDEMUL_CHOOSE_TARGET=gld${EMULATION_NAME}_choose_target
+diff --git a/ld/ldfile.c b/ld/ldfile.c
+index 782ed7f..ead7345 100644
+--- a/ld/ldfile.c
++++ b/ld/ldfile.c
+@@ -317,7 +317,9 @@ success:
+ plugin_maybe_claim (&file, entry);
+ }
+ }
++ else
+ #endif /* ENABLE_PLUGINS */
++ cmdline_check_object_only_section (entry->the_bfd, FALSE);
+
+ /* It opened OK, the format checked out, and the plugins have had
+ their chance to claim it, so this is success. */
+diff --git a/ld/ldlang.c b/ld/ldlang.c
+index 899f710..342a547 100644
+--- a/ld/ldlang.c
++++ b/ld/ldlang.c
+@@ -36,6 +36,7 @@
+ #include "ldctor.h"
+ #include "ldfile.h"
+ #include "ldemul.h"
++#include "ldwrite.h"
+ #include "fnmatch.h"
+ #include "demangle.h"
+ #include "hashtab.h"
+@@ -45,6 +46,9 @@
+ #include "plugin.h"
+ #endif /* ENABLE_PLUGINS */
+
++/* FIXME: Put it here to avoid NAME conflict from ldgram.h. */
++#include "elf-bfd.h"
++
+ #ifndef offsetof
+ #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
+ #endif
+@@ -69,6 +73,9 @@ static lang_statement_list_type *stat_save[10];
+ static lang_statement_list_type **stat_save_ptr = &stat_save[0];
+ static struct unique_sections *unique_section_list;
+ static struct asneeded_minfo *asneeded_list_head;
++static cmdline_list_type cmdline_object_only_file_list;
++static cmdline_list_type cmdline_object_only_archive_list;
++static cmdline_list_type cmdline_temp_object_only_list;
+
+ /* Forward declarations. */
+ static void exp_init_os (etree_type *);
+@@ -88,6 +95,10 @@ static void lang_record_phdrs (void);
+ static void lang_do_version_exports_section (void);
+ static void lang_finalize_version_expr_head
+ (struct bfd_elf_version_expr_head *);
++static void cmdline_lists_init (void);
++static void cmdline_get_object_only_input_files (void);
++static void print_cmdline_list (cmdline_union_type *);
++static bfd_boolean cmdline_on_object_only_archive_list_p (bfd *);
+
+ /* Exported variables. */
+ const char *output_target;
+@@ -1201,14 +1212,17 @@ output_section_statement_table_free (void)
+ /* Build enough state so that the parser can build its tree. */
+
+ void
+-lang_init (void)
++lang_init (bfd_boolean object_only)
+ {
+- obstack_begin (&stat_obstack, 1000);
++ if (!object_only)
++ obstack_begin (&stat_obstack, 1000);
+
+ stat_ptr = &statement_list;
+
+ output_section_statement_table_init ();
+
++ cmdline_lists_init ();
++
+ lang_list_init (stat_ptr);
+
+ lang_list_init (&input_file_chain);
+@@ -1223,10 +1237,11 @@ lang_init (void)
+
+ /* The value "13" is ad-hoc, somewhat related to the expected number of
+ assignments in a linker script. */
+- if (!bfd_hash_table_init_n (&lang_definedness_table,
+- lang_definedness_newfunc,
+- sizeof (struct lang_definedness_hash_entry),
+- 13))
++ if (!object_only
++ && !bfd_hash_table_init_n (&lang_definedness_table,
++ lang_definedness_newfunc,
++ sizeof (struct lang_definedness_hash_entry),
++ 13))
+ einfo (_("%P%F: can not create hash table: %E\n"));
+
+ asneeded_list_head = NULL;
+@@ -1234,9 +1249,10 @@ lang_init (void)
+ }
+
+ void
+-lang_finish (void)
++lang_finish (bfd_boolean object_only)
+ {
+- bfd_hash_table_free (&lang_definedness_table);
++ if (!object_only)
++ bfd_hash_table_free (&lang_definedness_table);
+ output_section_statement_table_free ();
+ }
+
+@@ -2820,6 +2836,12 @@ load_symbols (lang_input_statement_type *entry,
+ loaded = FALSE;
+ }
+
++ if (link_info.emitting_gnu_object_only)
++ {
++ if (!cmdline_on_object_only_archive_list_p (member))
++ continue;
++ }
++
+ subsbfd = member;
+ if (!(*link_info.callbacks
+ ->add_archive_element) (&link_info, member,
+@@ -6721,7 +6743,38 @@ lang_process (void)
+ open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+ }
+ }
++ else
+ #endif /* ENABLE_PLUGINS */
++ if (link_info.relocatable)
++ {
++ /* Check if .gnu_object_only section should be created. */
++ bfd *p;
++ int object_type;
++
++ object_type = 0;
++ for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link.next)
++ {
++ object_type |= 1 << p->lto_type;
++ if ((object_type & (1 << lto_mixed_object)) != 0
++ || ((object_type
++ & (1 << lto_non_ir_object
++ | 1 << lto_ir_object))
++ == (1 << lto_non_ir_object | 1 << lto_ir_object)))
++ {
++ link_info.emit_gnu_object_only = TRUE;
++ break;
++ }
++ }
++
++ if (verbose
++ && (cmdline_object_only_file_list.head
++ || cmdline_object_only_archive_list.head))
++ {
++ info_msg (_("Object-only input files:\n "));
++ print_cmdline_list (cmdline_object_only_file_list.head);
++ print_cmdline_list (cmdline_object_only_archive_list.head);
++ }
++ }
+
+ link_info.gc_sym_list = &entry_symbol;
+ if (entry_symbol.name == NULL)
+@@ -8123,3 +8176,963 @@ lang_ld_feature (char *str)
+ p = q;
+ }
+ }
++
++static void
++cmdline_lists_init (void)
++{
++ cmdline_object_only_file_list.tail
++ = &cmdline_object_only_file_list.head;
++ cmdline_object_only_archive_list.tail
++ = &cmdline_object_only_archive_list.head;
++ cmdline_temp_object_only_list.tail
++ = &cmdline_temp_object_only_list.head;
++}
++
++/* Allocate an item with TYPE and DATA. */
++
++static cmdline_union_type *
++cmdline_list_new (cmdline_enum_type type, void *data)
++{
++ cmdline_union_type *new_opt;
++
++ new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
++ new_opt->header.type = type;
++ switch (type)
++ {
++ default:
++ break;
++ case cmdline_is_file_enum:
++ new_opt->file.filename = (const char *) data;
++ break;
++ case cmdline_is_bfd_enum:
++ new_opt->abfd.abfd = (bfd *) data;
++ break;
++ }
++ return new_opt;
++}
++
++/* Append an item with TYPE and DATA to LIST. */
++
++static void
++cmdline_list_append (cmdline_list_type *list, cmdline_enum_type type,
++ void *data)
++{
++ cmdline_union_type *new_opt = cmdline_list_new (type, data);
++ new_opt->header.next = NULL;
++ *list->tail = new_opt;
++ list->tail = &new_opt->header.next;
++}
++
++static void
++print_cmdline_list (cmdline_union_type *c)
++{
++ for (; c != NULL; c = c->header.next)
++ switch (c->header.type)
++ {
++ default:
++ abort ();
++ case cmdline_is_file_enum:
++ info_msg (" %s", c->file.filename);
++ break;
++ case cmdline_is_bfd_enum:
++ info_msg (" [%B]", c->abfd.abfd);
++ break;
++ }
++
++ info_msg ("\n");
++}
++
++/* Return TRUE if ABFD is on cmdline_object_only_archive_list. */
++
++static bfd_boolean
++cmdline_on_object_only_archive_list_p (bfd *abfd)
++{
++ cmdline_union_type *c, *next;
++ bfd *archive, *obfd, *oarchive;
++ ufile_ptr origin = abfd->origin;
++
++ archive = bfd_my_archive (abfd);
++ for (c = cmdline_object_only_archive_list.head; c != NULL; c = next)
++ {
++ if (c->header.type != cmdline_is_bfd_enum)
++ abort ();
++
++ next = c->header.next;
++ obfd = c->abfd.abfd;
++ oarchive = bfd_my_archive (obfd);
++
++ /* The list is grouped by archive file name and sorted by member
++ origin. */
++ if (strcmp (archive->filename, oarchive->filename) != 0)
++ continue;
++
++ if (origin == obfd->origin)
++ return TRUE;
++ else if (origin < obfd->origin)
++ return FALSE;
++ }
++
++ return FALSE;
++}
++
++/* Append an item with TYPE and DATA to cmdline_object_only_file_list
++ or cmdline_object_only_archive_list if needed. */
++
++static void
++cmdline_object_only_list_append (cmdline_enum_type type, void *data)
++{
++ cmdline_union_type *c;
++ cmdline_union_type *new_opt, *next, **prev;
++ bfd *abfd, *archive;
++ bfd *obfd, *oarchive;
++ bfd *nbfd, *narchive;
++ ufile_ptr origin, norigin;
++
++ /* Put it on cmdline_object_only_file_list if it isn't an archive
++ member. */
++ switch (type)
++ {
++ default:
++ abort ();
++ case cmdline_is_bfd_enum:
++ abfd = (bfd *) data;
++ archive = bfd_my_archive (abfd);
++ if (archive)
++ break;
++ case cmdline_is_file_enum:
++ cmdline_list_append (&cmdline_object_only_file_list, type, data);
++ return;
++ }
++
++ /* Put archive member on cmdline_object_only_archive_list and sort
++ the list by archive name and archive member origin. */
++ new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
++ new_opt->header.type = cmdline_is_bfd_enum;
++ new_opt->header.next = NULL;
++ new_opt->abfd.abfd = (bfd *) data;
++
++ c = cmdline_object_only_archive_list.head;
++ if (c == NULL)
++ {
++ cmdline_object_only_archive_list.head = new_opt;
++ cmdline_object_only_archive_list.tail = &new_opt->header.next;
++ return;
++ }
++
++ prev = NULL;
++ origin = abfd->origin;
++ for (; c != NULL; c = next)
++ {
++ if (c->header.type != cmdline_is_bfd_enum)
++ abort ();
++
++ next = c->header.next;
++
++ obfd = c->abfd.abfd;
++ oarchive = bfd_my_archive (obfd);
++
++ if (strcmp (archive->filename, oarchive->filename) == 0)
++ {
++ bfd_boolean after;
++
++ if (origin < obfd->origin)
++ {
++ /* Insert it before the current. */
++ new_opt->header.next = c;
++ if (prev)
++ *prev = new_opt;
++ else
++ cmdline_object_only_archive_list.head = new_opt;
++ return;
++ }
++
++ after = TRUE;
++
++ /* Check origin. */
++ while (next)
++ {
++ if (next->header.type != cmdline_is_bfd_enum)
++ abort ();
++
++ nbfd = next->abfd.abfd;
++ norigin = nbfd->origin;
++ if (origin > norigin)
++ {
++ /* Insert it after NEXT. */
++ break;
++ }
++
++ narchive = bfd_my_archive (nbfd);
++ if (strcmp (archive->filename, narchive->filename) != 0)
++ {
++ /* Insert it befor NEXT. */
++ after = FALSE;
++ break;
++ }
++
++ c = next;
++ next = next->header.next;
++ }
++
++ if (after && next)
++ {
++ c = next;
++ next = next->header.next;
++ }
++
++ if (*cmdline_object_only_archive_list.tail == c->header.next)
++ cmdline_object_only_archive_list.tail
++ = &new_opt->header.next;
++
++ prev = &c->header.next;
++ new_opt->header.next = next;
++ *prev = new_opt;
++ return;
++ }
++
++ prev = &c->header.next;
++ }
++
++ *cmdline_object_only_archive_list.tail = new_opt;
++ cmdline_object_only_archive_list.tail = &new_opt->header.next;
++}
++
++/* Get object-only input files. */
++
++static void
++cmdline_get_object_only_input_files (void)
++{
++ cmdline_union_type *c, *next;
++ bfd *abfd, *archive;
++ bfd *nbfd, *narchive;
++
++ /* Add files first. */
++ for (c = cmdline_object_only_file_list.head;
++ c != NULL; c = c->header.next)
++ switch (c->header.type)
++ {
++ default:
++ abort ();
++ case cmdline_is_file_enum:
++ lang_add_input_file (c->file.filename,
++ lang_input_file_is_file_enum, NULL);
++ break;
++ case cmdline_is_bfd_enum:
++ abfd = c->abfd.abfd;
++ if (bfd_my_archive (abfd))
++ abort ();
++ lang_add_input_file (abfd->filename,
++ lang_input_file_is_file_enum, NULL);
++ break;
++ }
++
++ /* Add archive members next. */
++ for (c = cmdline_object_only_archive_list.head; c != NULL; c = next)
++ {
++ if (c->header.type != cmdline_is_bfd_enum)
++ abort ();
++
++ next = c->header.next;
++
++ abfd = c->abfd.abfd;
++ archive = bfd_my_archive (abfd);
++
++ /* Add the first archive of the archive member group. */
++ lang_add_input_file (archive->filename,
++ lang_input_file_is_file_enum, NULL);
++
++ /* Skip the rest members in the archive member group. */
++ do
++ {
++ if (!next)
++ break;
++
++ if (next->header.type != cmdline_is_bfd_enum)
++ abort ();
++
++ next = next->header.next;
++ if (!next)
++ break;
++ nbfd = next->abfd.abfd;
++ narchive = bfd_my_archive (nbfd);
++ }
++ while (strcmp (archive->filename, narchive->filename) == 0);
++ }
++}
++
++struct cmdline_arg
++{
++ bfd *obfd;
++ asymbol **isympp;
++ int status;
++};
++
++/* Create a section in OBFD with the same
++ name and attributes as ISECTION in IBFD. */
++
++static void
++setup_section (bfd *ibfd, sec_ptr isection, void *p)
++{
++ struct cmdline_arg *arg = (struct cmdline_arg *) p;
++ bfd *obfd = arg->obfd;
++ asymbol **isympp = arg->isympp;
++ const char *name = isection->name;
++ sec_ptr osection;
++ const char *err;
++
++ /* Skip the object-only section. */
++ if (ibfd->object_only_section == isection)
++ return;
++
++ /* If we have already failed earlier on, do not keep on generating
++ complaints now. */
++ if (arg->status)
++ return;
++
++ osection = bfd_make_section_anyway_with_flags (obfd, name,
++ isection->flags);
++
++ if (osection == NULL)
++ {
++ err = _("failed to create output section");
++ goto loser;
++ }
++
++ osection->size = isection->size;
++ osection->vma = isection->vma;
++ osection->lma = isection->lma;
++ osection->alignment_power = isection->alignment_power;
++
++ /* Copy merge entity size. */
++ osection->entsize = isection->entsize;
++
++ /* This used to be mangle_section; we do here to avoid using
++ bfd_get_section_by_name since some formats allow multiple
++ sections with the same name. */
++ isection->output_section = osection;
++ isection->output_offset = 0;
++
++ if ((isection->flags & SEC_GROUP) != 0)
++ {
++ asymbol *gsym = bfd_group_signature (isection, isympp);
++
++ if (gsym != NULL)
++ {
++ gsym->flags |= BSF_KEEP;
++ if (ibfd->xvec->flavour == bfd_target_elf_flavour)
++ elf_group_id (isection) = gsym;
++ }
++ }
++
++ /* Allow the BFD backend to copy any private data it understands
++ from the input section to the output section. */
++ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
++ {
++ err = _("failed to copy private data");
++ goto loser;
++ }
++
++ /* All went well. */
++ return;
++
++loser:
++ arg->status = 1;
++ einfo (_("%P%F: setup_section: %s: %s\n"), err, name);
++}
++
++/* Copy the data of input section ISECTION of IBFD
++ to an output section with the same name in OBFD.
++ If stripping then don't copy any relocation info. */
++
++static void
++copy_section (bfd *ibfd, sec_ptr isection, void *p)
++{
++ struct cmdline_arg *arg = (struct cmdline_arg *) p;
++ bfd *obfd = arg->obfd;
++ asymbol **isympp = arg->isympp;
++ arelent **relpp;
++ long relcount;
++ sec_ptr osection;
++ bfd_size_type size;
++ long relsize;
++ flagword flags;
++ const char *err;
++
++ /* Skip the object-only section. */
++ if (ibfd->object_only_section == isection)
++ return;
++
++ /* If we have already failed earlier on, do not keep on generating
++ complaints now. */
++ if (arg->status)
++ return;
++
++ flags = bfd_get_section_flags (ibfd, isection);
++ if ((flags & SEC_GROUP) != 0)
++ return;
++
++ osection = isection->output_section;
++ size = bfd_get_section_size (isection);
++
++ if (size == 0 || osection == 0)
++ return;
++
++ relsize = bfd_get_reloc_upper_bound (ibfd, isection);
++
++ if (relsize < 0)
++ {
++ /* Do not complain if the target does not support relocations. */
++ if (relsize == -1
++ && bfd_get_error () == bfd_error_invalid_operation)
++ relsize = 0;
++ else
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++ }
++
++ if (relsize == 0)
++ bfd_set_reloc (obfd, osection, NULL, 0);
++ else
++ {
++ relpp = (arelent **) xmalloc (relsize);
++ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
++ if (relcount < 0)
++ {
++ err = _("relocation count is negative");
++ goto loser;
++ }
++
++ bfd_set_reloc (obfd, osection,
++ relcount == 0 ? NULL : relpp, relcount);
++ if (relcount == 0)
++ free (relpp);
++ }
++
++ if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS)
++ {
++ bfd_byte *memhunk = NULL;
++
++ if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++ free (memhunk);
++ }
++
++ /* All went well. */
++ return;
++
++loser:
++ einfo (_("%P%F: copy_section: %s: %s\n"), err, isection->name);
++}
++/* Open the temporary bfd created in the same directory as PATH. */
++
++static bfd *
++cmdline_fopen_temp (const char *path, const char *target,
++ const char *mode)
++{
++#define template "ldXXXXXX"
++ const char *slash = strrchr (path, '/');
++ char *tmpname;
++ size_t len;
++ int fd;
++
++#ifdef HAVE_DOS_BASED_FILE_SYSTEM
++ {
++ /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
++ char *bslash = strrchr (path, '\\');
++
++ if (slash == NULL || (bslash != NULL && bslash > slash))
++ slash = bslash;
++ if (slash == NULL && path[0] != '\0' && path[1] == ':')
++ slash = path + 1;
++ }
++#endif
++
++ if (slash != (char *) NULL)
++ {
++ len = slash - path;
++ tmpname = (char *) xmalloc (len + sizeof (template) + 2);
++ memcpy (tmpname, path, len);
++
++#ifdef HAVE_DOS_BASED_FILE_SYSTEM
++ /* If tmpname is "X:", appending a slash will make it a root
++ directory on drive X, which is NOT the same as the current
++ directory on drive X. */
++ if (len == 2 && tmpname[1] == ':')
++ tmpname[len++] = '.';
++#endif
++ tmpname[len++] = '/';
++ }
++ else
++ {
++ tmpname = (char *) xmalloc (sizeof (template));
++ len = 0;
++ }
++
++ memcpy (tmpname + len, template, sizeof (template));
++#undef template
++
++#ifdef HAVE_MKSTEMP
++ fd = mkstemp (tmpname);
++#else
++ tmpname = mktemp (tmpname);
++ if (tmpname == NULL)
++ return NULL;
++ fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
++#endif
++ if (fd == -1)
++ return NULL;
++ return bfd_fopen (tmpname, target, mode, fd);
++}
++
++/* Add the object-only section. */
++
++static void
++cmdline_add_object_only_section (bfd_byte *contents, size_t size)
++{
++ bfd_vma start;
++ flagword flags;
++ enum bfd_architecture iarch;
++ unsigned int imach;
++ long symcount;
++ long symsize;
++ asymbol **isympp = NULL;
++ asymbol **osympp = NULL;
++ bfd *obfd = NULL, *ibfd;
++ const char *err;
++ struct arg
++ {
++ bfd *obfd;
++ asymbol **isympp;
++ int status;
++ } arg;
++ char **matching;
++ char *ofilename = NULL;
++ asection *sec;
++
++ ibfd = bfd_openr (output_filename, output_target);
++ if (!ibfd)
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ if (!bfd_check_format_matches (ibfd, bfd_object, &matching))
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ obfd = cmdline_fopen_temp (output_filename, output_target, "w");
++ if (!obfd)
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++ /* To be used after bfd_close (). */
++ ofilename = xstrdup (bfd_get_filename (obfd));
++
++ if (!bfd_set_format (obfd, bfd_object))
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ /* Copy the start address, flags and architecture of input file to
++ output file. */
++ flags = bfd_get_file_flags (ibfd);
++ start = bfd_get_start_address (ibfd);
++ iarch = bfd_get_arch (ibfd);
++ imach = bfd_get_mach (ibfd);
++ if (!bfd_set_start_address (obfd, start)
++ || !bfd_set_file_flags (obfd, flags)
++ || !bfd_set_arch_mach (obfd, iarch, imach))
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ symsize = bfd_get_symtab_upper_bound (ibfd);
++ if (symsize < 0)
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ isympp = (asymbol **) xmalloc (symsize);
++ symcount = bfd_canonicalize_symtab (ibfd, isympp);
++ if (symcount < 0)
++ {
++ err = bfd_errmsg (bfd_get_error ());
++ goto loser;
++ }
++
++ arg.obfd = obfd;
++ arg.isympp = isympp;
++ arg.status = 0;
++
++ /* BFD mandates that all output sections be created and sizes set before
++ any output is done. Thus, we traverse all sections multiple times. */
++ bfd_map_over_sections (ibfd, setup_section, &arg);
++
++ if (arg.status)
++ {
++ err = _("error setting up sections");
++ goto loser;
++ }
++
++ /* Allow the BFD backend to copy any private data it understands
++ from the input section to the output section. */
++ if (! bfd_copy_private_header_data (ibfd, obfd))
++ {
++ err = _("error copying private header data");
++ goto loser;
++ }
++
++ /* Create the object-only section. */
++ sec = bfd_make_section_with_flags (obfd,
++ GNU_OBJECT_ONLY_SECTION_NAME,
++ (SEC_HAS_CONTENTS
++ | SEC_READONLY
++ | SEC_DATA
++ | SEC_LINKER_CREATED));
++ if (sec == NULL)
++ {
++ err = _("can't create object-only section");
++ goto loser;
++ }
++
++ if (! bfd_set_section_size (obfd, sec, size))
++ {
++ err = _("can't set object-only section size");
++ goto loser;
++ }
++
++ if (ibfd->object_only_section)
++ {
++ /* Filter out the object-only section symbol. */
++ long src_count = 0, dst_count = 0;
++ asymbol **from, **to;
++
++ osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
++ from = isympp;
++ to = osympp;
++ for (; src_count < symcount; src_count++)
++ {
++ asymbol *sym = from[src_count];
++ if (bfd_get_section (sym) != ibfd->object_only_section)
++ to[dst_count++] = sym;
++ }
++ to[dst_count] = NULL;
++ symcount = dst_count;
++ bfd_set_symtab (obfd, osympp, symcount);
++ }
++ else
++ bfd_set_symtab (obfd, isympp, symcount);
++
++ /* This has to happen after the symbol table has been set. */
++ bfd_map_over_sections (ibfd, copy_section, &arg);
++
++ if (arg.status)
++ {
++ err = _("error copying sections");
++ goto loser;
++ }
++
++ /* Copy the object-only section to the output. */
++ if (! bfd_set_section_contents (obfd, sec, contents, 0, size))
++ {
++ err = _("error adding object-only section");
++ goto loser;
++ }
++
++ /* Allow the BFD backend to copy any private data it understands
++ from the input BFD to the output BFD. This is done last to
++ permit the routine to look at the filtered symbol table, which is
++ important for the ECOFF code at least. */
++ if (! bfd_copy_private_bfd_data (ibfd, obfd))
++ {
++ err = _("error copying private BFD data");
++ goto loser;
++ }
++
++ if (!bfd_close (obfd))
++ {
++ unlink (ofilename);
++ einfo (_("%P%F: failed to finish output with object-only section\n"));
++ }
++
++ /* Must be freed after bfd_close (). */
++ free (isympp);
++ if (osympp)
++ free (osympp);
++
++ if (rename (ofilename, output_filename))
++ {
++ unlink (ofilename);
++ einfo (_("%P%F: failed to rename output with object-only section\n"));
++ }
++
++ free (ofilename);
++ return;
++
++loser:
++ if (isympp)
++ free (isympp);
++ if (osympp)
++ free (osympp);
++ if (obfd)
++ bfd_close (obfd);
++ if (ofilename)
++ unlink (ofilename);
++ einfo (_("%P%F: failed to add object-only section: %s\n"), err);
++}
++
++/* Emit the final output with object-only section. */
++
++void
++cmdline_emit_object_only_section (void)
++{
++ const char *saved_output_filename = output_filename;
++ int fd;
++ size_t size, off;
++ bfd_byte *contents;
++ struct stat st;
++
++ /* Get a temporary object-only file. */
++ output_filename = make_temp_file (".obj-only.o");
++
++ had_output_filename = FALSE;
++ link_info.input_bfds = NULL;
++ link_info.input_bfds_tail = &link_info.input_bfds;
++
++ lang_init (TRUE);
++
++ ld_parse_linker_script ();
++
++ /* Set up the object-only output. */
++ lang_final ();
++
++ /* Open the object-only file for output. */
++ lang_for_each_statement (ldlang_open_output);
++
++ ldemul_create_output_section_statements ();
++
++ if (!bfd_section_already_linked_table_init ())
++ einfo (_("%P%F: Failed to create hash table\n"));
++
++ /* Call cmdline_on_object_only_archive_list_p to check which member
++ should be loaded. */
++ input_flags.whole_archive = TRUE;
++
++ /* Set it to avoid adding more to cmdline lists. */
++ link_info.emitting_gnu_object_only = TRUE;
++
++ /* Get object-only input files. */
++ cmdline_get_object_only_input_files ();
++
++ /* Open object-only input files. */
++ open_input_bfds (statement_list.head, FALSE);
++
++ ldemul_after_open ();
++
++ bfd_section_already_linked_table_free ();
++
++ /* Make sure that we're not mixing architectures. We call this
++ after all the input files have been opened, but before we do any
++ other processing, so that any operations merge_private_bfd_data
++ does on the output file will be known during the rest of the
++ link. */
++ lang_check ();
++
++ /* Size up the common data. */
++ lang_common ();
++
++ /* Update wild statements. */
++ update_wild_statements (statement_list.head);
++
++ /* Run through the contours of the script and attach input sections
++ to the correct output sections. */
++ map_input_to_output_sections (statement_list.head, NULL, NULL);
++
++ /* Find any sections not attached explicitly and handle them. */
++ lang_place_orphans ();
++
++ /* Do anything special before sizing sections. This is where ELF
++ and other back-ends size dynamic sections. */
++ ldemul_before_allocation ();
++
++ /* Size up the sections. */
++ lang_size_sections (NULL, ! RELAXATION_ENABLED);
++
++ /* See if anything special should be done now we know how big
++ everything is. This is where relaxation is done. */
++ ldemul_after_allocation ();
++
++ ldemul_finish ();
++
++ /* Make sure that the section addresses make sense. */
++ if (command_line.check_section_addresses)
++ lang_check_section_addresses ();
++
++ lang_end ();
++
++ ldwrite ();
++
++ lang_finish (TRUE);
++
++ if (! bfd_close (link_info.output_bfd))
++ einfo (_("%P%F:%s: final close failed on object-only output: %E\n"),
++ output_filename);
++
++ /* Read in the object-only file. */
++ fd = open (output_filename, O_RDONLY | O_BINARY);
++ if (fd < 0)
++ {
++ bfd_set_error (bfd_error_system_call);
++ einfo (_("%P%F:%s: cannot open object-only output: %E"),
++ output_filename);
++ }
++
++ /* Get the object-only file size. */
++ if (fstat (fd, &st) != 0)
++ {
++ bfd_set_error (bfd_error_system_call);
++ einfo (_("%P%F:%s: cannot stat object-only output: %E"),
++ output_filename);
++ }
++
++ size = st.st_size;
++ off = 0;
++ contents = (bfd_byte *) xmalloc (size);
++ while (off != size)
++ {
++ ssize_t got;
++
++ got = read (fd, contents + off, size - off);
++ if (got < 0)
++ {
++ bfd_set_error (bfd_error_system_call);
++ einfo (_("%P%F:%s: read failed on object-only output: %E"),
++ output_filename);
++ }
++
++ off += got;
++ }
++
++ close (fd);
++
++ /* Remove the temporary object-only file. */
++ unlink (output_filename);
++
++ output_filename = saved_output_filename;
++
++ cmdline_add_object_only_section (contents, size);
++
++ free (contents);
++}
++
++/* Extract the object-only section. */
++
++static const char *
++cmdline_extract_object_only_section (bfd *abfd)
++{
++ const char *name = bfd_extract_object_only_section (abfd);
++
++ if (name == NULL)
++ einfo (_("%P%F: cannot extract object-only section from %B: %E"),
++ abfd);
++
++ /* It should be removed after it is done. */
++ cmdline_list_append (&cmdline_temp_object_only_list,
++ cmdline_is_file_enum, (void *) name);
++
++ return name;
++}
++
++/* Check and handle the object-only section. */
++
++void
++cmdline_check_object_only_section (bfd *abfd, bfd_boolean lto)
++{
++ const char *filename;
++
++ if (link_info.emitting_gnu_object_only
++ || abfd->format != bfd_object)
++ return;
++
++ if (lto)
++ {
++ /* For LTO link, we only need to extract object-only section
++ from the mixed object, add it to input, and put it on LTO
++ claimed output. */
++ switch (abfd->lto_type)
++ {
++ default:
++ abort ();
++ case lto_mixed_object:
++ filename = cmdline_extract_object_only_section (abfd);
++ lang_add_input_file (filename,
++ lang_input_file_is_file_enum, NULL);
++ break;
++ case lto_non_ir_object:
++ case lto_ir_object:
++ break;
++ }
++ }
++ else if (link_info.relocatable)
++ {
++ /* For non-LTO relocatable link, we need to append non-IR object
++ file and the object file in object-only section to the object
++ only list. */
++ switch (abfd->lto_type)
++ {
++ default:
++ abort ();
++ case lto_mixed_object:
++ filename = cmdline_extract_object_only_section (abfd);
++ cmdline_object_only_list_append (cmdline_is_file_enum,
++ (void *) filename);
++ break;
++ case lto_non_ir_object:
++ cmdline_object_only_list_append (cmdline_is_bfd_enum, abfd);
++ break;
++ case lto_ir_object:
++ break;
++ }
++ }
++}
++
++/* Remove temporary object-only files. */
++
++void
++cmdline_remove_object_only_files (void)
++{
++ cmdline_union_type *c;
++
++#ifdef ENABLE_PLUGINS
++ if (plugin_save_temps)
++ return;
++#endif
++
++ c = cmdline_temp_object_only_list.head;
++ for (; c != NULL; c = c->header.next)
++ switch (c->header.type)
++ {
++ default:
++ abort ();
++ case cmdline_is_file_enum:
++ unlink (c->file.filename);
++ break;
++ }
++}
+diff --git a/ld/ldlang.h b/ld/ldlang.h
+index 5f6faae..0b334e0 100644
+--- a/ld/ldlang.h
++++ b/ld/ldlang.h
+@@ -523,9 +523,9 @@ extern struct asneeded_minfo **asneeded_list_tail;
+ extern void (*output_bfd_hash_table_free_fn) (struct bfd_link_hash_table *);
+
+ extern void lang_init
+- (void);
++ (bfd_boolean);
+ extern void lang_finish
+- (void);
++ (bfd_boolean);
+ extern lang_memory_region_type * lang_memory_region_lookup
+ (const char * const, bfd_boolean);
+ extern void lang_memory_region_alias
+@@ -698,4 +698,45 @@ ldlang_override_segment_assignment
+ extern void
+ lang_ld_feature (char *);
+
++typedef enum
++{
++ cmdline_is_file_enum,
++ cmdline_is_bfd_enum
++} cmdline_enum_type;
++
++typedef struct cmdline_header_struct
++{
++ union cmdline_union *next;
++ cmdline_enum_type type;
++} cmdline_header_type;
++
++typedef struct cmdline_file_struct
++{
++ cmdline_header_type header;
++ const char *filename;
++} cmdline_file_type;
++
++typedef struct cmdline_bfd_struct
++{
++ cmdline_header_type header;
++ bfd *abfd;
++} cmdline_bfd_type;
++
++typedef union cmdline_union
++{
++ cmdline_header_type header;
++ cmdline_file_type file;
++ cmdline_bfd_type abfd;
++} cmdline_union_type;
++
++typedef struct cmdline_list
++{
++ cmdline_union_type *head;
++ cmdline_union_type **tail;
++} cmdline_list_type;
++
++extern void cmdline_emit_object_only_section (void);
++extern void cmdline_check_object_only_section (bfd *, bfd_boolean);
++extern void cmdline_remove_object_only_files (void);
++
+ #endif
+diff --git a/ld/ldlex.h b/ld/ldlex.h
+index 63f4c81..2019bc3 100644
+--- a/ld/ldlex.h
++++ b/ld/ldlex.h
+@@ -133,6 +133,7 @@ enum option_values
+ #ifdef ENABLE_PLUGINS
+ OPTION_PLUGIN,
+ OPTION_PLUGIN_OPT,
++ OPTION_PLUGIN_SAVE_TEMPS,
+ #endif /* ENABLE_PLUGINS */
+ OPTION_DEFAULT_SCRIPT,
+ OPTION_PRINT_OUTPUT_FORMAT,
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index 77235d5..5670328 100644
+--- a/ld/ldmain.c
++++ b/ld/ldmain.c
+@@ -220,6 +220,9 @@ main (int argc, char **argv)
+
+ xatexit (ld_cleanup);
+
++ /* Remove temporary object-only files. */
++ xatexit (cmdline_remove_object_only_files);
++
+ /* Set up the sysroot directory. */
+ ld_sysroot = get_sysroot (argc, argv);
+ if (*ld_sysroot)
+@@ -296,7 +299,7 @@ main (int argc, char **argv)
+ default_target = ldemul_choose_target (argc, argv);
+ config.maxpagesize = bfd_emul_get_maxpagesize (default_target);
+ config.commonpagesize = bfd_emul_get_commonpagesize (default_target);
+- lang_init ();
++ lang_init (FALSE);
+ ldemul_before_parse ();
+ lang_has_input_file = FALSE;
+ parse_args (argc, argv);
+@@ -311,34 +314,7 @@ main (int argc, char **argv)
+
+ ldemul_set_symbols ();
+
+- /* If we have not already opened and parsed a linker script,
+- try the default script from command line first. */
+- if (saved_script_handle == NULL
+- && command_line.default_script != NULL)
+- {
+- ldfile_open_command_file (command_line.default_script);
+- parser_input = input_script;
+- yyparse ();
+- }
+-
+- /* If we have not already opened and parsed a linker script
+- read the emulation's appropriate default script. */
+- if (saved_script_handle == NULL)
+- {
+- int isfile;
+- char *s = ldemul_get_script (&isfile);
+-
+- if (isfile)
+- ldfile_open_default_command_file (s);
+- else
+- {
+- lex_string = s;
+- lex_redirect (s, _("built in linker script"), 1);
+- }
+- parser_input = input_script;
+- yyparse ();
+- lex_string = NULL;
+- }
++ ld_parse_linker_script ();
+
+ if (verbose)
+ {
+@@ -440,7 +416,7 @@ main (int argc, char **argv)
+ fprintf (stderr, "lookup = %p val %lx\n", h, h ? h->u.def.value : 1);
+ }
+ #endif
+- lang_finish ();
++ lang_finish (FALSE);
+
+ /* Even if we're producing relocatable output, some non-fatal errors should
+ be reported in the exit status. (What non-fatal errors, if any, do we
+@@ -459,6 +435,8 @@ main (int argc, char **argv)
+ if (! bfd_close (link_info.output_bfd))
+ einfo (_("%F%B: final close failed: %E\n"), link_info.output_bfd);
+
++ link_info.output_bfd = NULL;
++
+ /* If the --force-exe-suffix is enabled, and we're making an
+ executable file and it doesn't end in .exe, copy it to one
+ which does. */
+@@ -505,6 +483,9 @@ main (int argc, char **argv)
+ }
+ }
+
++ if (link_info.emit_gnu_object_only)
++ cmdline_emit_object_only_section ();
++
+ END_PROGRESS (program_name);
+
+ if (config.stats)
+@@ -812,7 +793,9 @@ add_archive_element (struct bfd_link_info *info,
+ }
+ }
+ }
++ else
+ #endif /* ENABLE_PLUGINS */
++ cmdline_check_object_only_section (input->the_bfd, FALSE);
+
+ ldlang_add_file (input);
+
+@@ -1491,3 +1474,38 @@ notice (struct bfd_link_info *info,
+
+ return TRUE;
+ }
++
++/* Parse the linker script. */
++
++void
++ld_parse_linker_script ()
++{
++ /* If we have not already opened and parsed a linker script,
++ try the default script from command line first. */
++ if (saved_script_handle == NULL
++ && command_line.default_script != NULL)
++ {
++ ldfile_open_command_file (command_line.default_script);
++ parser_input = input_script;
++ yyparse ();
++ }
++
++ /* If we have not already opened and parsed a linker script
++ read the emulation's appropriate default script. */
++ if (saved_script_handle == NULL)
++ {
++ int isfile;
++ char *s = ldemul_get_script (&isfile);
++
++ if (isfile)
++ ldfile_open_default_command_file (s);
++ else
++ {
++ lex_string = s;
++ lex_redirect (s, _("built in linker script"), 1);
++ }
++ parser_input = input_script;
++ yyparse ();
++ lex_string = NULL;
++ }
++}
+diff --git a/ld/ldmain.h b/ld/ldmain.h
+index dce9650..5c1efc3 100644
+--- a/ld/ldmain.h
++++ b/ld/ldmain.h
+@@ -59,4 +59,6 @@ extern void add_wrap (const char *);
+ extern void add_ignoresym (struct bfd_link_info *, const char *);
+ extern void add_keepsyms_file (const char *);
+
++extern void ld_parse_linker_script (void);
++
+ #endif
+diff --git a/ld/lexsup.c b/ld/lexsup.c
+index 3a1ea9e..a0612e1 100644
+--- a/ld/lexsup.c
++++ b/ld/lexsup.c
+@@ -166,6 +166,9 @@ static const struct ld_option ld_options[] =
+ '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
+ { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
+ '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
++ { {"plugin-save-temps", no_argument, NULL, OPTION_PLUGIN_SAVE_TEMPS},
++ '\0', NULL, N_("Store plugin intermediate files permanently"),
++ ONE_DASH },
+ { {"flto", optional_argument, NULL, OPTION_IGNORE},
+ '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
+ ONE_DASH },
+@@ -971,6 +974,9 @@ parse_args (unsigned argc, char **argv)
+ if (plugin_opt_plugin_arg (optarg))
+ einfo(_("%P%F: bad -plugin-opt option\n"));
+ break;
++ case OPTION_PLUGIN_SAVE_TEMPS:
++ plugin_save_temps = TRUE;
++ break;
+ #endif /* ENABLE_PLUGINS */
+ case 'q':
+ link_info.emitrelocations = TRUE;
+diff --git a/ld/plugin.c b/ld/plugin.c
+index f02a97f..0a16644 100644
+--- a/ld/plugin.c
++++ b/ld/plugin.c
+@@ -39,6 +39,9 @@
+ /* Report plugin symbols. */
+ bfd_boolean report_plugin_symbols;
+
++/* Store plugin intermediate files permanently. */
++bfd_boolean plugin_save_temps;
++
+ /* The suffix to append to the name of the real (claimed) object file
+ when generating a dummy BFD to hold the IR symbols sent from the
+ plugin. For cosmetic use only; appears in maps, crefs etc. */
+@@ -882,6 +885,9 @@ plugin_maybe_claim (struct ld_plugin_input_file *file,
+ close (file->fd);
+ if (claimed)
+ {
++ /* Check object only section. */
++ cmdline_check_object_only_section (entry->the_bfd, TRUE);
++
+ /* Discard the real file's BFD and substitute the dummy one. */
+
+ /* BFD archive handling caches elements so we can't call
+@@ -935,14 +941,17 @@ plugin_call_cleanup (void)
+ {
+ if (curplug->cleanup_handler && !curplug->cleanup_done)
+ {
+- enum ld_plugin_status rv;
+- curplug->cleanup_done = TRUE;
+- called_plugin = curplug;
+- rv = (*curplug->cleanup_handler) ();
+- called_plugin = NULL;
+- if (rv != LDPS_OK)
+- info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
+- curplug->name, rv);
++ if (!plugin_save_temps)
++ {
++ enum ld_plugin_status rv;
++ curplug->cleanup_done = TRUE;
++ called_plugin = curplug;
++ rv = (*curplug->cleanup_handler) ();
++ called_plugin = NULL;
++ if (rv != LDPS_OK)
++ info_msg (_("%P: %s: error in plugin cleanup: %d (ignored)\n"),
++ curplug->name, rv);
++ }
+ dlclose (curplug->dlhandle);
+ }
+ curplug = curplug->next;
+diff --git a/ld/plugin.h b/ld/plugin.h
+index bccbee3..483519e 100644
+--- a/ld/plugin.h
++++ b/ld/plugin.h
+@@ -24,6 +24,9 @@
+ /* Report plugin symbols. */
+ extern bfd_boolean report_plugin_symbols;
+
++/* Store plugin intermediate files permanently. */
++extern bfd_boolean plugin_save_temps;
++
+ /* Set at all symbols read time, to avoid recursively offering the plugin
+ its own newly-added input files and libs to claim. */
+ extern bfd_boolean no_more_claiming;
+diff --git a/ld/scripttempl/armbpabi.sc b/ld/scripttempl/armbpabi.sc
+index a1bbc2b..d85aeba 100644
+--- a/ld/scripttempl/armbpabi.sc
++++ b/ld/scripttempl/armbpabi.sc
+@@ -30,7 +30,7 @@ INTERP=".interp 0 : { *(.interp) }"
+ PLT=".plt ${RELOCATING-0} : { *(.plt) }"
+ RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+ DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro .data.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }"
+ if test -z "${NO_SMALL_DATA}"; then
+ SBSS=".sbss ${RELOCATING-0} :
+ {
+diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
+index 6d0d13d..b721c10 100644
+--- a/ld/scripttempl/elf.sc
++++ b/ld/scripttempl/elf.sc
+@@ -160,7 +160,7 @@ RELA_IPLT=".rela.iplt ${RELOCATING-0} :
+ DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
+ RODATA=".${RODATA_NAME} ${RELOCATING-0} : { *(.${RODATA_NAME}${RELOCATING+ .${RODATA_NAME}.* .gnu.linkonce.r.*}) }"
+ DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }"
+ if test -z "${NO_SMALL_DATA}"; then
+ SBSS=".${SBSS_NAME} ${RELOCATING-0} :
+ {
+diff --git a/ld/scripttempl/elf32sh-symbian.sc b/ld/scripttempl/elf32sh-symbian.sc
+index 680028f..9130376 100644
+--- a/ld/scripttempl/elf32sh-symbian.sc
++++ b/ld/scripttempl/elf32sh-symbian.sc
+@@ -83,7 +83,7 @@ fi
+ PLT=".plt : { *(.plt) } :dynamic :dyn"
+ DYNAMIC=".dynamic : { *(.dynamic) } :dynamic :dyn"
+ RODATA=".rodata ALIGN(4) : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.directive) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.directive) *(.gnu.lto_*) *(.gnu_object_only) }"
+ test -z "$GOT" && GOT=".got ${RELOCATING-0} : { *(.got.plt) *(.got) } :dynamic :dyn"
+ INIT_ARRAY=".init_array ${RELOCATING-0} :
+ {
+diff --git a/ld/scripttempl/elf64hppa.sc b/ld/scripttempl/elf64hppa.sc
+index d529f8d..7676925 100644
+--- a/ld/scripttempl/elf64hppa.sc
++++ b/ld/scripttempl/elf64hppa.sc
+@@ -127,7 +127,7 @@ fi
+ DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
+ RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+ DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }"
+ if test -z "${NO_SMALL_DATA}"; then
+ SBSS=".sbss ${RELOCATING-0} :
+ {
+diff --git a/ld/scripttempl/elfxtensa.sc b/ld/scripttempl/elfxtensa.sc
+index b51fe6a..a440d68 100644
+--- a/ld/scripttempl/elfxtensa.sc
++++ b/ld/scripttempl/elfxtensa.sc
+@@ -140,7 +140,7 @@ fi
+ DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
+ RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+ DATARELRO=".data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }"
+ INIT_LIT=".init.literal 0 : { *(.init.literal) }"
+ INIT=".init 0 : { *(.init) }"
+ FINI_LIT=".fini.literal 0 : { *(.fini.literal) }"
+diff --git a/ld/scripttempl/mep.sc b/ld/scripttempl/mep.sc
+index cf85f76..562696b 100644
+--- a/ld/scripttempl/mep.sc
++++ b/ld/scripttempl/mep.sc
+@@ -114,7 +114,7 @@ fi
+ DYNAMIC=".dynamic ${RELOCATING-0} : { *(.dynamic) }"
+ RODATA=".rodata ${RELOCATING-0} : { *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) }"
+ DATARELRO=".data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro .data.rel.ro.*) }"
+-DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }"
++DISCARDED="/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) }"
+ if test -z "${NO_SMALL_DATA}"; then
+ SBSS=".sbss ${RELOCATING-0} :
+ {
+diff --git a/ld/scripttempl/pe.sc b/ld/scripttempl/pe.sc
+index 579c0c8..cdf92da 100644
+--- a/ld/scripttempl/pe.sc
++++ b/ld/scripttempl/pe.sc
+@@ -153,6 +153,7 @@ SECTIONS
+ *(.drectve)
+ ${RELOCATING+ *(.note.GNU-stack)}
+ ${RELOCATING+ *(.gnu.lto_*)}
++ ${RELOCATING+ *(.gnu_object_only)}
+ }
+
+ .idata ${RELOCATING+BLOCK(__section_alignment__)} :
+diff --git a/ld/scripttempl/pep.sc b/ld/scripttempl/pep.sc
+index a71dd21..9714a0a 100644
+--- a/ld/scripttempl/pep.sc
++++ b/ld/scripttempl/pep.sc
+@@ -158,6 +158,7 @@ SECTIONS
+ *(.drectve)
+ ${RELOCATING+ *(.note.GNU-stack)}
+ ${RELOCATING+ *(.gnu.lto_*)}
++ ${RELOCATING+ *(.gnu_object_only)}
+ }
+
+ .idata ${RELOCATING+BLOCK(__section_alignment__)} :
+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-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.exp b/ld/testsuite/ld-plugin/lto.exp
+index 7ff5bfb..d1d5a21 100644
+--- a/ld/testsuite/ld-plugin/lto.exp
++++ b/ld/testsuite/ld-plugin/lto.exp
+@@ -76,6 +76,15 @@ set lto_link_tests [list \
+ [list "Build liblto-3.a" \
+ "" "-flto $lto_fat" \
+ {lto-3b.c} {} "liblto-3.a"] \
++ [list "Compile 4a" \
++ "" "-flto $lto_fat" \
++ {lto-4a.c} {} ""] \
++ [list "Compile 4b" \
++ "" "-O2" \
++ {lto-4b.c} {} ""] \
++ [list "Compile 4c" \
++ "" "-O2" \
++ {lto-4c.c} {} ""] \
+ [list "Compile 5a" \
+ "" "-flto $lto_fat" \
+ {lto-5a.c} {} ""] \
+@@ -85,9 +94,18 @@ set lto_link_tests [list \
+ [list "LTO 6" \
+ "-O2 -flto -fuse-linker-plugin" "" \
+ {lto-6.c} {} "lto-6.exe" "c"] \
++ [list "Compile PR ld/12365" \
++ "" "-flto -O2 $lto_fat" \
++ {pr12365a.c pr12365b.c pr12365c.c} {} ""] \
+ [list "Compile 9" \
+ "" "-O2 -finline -flto" \
+ {lto-9.cc} {} "" "c++"] \
++ [list "Compile 10a" \
++ "" "-O2" \
++ {lto-10a.c} {} ""] \
++ [list "Compile 10b" \
++ "" "-O2 -flto $lto_fat" \
++ {lto-10b.c} {} ""] \
+ [list "Compile 11a" \
+ "" "-O -flto" \
+ {lto-11a.c} {} ""] \
+@@ -244,6 +262,9 @@ set lto_link_elf_tests [list \
+ [list "PR ld/16746 (2)" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/pr16746c.o tmpdir/pr16746a.o" "-O2 -flto" \
+ {dummy.c} {} "pr16746b.exe"] \
++ [list "PR ld/14918" \
++ "-flto" "-flto" \
++ {pr14918.c} {{"readelf" {-d --wide} "pr14918.d"}} "pr14918.exe" "c"] \
+ ]
+
+ # Check final symbols in executables.
+@@ -279,9 +300,21 @@ set lto_run_tests [list \
+ [list "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"] \
++ [list "LTO 4a" \
++ "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-a.o" "" \
++ {dummy.c} "lto-4a.exe" "lto-4.out" "" "c"] \
++ [list "LTO 4c" \
++ "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-c.o" "" \
++ {dummy.c} "lto-4c.exe" "lto-4.out" "" "c"] \
++ [list "LTO 4d" \
++ "-O2 -flto -fuse-linker-plugin tmpdir/lto-4r-d.o" "" \
++ {dummy.c} "lto-4d.exe" "lto-4.out" "" "c"] \
+ [list "LTO 5" \
+ "-O2 -flto -fuse-linker-plugin tmpdir/lto-5.o" "" \
+ {dummy.c} "lto-5.exe" "lto-5.out" "" "c"] \
++ [list "LTO 10" \
++ "-O2 -flto -fuse-linker-plugin tmpdir/lto-10.o" "" \
++ {dummy.c} "lto-10.exe" "lto-10.out" "" "c"] \
+ [list "LTO 11" \
+ "-O -flto -fuse-linker-plugin tmpdir/liblto-11.a" "" \
+ {dummy.c} "lto-11.exe" "lto-11.out" "" "c"] \
+@@ -363,6 +396,15 @@ if { [is_elf_format] && [check_lto_shared_available] } {
+ }
+ }
+
++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
++ restore_notify
++ return
++}
++
+ set testname "Build liblto-11.a"
+ remote_file host delete "tmpdir/liblto-11.a"
+ set catch_output [run_host_cmd "$ar" "rc $plug_opt tmpdir/liblto-11.a tmpdir/lto-11a.o tmpdir/lto-11b.o tmpdir/lto-11c.o"]
+@@ -374,6 +416,13 @@ if {![string match "" $catch_output]} {
+
+ if { [at_least_gcc_version 4 7] } {
+ # Check expected 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
++ }
+ set testname "PR ld/12942 (3)"
+ set exec_output [run_host_cmd "$CXX" "-O2 -flto -fuse-linker-plugin tmpdir/pr12942b.o tmpdir/pr12942a.o"]
+ if { [ regexp "undefined reference to `link_error\\(\\)'" $exec_output ] } {
+@@ -386,8 +435,30 @@ if { [at_least_gcc_version 4 7] } {
+ # 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"
++set testname "nm mixed object"
++set lto_plugin [run_host_cmd "$CC" "-print-prog-name=liblto_plugin.so tmpdir/lto-10.o"]
++if { [ regexp "liblto_plugin.so" $lto_plugin ] } {
++ set exec_output [run_host_cmd "$NM" "--plugin $lto_plugin tmpdir/lto-10.o"]
++ if { [ regexp "T main" $exec_output ] } {
++ pass $testname
++ } {
++ fail $testname
++ }
++} {
++ fail $testname
++ }
+
+ run_cc_link_tests $lto_link_symbol_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..a5a80e0
+--- /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/ld-plugin/pr14918.c b/ld/testsuite/ld-plugin/pr14918.c
+new file mode 100644
+index 0000000..a9bce4a
+--- /dev/null
++++ b/ld/testsuite/ld-plugin/pr14918.c
+@@ -0,0 +1,5 @@
++int
++main ()
++{
++ return 0;
++}
+diff --git a/ld/testsuite/ld-plugin/pr14918.d b/ld/testsuite/ld-plugin/pr14918.d
+new file mode 100644
+index 0000000..0b14948
+--- /dev/null
++++ b/ld/testsuite/ld-plugin/pr14918.d
+@@ -0,0 +1,4 @@
++#failif
++#...
++ 0x0+1 \(NEEDED\) +Shared library: \[libgcc_s.so.[0-9]+\]
++#...
diff --git a/patches/binutils-pr12639.patch b/patches/binutils-pr12639.patch
new file mode 100644
index 0000000..a0b5fec
--- /dev/null
+++ b/patches/binutils-pr12639.patch
@@ -0,0 +1,104 @@
+From e1b9237d84d013c5d0586edeb5267c823c4b9284 Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Tue, 5 Nov 2013 10:14:57 -0800
+Subject: [PATCH] Check corrupted symbol table
+
+---
+ ChangeLog.pr12639 | 15 +++++++++++++++
+ bfd/elfcode.h | 12 ++++++++++++
+ binutils/readelf.c | 13 ++++++++++++-
+ 3 files changed, 39 insertions(+), 1 deletion(-)
+ create mode 100644 ChangeLog.pr12639
+
+diff --git a/ChangeLog.pr12639 b/ChangeLog.pr12639
+new file mode 100644
+index 0000000..e7a41f4
+--- /dev/null
++++ b/ChangeLog.pr12639
+@@ -0,0 +1,15 @@
++bfd/
++
++2013-11-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR binutils/12639
++ * elfcode.h (elf_slurp_symbol_table): Check corrupted global
++ symbols.
++
++binutils/
++
++2013-11-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR binutils/12639
++ * readelf.c (process_symbol_table): Detect corrupted symbol
++ table.
+diff --git a/bfd/elfcode.h b/bfd/elfcode.h
+index e296c5c..cf45c27 100644
+--- a/bfd/elfcode.h
++++ b/bfd/elfcode.h
+@@ -1168,6 +1168,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
+ sym = symbase = NULL;
+ else
+ {
++ /* Start of global symbols */
++ Elf_Internal_Sym *start_global;
++
+ isymbuf = bfd_elf_get_elf_syms (abfd, hdr, symcount, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+@@ -1212,6 +1215,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
+ if (xver != NULL)
+ ++xver;
+ isymend = isymbuf + symcount;
++ start_global = isymbuf;
++ if (!elf_bad_symtab (abfd))
++ start_global += hdr->sh_info;
+ for (isym = isymbuf + 1, sym = symbase; isym < isymend; isym++, sym++)
+ {
+ memcpy (&sym->internal_elf_sym, isym, sizeof (Elf_Internal_Sym));
+@@ -1270,6 +1276,12 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ sym->symbol.value -= sym->symbol.section->vma;
+
++ if (isym < start_global
++ && ELF_ST_BIND (isym->st_info) != STB_LOCAL)
++ (*_bfd_error_handler)
++ (_("%s: corrupted global symbol `%s' treated as local"),
++ abfd->filename, sym->symbol.name);
++
+ switch (ELF_ST_BIND (isym->st_info))
+ {
+ case STB_LOCAL:
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index 0389f14..9ae5b5d 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -9607,6 +9607,12 @@ process_symbol_table (FILE * file)
+ else if (do_dyn_syms || (do_syms && !do_using_dynamic))
+ {
+ unsigned int i;
++ /* Irix 5 and 6 are broken. Object file symbol tables are not
++ always sorted correctly such that local symbols precede global
++ symbols, and the sh_info field in the symbol table is not
++ always right. */
++ bfd_boolean check_corrupt_symtab
++ = elf_header.e_ident[EI_OSABI] != ELFOSABI_IRIX;
+
+ for (i = 0, section = section_headers;
+ i < elf_header.e_shnum;
+@@ -9669,7 +9675,12 @@ process_symbol_table (FILE * file)
+ putchar (' ');
+ print_vma (psym->st_size, DEC_5);
+ printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info)));
+- printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
++ if (check_corrupt_symtab
++ && si < section->sh_info
++ && ELF_ST_BIND (psym->st_info) != STB_LOCAL)
++ printf (" %-6s", "<corrupt>");
++ else
++ printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info)));
+ printf (" %-7s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other)));
+ /* Check to see if any other bits in the st_other field are set.
+ Note - displaying this information disrupts the layout of the
+--
+1.8.3.1
+
diff --git a/patches/binutils-pr14675.patch b/patches/binutils-pr14675.patch
new file mode 100644
index 0000000..6875a5c
--- /dev/null
+++ b/patches/binutils-pr14675.patch
@@ -0,0 +1,197 @@
+From 4a5d5d94ca76cbf730d7f0379601e75f9469670e Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Sat, 20 Dec 2014 05:45:51 -0800
+Subject: [PATCH] Treat .eh_frame section before crtbegin as normal input
+
+Force the exception frame section from input files before the crtbegin
+file to be handled as an ordinary input section if we aren't creating
+the exception frame header. If we don't do this, we won't correctly
+handle the special marker symbol in the exception frame section in the
+crtbegin file.
+
+ PR gold/14675
+ * ehframe.cc (Eh_frame::add_ehframe_input_section): Force the
+ exception frame section from input files before the crtbegin
+ file to be handled as an ordinary input section if we aren't
+ creating the exception frame header.
+ (Eh_frame::add_ehframe_input_section<32, false>): Updated.
+ (Eh_frame::add_ehframe_input_section<32, true>): Likewise.
+ (Eh_frame::add_ehframe_input_section<64, false>): Likewise.
+ (Eh_frame::add_ehframe_input_section<64, true>): Likewise.
+ * ehframe.h (Eh_frame::add_ehframe_input_section): Add a
+ bool parameter to indicate if the crtbegin file has been
+ processed.
+ * layout.cc (Layout::Layout): Initialize seen_crtbegin_.
+ (Layout::layout_eh_frame): Pass this->seen_crtbegin_ to
+ Eh_frame::add_ehframe_input_section.
+ (Layout::make_eh_frame_section): Set this->seen_crtbegin_ to
+ true when processing the crtbegin file.
+ * layout.h (Layout): Add a seen_crtbegin_ field.
+---
+ gold/ChangeLog | 21 +++++++++++++++++++++
+ gold/ehframe.cc | 34 ++++++++++++++++++++++++----------
+ gold/ehframe.h | 6 ++++--
+ gold/layout.cc | 10 +++++++++-
+ gold/layout.h | 3 +++
+ 5 files changed, 61 insertions(+), 13 deletions(-)
+
+diff --git a/gold/ehframe.cc b/gold/ehframe.cc
+index c711bac..dde90df 100644
+--- a/gold/ehframe.cc
++++ b/gold/ehframe.cc
+@@ -576,7 +576,8 @@ Eh_frame::add_ehframe_input_section(
+ section_size_type symbol_names_size,
+ unsigned int shndx,
+ unsigned int reloc_shndx,
+- unsigned int reloc_type)
++ unsigned int reloc_type,
++ bool crtbegin_seen)
+ {
+ // Get the section contents.
+ section_size_type contents_len;
+@@ -595,15 +596,24 @@ Eh_frame::add_ehframe_input_section(
+ return false;
+
+ New_cies new_cies;
+- if (!this->do_add_ehframe_input_section(object, symbols, symbols_size,
++ bool recognized_eh_frame_section
++ = this->do_add_ehframe_input_section(object, symbols, symbols_size,
+ symbol_names, symbol_names_size,
+ shndx, reloc_shndx,
+ reloc_type, pcontents,
+- contents_len, &new_cies))
++ contents_len, &new_cies);
++ if (!recognized_eh_frame_section && this->eh_frame_hdr_ != NULL)
++ this->eh_frame_hdr_->found_unrecognized_eh_frame_section();
++
++ // If we don't unrecognize the exception frame section or we haven't
++ // seen the crtbegin file and we aren't creating the exception frame
++ // header, then return false to force it to be handled as an ordinary
++ // input section. If we don't do this, we won't correctly handle the
++ // special marker symbol in the exception frame section in the crtbegin
++ // file.
++ if (!recognized_eh_frame_section
++ || (this->eh_frame_hdr_ == NULL && !crtbegin_seen))
+ {
+- if (this->eh_frame_hdr_ != NULL)
+- this->eh_frame_hdr_->found_unrecognized_eh_frame_section();
+-
+ for (New_cies::iterator p = new_cies.begin();
+ p != new_cies.end();
+ ++p)
+@@ -1224,7 +1234,8 @@ Eh_frame::add_ehframe_input_section<32, false>(
+ section_size_type symbol_names_size,
+ unsigned int shndx,
+ unsigned int reloc_shndx,
+- unsigned int reloc_type);
++ unsigned int reloc_type,
++ bool crtbegin_seen);
+ #endif
+
+ #ifdef HAVE_TARGET_32_BIG
+@@ -1238,7 +1249,8 @@ Eh_frame::add_ehframe_input_section<32, true>(
+ section_size_type symbol_names_size,
+ unsigned int shndx,
+ unsigned int reloc_shndx,
+- unsigned int reloc_type);
++ unsigned int reloc_type,
++ bool crtbegin_seen);
+ #endif
+
+ #ifdef HAVE_TARGET_64_LITTLE
+@@ -1252,7 +1264,8 @@ Eh_frame::add_ehframe_input_section<64, false>(
+ section_size_type symbol_names_size,
+ unsigned int shndx,
+ unsigned int reloc_shndx,
+- unsigned int reloc_type);
++ unsigned int reloc_type,
++ bool crtbegin_seen);
+ #endif
+
+ #ifdef HAVE_TARGET_64_BIG
+@@ -1266,7 +1279,8 @@ Eh_frame::add_ehframe_input_section<64, true>(
+ section_size_type symbol_names_size,
+ unsigned int shndx,
+ unsigned int reloc_shndx,
+- unsigned int reloc_type);
++ unsigned int reloc_type,
++ bool crtbegin_seen);
+ #endif
+
+ } // End namespace gold.
+diff --git a/gold/ehframe.h b/gold/ehframe.h
+index 2ae12e0..b0effa0 100644
+--- a/gold/ehframe.h
++++ b/gold/ehframe.h
+@@ -371,7 +371,8 @@ class Eh_frame : public Output_section_data
+ // is the relocation section if any (0 for none, -1U for multiple).
+ // RELOC_TYPE is the type of the relocation section if any. This
+ // returns whether the section was incorporated into the .eh_frame
+- // data.
++ // data. CRTBEGIN_SEEN is true if the crtbegin file has been
++ // processed.
+ template<int size, bool big_endian>
+ bool
+ add_ehframe_input_section(Sized_relobj_file<size, big_endian>* object,
+@@ -380,7 +381,8 @@ class Eh_frame : public Output_section_data
+ const unsigned char* symbol_names,
+ section_size_type symbol_names_size,
+ unsigned int shndx, unsigned int reloc_shndx,
+- unsigned int reloc_type);
++ unsigned int reloc_type,
++ bool crtbegin_seen);
+
+ // Add a CIE and an FDE for a PLT section, to permit unwinding
+ // through a PLT. The FDE data should start with 8 bytes of zero,
+diff --git a/gold/layout.cc b/gold/layout.cc
+index 0a71a2a..6649f9f 100644
+--- a/gold/layout.cc
++++ b/gold/layout.cc
+@@ -469,6 +469,7 @@ Layout::Layout(int number_of_input_files, Script_options* script_options)
+ unique_segment_for_sections_specified_(false),
+ incremental_inputs_(NULL),
+ record_output_section_data_from_script_(false),
++ seen_crtbegin_(false),
+ script_output_section_data_list_(),
+ segment_states_(NULL),
+ relaxation_debug_check_(NULL),
+@@ -1428,7 +1429,8 @@ Layout::layout_eh_frame(Sized_relobj_file<size, big_endian>* object,
+ symbol_names_size,
+ shndx,
+ reloc_shndx,
+- reloc_type))
++ reloc_type,
++ this->seen_crtbegin_))
+ {
+ os->update_flags_for_input_section(shdr.get_sh_flags());
+
+@@ -1485,6 +1487,12 @@ Layout::make_eh_frame_section(const Relobj* object)
+ if (os == NULL)
+ return NULL;
+
++ if (object != NULL && Layout::match_file_name(object, "crtbegin"))
++ {
++ gold_assert(!this->seen_crtbegin_);
++ this->seen_crtbegin_ = true;
++ }
++
+ if (this->eh_frame_section_ == NULL)
+ {
+ this->eh_frame_section_ = os;
+diff --git a/gold/layout.h b/gold/layout.h
+index 032f5f3..74e5ec1 100644
+--- a/gold/layout.h
++++ b/gold/layout.h
+@@ -1420,6 +1420,9 @@ class Layout
+ Incremental_inputs* incremental_inputs_;
+ // Whether we record output section data created in script
+ bool record_output_section_data_from_script_;
++ // Whether we have seen the crtbegin file when processing the exception
++ // frame sections.
++ bool seen_crtbegin_;
+ // List of output data that needs to be removed at relaxation clean up.
+ Output_section_data_list script_output_section_data_list_;
+ // Structure to save segment states before entering the relaxation loop.
+--
+1.9.3
+
diff --git a/patches/binutils-pr17729.patch b/patches/binutils-pr17729.patch
new file mode 100644
index 0000000..c4900b8
--- /dev/null
+++ b/patches/binutils-pr17729.patch
@@ -0,0 +1,592 @@
+From 9fc332659c821bf53e03fa0c086fc9c940cabda5 Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Thu, 18 Dec 2014 11:09:28 -0800
+Subject: [PATCH] Handle stack split for x32
+
+X32 uses cmp %fs:NN,%esp, lea NN(%rsp),%r10d, lea NN(%rsp),%r11d,
+instead of cmp %fs:NN,%rsp, lea NN(%rsp),%r10, lea NN(%rsp),%r11.
+This patch handles it.
+
+ PR gold/17729
+ * configure.ac (DEFAULT_TARGET_X86_64): Don't set for x32.
+ (DEFAULT_TARGET_X32): Set for x32.
+ * x86_64.cc (Target_x86_64<size>::do_calls_non_split): Handle
+ x32.
+ * testsuite/Makefile.am (check_SCRIPTS): Add split_x32.sh.
+ (check_DATA): Add split_x32 files.
+ (split_x32_[1234n].o): New targets.
+ (split_x32_[124]): New targets.
+ (split_x32_[1234r].stdout): New targets.
+ * testsuite/split_x32.sh: New file.
+ * testsuite/split_x32_1.s: Likewise.
+ * testsuite/split_x32_2.s: Likewise.
+ * testsuite/split_x32_3.s: Likewise.
+ * testsuite/split_x32_4.s: Likewise.
+ * testsuite/split_x32_n.s: Likewise.
+ * configure: Regenerated.
+ * testsuite/Makefile.in: Likewise.
+---
+ gold/ChangeLog | 21 +++++++++++++++++
+ gold/configure | 28 +++++++++++++++++++++-
+ gold/configure.ac | 15 +++++++++++-
+ gold/testsuite/Makefile.am | 37 +++++++++++++++++++++++++++++
+ gold/testsuite/Makefile.in | 55 ++++++++++++++++++++++++++++++++++++--------
+ gold/testsuite/split_x32.sh | 55 ++++++++++++++++++++++++++++++++++++++++++++
+ gold/testsuite/split_x32_1.s | 33 ++++++++++++++++++++++++++
+ gold/testsuite/split_x32_2.s | 33 ++++++++++++++++++++++++++
+ gold/testsuite/split_x32_3.s | 22 ++++++++++++++++++
+ gold/testsuite/split_x32_4.s | 23 ++++++++++++++++++
+ gold/testsuite/split_x32_n.s | 12 ++++++++++
+ gold/x86_64.cc | 40 +++++++++++++++++++++++++-------
+ 12 files changed, 355 insertions(+), 19 deletions(-)
+ create mode 100755 gold/testsuite/split_x32.sh
+ create mode 100644 gold/testsuite/split_x32_1.s
+ create mode 100644 gold/testsuite/split_x32_2.s
+ create mode 100644 gold/testsuite/split_x32_3.s
+ create mode 100644 gold/testsuite/split_x32_4.s
+ create mode 100644 gold/testsuite/split_x32_n.s
+diff --git a/gold/configure b/gold/configure
+index 7d7b849..23e4735 100755
+--- a/gold/configure
++++ b/gold/configure
+@@ -688,6 +688,8 @@ DEFAULT_TARGET_MIPS_FALSE
+ DEFAULT_TARGET_MIPS_TRUE
+ DEFAULT_TARGET_TILEGX_FALSE
+ DEFAULT_TARGET_TILEGX_TRUE
++DEFAULT_TARGET_X32_FALSE
++DEFAULT_TARGET_X32_TRUE
+ DEFAULT_TARGET_X86_64_FALSE
+ DEFAULT_TARGET_X86_64_TRUE
+ DEFAULT_TARGET_SPARC_FALSE
+@@ -3475,7 +3477,19 @@ else
+ DEFAULT_TARGET_SPARC_FALSE=
+ fi
+
+- if test "$targ_obj" = "x86_64"; then
++ target_x86_64=no
++ target_x32=no
++ if test "$targ_obj" = "x86_64"; then
++ case "$target" in
++ x86_64*-linux-gnux32)
++ target_x32=yes
++ ;;
++ *)
++ target_x86_64=yes
++ ;;
++ esac
++ fi
++ if test "$target_x86_64" = "yes"; then
+ DEFAULT_TARGET_X86_64_TRUE=
+ DEFAULT_TARGET_X86_64_FALSE='#'
+ else
+@@ -3483,6 +3497,14 @@ else
+ DEFAULT_TARGET_X86_64_FALSE=
+ fi
+
++ if test "$target_x32" = "yes"; then
++ DEFAULT_TARGET_X32_TRUE=
++ DEFAULT_TARGET_X32_FALSE='#'
++else
++ DEFAULT_TARGET_X32_TRUE='#'
++ DEFAULT_TARGET_X32_FALSE=
++fi
++
+ if test "$targ_obj" = "tilegx"; then
+ DEFAULT_TARGET_TILEGX_TRUE=
+ DEFAULT_TARGET_TILEGX_FALSE='#'
+@@ -7811,6 +7833,10 @@ if test -z "${DEFAULT_TARGET_X86_64_TRUE}" && test -z "${DEFAULT_TARGET_X86_64_F
+ as_fn_error "conditional \"DEFAULT_TARGET_X86_64\" was never defined.
+ Usually this means the macro was only invoked conditionally." "$LINENO" 5
+ fi
++if test -z "${DEFAULT_TARGET_X32_TRUE}" && test -z "${DEFAULT_TARGET_X32_FALSE}"; then
++ as_fn_error "conditional \"DEFAULT_TARGET_X32\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
+ if test -z "${DEFAULT_TARGET_TILEGX_TRUE}" && test -z "${DEFAULT_TARGET_TILEGX_FALSE}"; then
+ as_fn_error "conditional \"DEFAULT_TARGET_TILEGX\" was never defined.
+ Usually this means the macro was only invoked conditionally." "$LINENO" 5
+diff --git a/gold/configure.ac b/gold/configure.ac
+index 0478011..64e603a 100644
+--- a/gold/configure.ac
++++ b/gold/configure.ac
+@@ -204,7 +204,20 @@ for targ in $target $canon_targets; do
+ AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
+ AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
+ AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
+- AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
++ target_x86_64=no
++ target_x32=no
++ if test "$targ_obj" = "x86_64"; then
++ case "$target" in
++ x86_64*-linux-gnux32)
++ target_x32=yes
++ ;;
++ *)
++ target_x86_64=yes
++ ;;
++ esac
++ fi
++ AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$target_x86_64" = "yes")
++ AM_CONDITIONAL(DEFAULT_TARGET_X32, test "$target_x32" = "yes")
+ AM_CONDITIONAL(DEFAULT_TARGET_TILEGX, test "$targ_obj" = "tilegx")
+ AM_CONDITIONAL(DEFAULT_TARGET_MIPS, test "$targ_obj" = "mips")
+ DEFAULT_TARGET=${targ_obj}
+diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
+index 7604282..aca2a41 100644
+--- a/gold/testsuite/Makefile.am
++++ b/gold/testsuite/Makefile.am
+@@ -2484,6 +2484,43 @@ MOSTLYCLEANFILES += split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+
+ endif DEFAULT_TARGET_X86_64
+
++if DEFAULT_TARGET_X32
++
++check_SCRIPTS += split_x32.sh
++check_DATA += split_x32_1.stdout split_x32_2.stdout \
++ split_x32_3.stdout split_x32_4.stdout split_x32_r.stdout
++SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
++split_x32_1.o: split_x32_1.s
++ $(TEST_AS) -o $@ $<
++split_x32_2.o: split_x32_2.s
++ $(TEST_AS) -o $@ $<
++split_x32_3.o: split_x32_3.s
++ $(TEST_AS) -o $@ $<
++split_x32_4.o: split_x32_4.s
++ $(TEST_AS) -o $@ $<
++split_x32_n.o: split_x32_n.s
++ $(TEST_AS) -o $@ $<
++split_x32_1: split_x32_1.o split_x32_n.o ../ld-new
++ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_1.o split_x32_n.o
++split_x32_1.stdout: split_x32_1
++ $(TEST_OBJDUMP) -d $< > $@
++split_x32_2: split_x32_2.o split_x32_n.o ../ld-new
++ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_2.o split_x32_n.o
++split_x32_2.stdout: split_x32_2
++ $(TEST_OBJDUMP) -d $< > $@
++split_x32_3.stdout: split_x32_3.o split_x32_n.o ../ld-new
++ ../ld-new $(SPLIT_DEFSYMS) -o split_x32_3 split_x32_3.o split_x32_n.o > $@ 2>&1 || exit 0
++split_x32_4: split_x32_4.o split_x32_n.o ../ld-new
++ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_4.o split_x32_n.o
++split_x32_4.stdout: split_x32_4
++ $(TEST_OBJDUMP) -d $< > $@
++split_x32_r.stdout: split_x32_1.o split_x32_n.o ../ld-new
++ ../ld-new -r split_x32_1.o split_x32_n.o -o split_x32_r > $@ 2>&1 || exit 0
++MOSTLYCLEANFILES += split_x32_1 split_x32_2 split_x32_3 \
++ split_x32_4 split_x32_r
++
++endif DEFAULT_TARGET_X32
++
+ if DEFAULT_TARGET_ARM
+
+ check_SCRIPTS += arm_abs_global.sh
+diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
+index 1174399..d818570 100644
+--- a/gold/testsuite/Makefile.in
++++ b/gold/testsuite/Makefile.in
+@@ -623,6 +623,13 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_83 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x86_64_4 split_x86_64_r
+
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_84 = split_x32.sh
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_85 = split_x32_1.stdout split_x32_2.stdout \
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x32_3.stdout split_x32_4.stdout split_x32_r.stdout
++
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_86 = split_x32_1 split_x32_2 split_x32_3 \
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_x32_4 split_x32_r
++
+
+ # ARM1176 workaround test.
+
+@@ -635,7 +642,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ # Check Thumb to Thumb farcall veneers
+
+ # Check Thumb to ARM farcall veneers
+-@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_84 = arm_abs_global.sh \
++@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_87 = arm_abs_global.sh \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_in_range.sh \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_branch_out_of_range.sh \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_fix_v4bx.sh \
+@@ -649,7 +656,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_arm_thumb.sh \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb.sh \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.sh
+-@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_85 = arm_abs_global.stdout \
++@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_88 = arm_abs_global.stdout \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range.stdout \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range.stdout \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range.stdout \
+@@ -694,7 +701,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_6m.stdout \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm.stdout \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm_5t.stdout
+-@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_86 = arm_abs_global \
++@DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_89 = arm_abs_global \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_in_range \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_bl_out_of_range \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ thumb_bl_in_range \
+@@ -737,10 +744,10 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_thumb_6m \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm \
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ arm_farcall_thumb_arm_5t
+-@DEFAULT_TARGET_X86_64_TRUE@am__append_87 = *.dwo *.dwp
+-@DEFAULT_TARGET_X86_64_TRUE@am__append_88 = dwp_test_1.sh \
++@DEFAULT_TARGET_X86_64_TRUE@am__append_90 = *.dwo *.dwp
++@DEFAULT_TARGET_X86_64_TRUE@am__append_91 = dwp_test_1.sh \
+ @DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.sh
+-@DEFAULT_TARGET_X86_64_TRUE@am__append_89 = dwp_test_1.stdout \
++@DEFAULT_TARGET_X86_64_TRUE@am__append_92 = dwp_test_1.stdout \
+ @DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.stdout
+ subdir = testsuite
+ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+@@ -2223,7 +2230,8 @@ MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_4) \
+ $(am__append_41) $(am__append_47) $(am__append_63) \
+ $(am__append_66) $(am__append_69) $(am__append_72) \
+ $(am__append_74) $(am__append_77) $(am__append_80) \
+- $(am__append_83) $(am__append_86) $(am__append_87)
++ $(am__append_83) $(am__append_86) $(am__append_89) \
++ $(am__append_90)
+
+ # We will add to these later, for each individual test. Note
+ # that we add each test under check_SCRIPTS or check_PROGRAMS;
+@@ -2232,13 +2240,13 @@ check_SCRIPTS = $(am__append_2) $(am__append_34) $(am__append_38) \
+ $(am__append_42) $(am__append_45) $(am__append_61) \
+ $(am__append_64) $(am__append_67) $(am__append_70) \
+ $(am__append_75) $(am__append_78) $(am__append_81) \
+- $(am__append_84) $(am__append_88)
++ $(am__append_84) $(am__append_87) $(am__append_91)
+ check_DATA = $(am__append_3) $(am__append_27) $(am__append_29) \
+ $(am__append_35) $(am__append_39) $(am__append_43) \
+ $(am__append_46) $(am__append_62) $(am__append_65) \
+ $(am__append_68) $(am__append_71) $(am__append_76) \
+ $(am__append_79) $(am__append_82) $(am__append_85) \
+- $(am__append_89)
++ $(am__append_88) $(am__append_92)
+ BUILT_SOURCES = $(am__append_25)
+ TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
+
+@@ -2736,6 +2744,7 @@ LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
+ @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_x86_64_bnd_test_LDFLAGS = $(exception_test_LDFLAGS)
+ @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_x86_64_bnd_test_LDADD = exception_x86_64_bnd_1.o exception_x86_64_bnd_2.o
+ @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+ all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+@@ -4180,6 +4189,8 @@ split_i386.sh.log: split_i386.sh
+ @p='split_i386.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ split_x86_64.sh.log: split_x86_64.sh
+ @p='split_x86_64.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
++split_x32.sh.log: split_x32.sh
++ @p='split_x32.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ arm_abs_global.sh.log: arm_abs_global.sh
+ @p='arm_abs_global.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+ arm_branch_in_range.sh.log: arm_branch_in_range.sh
+@@ -5791,6 +5802,32 @@ uninstall-am:
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x86_64_r.stdout: split_x86_64_1.o split_x86_64_n.o ../ld-new
+ @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -r split_x86_64_1.o split_x86_64_n.o -o split_x86_64_r > $@ 2>&1 || exit 0
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_1.o: split_x32_1.s
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_2.o: split_x32_2.s
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_3.o: split_x32_3.s
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_4.o: split_x32_4.s
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_n.o: split_x32_n.s
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $<
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_1: split_x32_1.o split_x32_n.o ../ld-new
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_1.o split_x32_n.o
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_1.stdout: split_x32_1
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_2: split_x32_2.o split_x32_n.o ../ld-new
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_2.o split_x32_n.o
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_2.stdout: split_x32_2
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_3.stdout: split_x32_3.o split_x32_n.o ../ld-new
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o split_x32_3 split_x32_3.o split_x32_n.o > $@ 2>&1 || exit 0
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_4: split_x32_4.o split_x32_n.o ../ld-new
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_x32_4.o split_x32_n.o
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_4.stdout: split_x32_4
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_OBJDUMP) -d $< > $@
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_x32_r.stdout: split_x32_1.o split_x32_n.o ../ld-new
++@DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ ../ld-new -r split_x32_1.o split_x32_n.o -o split_x32_r > $@ 2>&1 || exit 0
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_abs_lib.o: arm_abs_lib.s
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -march=armv7-a -o $@ $<
+ @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@libarm_abs.so: arm_abs_lib.o ../ld-new
+diff --git a/gold/testsuite/split_x32.sh b/gold/testsuite/split_x32.sh
+new file mode 100755
+index 0000000..0bc0cf3
+--- /dev/null
++++ b/gold/testsuite/split_x32.sh
+@@ -0,0 +1,55 @@
++#!/bin/sh
++
++# split_x32.sh -- test -fstack-split for x32
++
++# Copyright (C) 2014 Free Software Foundation, Inc.
++# Written by Ian Lance Taylor <iant@google.com>.
++# Modified by H.J. Lu <hongjiu.lu@intel.com>.
++
++# This file is part of gold.
++
++# 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.
++
++match()
++{
++ if ! egrep "$1" "$2" >/dev/null 2>&1; then
++ echo 1>&2 "could not find '$1' in $2"
++ exit 1
++ fi
++}
++
++nomatch()
++{
++ if egrep "$1" "$2" >/dev/null 2>&1; then
++ echo 1>&2 "found unexpected '$1' in $2"
++ exit 1
++ fi
++}
++
++match 'cmp.*+%fs:[^,]*,%esp' split_x32_1.stdout
++match 'callq.*__morestack>?$' split_x32_1.stdout
++match 'lea.*-0x200\(%rsp\),' split_x32_1.stdout
++
++match 'stc' split_x32_2.stdout
++match 'callq.*__morestack_non_split>?$' split_x32_2.stdout
++nomatch 'callq.*__morestack>?$' split_x32_2.stdout
++match 'lea.*-0x4200\(%rsp\),' split_x32_2.stdout
++
++match 'failed to match' split_x32_3.stdout
++
++match 'callq.*__morestack>?$' split_x32_4.stdout
++
++match 'cannot mix' split_x32_r.stdout
+diff --git a/gold/testsuite/split_x32_1.s b/gold/testsuite/split_x32_1.s
+new file mode 100644
+index 0000000..b78936e
+--- /dev/null
++++ b/gold/testsuite/split_x32_1.s
+@@ -0,0 +1,33 @@
++# split_x32_1.s: x32 specific test case for -fsplit-stack.
++
++ .text
++
++ .global fn1
++ .type fn1,@function
++fn1:
++ cmp %fs:0x40,%esp
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn2
++ retq
++
++ .size fn1,. - fn1
++
++ .global fn2
++ .type fn2,@function
++fn2:
++ lea -0x200(%rsp),%r10d
++ cmp %fs:0x40,%r10d
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn1
++ retq
++
++ .size fn2,. - fn2
++
++ .section .note.GNU-stack,"",@progbits
++ .section .note.GNU-split-stack,"",@progbits
+diff --git a/gold/testsuite/split_x32_2.s b/gold/testsuite/split_x32_2.s
+new file mode 100644
+index 0000000..b789afd
+--- /dev/null
++++ b/gold/testsuite/split_x32_2.s
+@@ -0,0 +1,33 @@
++# split_x32_2.s: x32 specific, -fsplit-stack calling non-split
++
++ .text
++
++ .global fn1
++ .type fn1,@function
++fn1:
++ cmp %fs:0x40,%esp
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn3
++ retq
++
++ .size fn1,. - fn1
++
++ .global fn2
++ .type fn2,@function
++fn2:
++ lea -0x200(%rsp),%r10d
++ cmp %fs:0x40,%r10d
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn3
++ retq
++
++ .size fn2,. - fn2
++
++ .section .note.GNU-stack,"",@progbits
++ .section .note.GNU-split-stack,"",@progbits
+diff --git a/gold/testsuite/split_x32_3.s b/gold/testsuite/split_x32_3.s
+new file mode 100644
+index 0000000..d7b09bd
+--- /dev/null
++++ b/gold/testsuite/split_x32_3.s
+@@ -0,0 +1,22 @@
++# split_x32_3.s: x32 specific, adjustment failure
++
++ .text
++
++ .global fn1
++ .type fn1,@function
++fn1:
++ push %rbp
++ mov %esp,%ebp
++ cmp %fs:0x40,%esp
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn3
++ leaveq
++ retq
++
++ .size fn1,. - fn1
++
++ .section .note.GNU-stack,"",@progbits
++ .section .note.GNU-split-stack,"",@progbits
+diff --git a/gold/testsuite/split_x32_4.s b/gold/testsuite/split_x32_4.s
+new file mode 100644
+index 0000000..1f4eece
+--- /dev/null
++++ b/gold/testsuite/split_x32_4.s
+@@ -0,0 +1,23 @@
++# split_x32_4.s: x32 specific, permitted adjustment failure
++
++ .text
++
++ .global fn1
++ .type fn1,@function
++fn1:
++ push %rbp
++ mov %esp,%ebp
++ cmp %fs:0x40,%esp
++ jae 1f
++ callq __morestack
++ retq
++1:
++ callq fn3
++ leaveq
++ retq
++
++ .size fn1,. - fn1
++
++ .section .note.GNU-stack,"",@progbits
++ .section .note.GNU-split-stack,"",@progbits
++ .section .note.GNU-no-split-stack,"",@progbits
+diff --git a/gold/testsuite/split_x32_n.s b/gold/testsuite/split_x32_n.s
+new file mode 100644
+index 0000000..54c0db6
+--- /dev/null
++++ b/gold/testsuite/split_x32_n.s
+@@ -0,0 +1,12 @@
++# split_x32_n.s: x32 specific, -fsplit-stack calling non-split
++
++ .text
++
++ .global fn3
++ .type fn3,@function
++fn3:
++ retq
++
++ .size fn3,. - fn3
++
++ .section .note.GNU-stack,"",@progbits
+diff --git a/gold/x86_64.cc b/gold/x86_64.cc
+index 4baa2bf..c058ba6 100644
+--- a/gold/x86_64.cc
++++ b/gold/x86_64.cc
+@@ -4470,22 +4470,46 @@ Target_x86_64<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
+ // The function starts with a comparison of the stack pointer and a
+ // field in the TCB. This is followed by a jump.
+
+- // cmp %fs:NN,%rsp
+- if (this->match_view(view, view_size, fnoffset, "\x64\x48\x3b\x24\x25", 5)
+- && fnsize > 9)
++ const char *cmp_insn, *lea_r10_insn, *lea_r11_insn;
++ size_t cmp_insn_len, nop_insn_len;
++
++ if (size == 32)
++ {
++ // For X32
++ // cmp %fs:NN,%esp
++ cmp_insn = "\x64\x3b\x24\x25";
++ cmp_insn_len = 4;
++ // lea NN(%rsp),%r10d
++ // lea NN(%rsp),%r11d
++ lea_r10_insn = "\x44\x8d\x94\x24";
++ lea_r11_insn = "\x44\x8d\x9c\x24";
++ nop_insn_len = 7;
++ }
++ else
++ {
++ // cmp %fs:NN,%rsp
++ cmp_insn = "\x64\x48\x3b\x24\x25";
++ cmp_insn_len = 5;
++ // lea NN(%rsp),%r10
++ // lea NN(%rsp),%r11
++ lea_r10_insn = "\x4c\x8d\x94\x24";
++ lea_r11_insn = "\x4c\x8d\x9c\x24";
++ nop_insn_len = 8;
++ }
++
++ if (this->match_view(view, view_size, fnoffset, cmp_insn, cmp_insn_len)
++ && fnsize > (nop_insn_len + 1))
+ {
+ // We will call __morestack if the carry flag is set after this
+ // comparison. We turn the comparison into an stc instruction
+ // and some nops.
+ view[fnoffset] = '\xf9';
+- this->set_view_to_nop(view, view_size, fnoffset + 1, 8);
++ this->set_view_to_nop(view, view_size, fnoffset + 1, nop_insn_len);
+ }
+- // lea NN(%rsp),%r10
+- // lea NN(%rsp),%r11
+ else if ((this->match_view(view, view_size, fnoffset,
+- "\x4c\x8d\x94\x24", 4)
++ lea_r10_insn, 4)
+ || this->match_view(view, view_size, fnoffset,
+- "\x4c\x8d\x9c\x24", 4))
++ lea_r11_insn, 4))
+ && fnsize > 8)
+ {
+ // This is loading an offset from the stack pointer for a
+--
+1.9.3
+
diff --git a/patches/binutils-secondary.patch b/patches/binutils-secondary.patch
new file mode 100644
index 0000000..eeeb95e
--- /dev/null
+++ b/patches/binutils-secondary.patch
@@ -0,0 +1,2197 @@
+From c7beb33d82923479aab9638145e23b26f4c68e2d Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 4 Nov 2013 09:35:07 -0800
+Subject: [PATCH] Add STB_SECONDARY support to gas and ld
+
+STB_SECONDARY is similar to STB_WEAK. But a STB_SECONDARY definition
+can be overridden by STB_GLOBAL or STB_WEAK definition at link-time
+as well as run-time. Linker also search archive library and extract
+archive members to resolve defined and undefined STB_SECONDARY symbol.
+---
+ ChangeLog.secondary | 221 +++++++++++++++++++++++++++++++++++
+ bfd/archive.c | 1 +
+ bfd/bfd-in2.h | 4 +
+ bfd/elf.c | 10 +-
+ bfd/elf32-mips.c | 5 +-
+ bfd/elf64-ia64-vms.c | 4 +
+ bfd/elfcode.h | 3 +
+ bfd/elflink.c | 171 ++++++++++++++++++++-------
+ bfd/elfn32-mips.c | 5 +-
+ bfd/linker.c | 44 ++++++-
+ bfd/syms.c | 14 +++
+ binutils/nm.c | 1 +
+ binutils/readelf.c | 1 +
+ gas/config/obj-elf.c | 42 ++++++-
+ gas/doc/as.texinfo | 9 ++
+ gas/symbols.c | 39 +++++--
+ gas/symbols.h | 2 +
+ gas/testsuite/gas/elf/common3.d | 2 +
+ gas/testsuite/gas/elf/common3.l | 2 +
+ gas/testsuite/gas/elf/common3.s | 2 +
+ gas/testsuite/gas/elf/common4.d | 2 +
+ gas/testsuite/gas/elf/common4.l | 2 +
+ gas/testsuite/gas/elf/common4.s | 2 +
+ gas/testsuite/gas/elf/elf.exp | 5 +
+ gas/testsuite/gas/elf/secondary1.e | 4 +
+ gas/testsuite/gas/elf/secondary1.s | 33 ++++++
+ gas/testsuite/gas/elf/secondary2.e | 1 +
+ gas/testsuite/gas/elf/secondary2.s | 5 +
+ gas/testsuite/gas/elf/type.e | 2 +
+ gas/testsuite/gas/elf/type.s | 13 ++-
+ include/bfdlink.h | 6 +
+ include/elf/common.h | 1 +
+ ld/emultempl/elf32.em | 4 +
+ ld/ld.texinfo | 4 +
+ ld/ldmain.c | 1 +
+ ld/testsuite/ld-elf/library1.c | 11 ++
+ ld/testsuite/ld-elf/library1.out | 1 +
+ ld/testsuite/ld-elf/library2.c | 12 ++
+ ld/testsuite/ld-elf/library2.out | 1 +
+ ld/testsuite/ld-elf/library3.out | 1 +
+ ld/testsuite/ld-elf/library4.out | 1 +
+ ld/testsuite/ld-elf/library5a.c | 16 +++
+ ld/testsuite/ld-elf/library5b.c | 10 ++
+ ld/testsuite/ld-elf/library6a.c | 4 +
+ ld/testsuite/ld-elf/library6b.c | 7 ++
+ ld/testsuite/ld-elf/library6c.c | 9 ++
+ ld/testsuite/ld-elf/library7a.c | 1 +
+ ld/testsuite/ld-elf/library7b.c | 7 ++
+ ld/testsuite/ld-elf/library7c.c | 3 +
+ ld/testsuite/ld-elf/library8.map | 4 +
+ ld/testsuite/ld-elf/library8a.c | 10 ++
+ ld/testsuite/ld-elf/library8a.rd | 5 +
+ ld/testsuite/ld-elf/library8b.c | 4 +
+ ld/testsuite/ld-elf/library8b.rd | 5 +
+ ld/testsuite/ld-elf/library8c.c | 7 ++
+ ld/testsuite/ld-elf/library8c.rd | 5 +
+ ld/testsuite/ld-elf/secondary-foo.c | 7 ++
+ ld/testsuite/ld-elf/secondary-main.c | 8 ++
+ ld/testsuite/ld-elf/secondary.c | 9 ++
+ ld/testsuite/ld-elf/secondary.exp | 176 ++++++++++++++++++++++++++++
+ ld/testsuite/ld-elf/secondary.rd | 5 +
+ ld/testsuite/ld-elf/secondary1.out | 1 +
+ ld/testsuite/ld-elf/secondary1.rd | 5 +
+ ld/testsuite/ld-elf/secondary2.rd | 5 +
+ ld/testsuite/ld-elf/secondary3.rd | 5 +
+ ld/testsuite/ld-elf/secondary3a.s | 4 +
+ ld/testsuite/ld-elf/secondary3b.s | 20 ++++
+ ld/testsuite/ld-elf/secondary4.rd | 5 +
+ ld/testsuite/ld-elf/secondary4.s | 9 ++
+ ld/testsuite/ld-elf/secondary5.c | 10 ++
+ ld/testsuite/ld-elf/secondary5.out | 3 +
+ ld/testsuite/ld-elf/secondary6.c | 11 ++
+ ld/testsuite/ld-elf/secondary6.out | 1 +
+ ld/testsuite/ld-elf/secondary7.c | 13 +++
+ ld/testsuite/ld-elf/secondary7.out | 1 +
+ 75 files changed, 1026 insertions(+), 63 deletions(-)
+ create mode 100644 ChangeLog.secondary
+ create mode 100644 gas/testsuite/gas/elf/common3.d
+ create mode 100644 gas/testsuite/gas/elf/common3.l
+ create mode 100644 gas/testsuite/gas/elf/common3.s
+ create mode 100644 gas/testsuite/gas/elf/common4.d
+ create mode 100644 gas/testsuite/gas/elf/common4.l
+ create mode 100644 gas/testsuite/gas/elf/common4.s
+ create mode 100644 gas/testsuite/gas/elf/secondary1.e
+ create mode 100644 gas/testsuite/gas/elf/secondary1.s
+ create mode 100644 gas/testsuite/gas/elf/secondary2.e
+ create mode 100644 gas/testsuite/gas/elf/secondary2.s
+ create mode 100644 ld/testsuite/ld-elf/library1.c
+ create mode 100644 ld/testsuite/ld-elf/library1.out
+ create mode 100644 ld/testsuite/ld-elf/library2.c
+ create mode 100644 ld/testsuite/ld-elf/library2.out
+ create mode 100644 ld/testsuite/ld-elf/library3.out
+ create mode 100644 ld/testsuite/ld-elf/library4.out
+ create mode 100644 ld/testsuite/ld-elf/library5a.c
+ create mode 100644 ld/testsuite/ld-elf/library5b.c
+ create mode 100644 ld/testsuite/ld-elf/library6a.c
+ create mode 100644 ld/testsuite/ld-elf/library6b.c
+ create mode 100644 ld/testsuite/ld-elf/library6c.c
+ create mode 100644 ld/testsuite/ld-elf/library7a.c
+ create mode 100644 ld/testsuite/ld-elf/library7b.c
+ create mode 100644 ld/testsuite/ld-elf/library7c.c
+ create mode 100644 ld/testsuite/ld-elf/library8.map
+ create mode 100644 ld/testsuite/ld-elf/library8a.c
+ create mode 100644 ld/testsuite/ld-elf/library8a.rd
+ create mode 100644 ld/testsuite/ld-elf/library8b.c
+ create mode 100644 ld/testsuite/ld-elf/library8b.rd
+ create mode 100644 ld/testsuite/ld-elf/library8c.c
+ create mode 100644 ld/testsuite/ld-elf/library8c.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary-foo.c
+ create mode 100644 ld/testsuite/ld-elf/secondary-main.c
+ create mode 100644 ld/testsuite/ld-elf/secondary.c
+ create mode 100644 ld/testsuite/ld-elf/secondary.exp
+ create mode 100644 ld/testsuite/ld-elf/secondary.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary1.out
+ create mode 100644 ld/testsuite/ld-elf/secondary1.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary2.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary3.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary3a.s
+ create mode 100644 ld/testsuite/ld-elf/secondary3b.s
+ create mode 100644 ld/testsuite/ld-elf/secondary4.rd
+ create mode 100644 ld/testsuite/ld-elf/secondary4.s
+ create mode 100644 ld/testsuite/ld-elf/secondary5.c
+ create mode 100644 ld/testsuite/ld-elf/secondary5.out
+ create mode 100644 ld/testsuite/ld-elf/secondary6.c
+ create mode 100644 ld/testsuite/ld-elf/secondary6.out
+ create mode 100644 ld/testsuite/ld-elf/secondary7.c
+ create mode 100644 ld/testsuite/ld-elf/secondary7.out
+
+diff --git a/ChangeLog.secondary b/ChangeLog.secondary
+new file mode 100644
+index 0000000..f3bb59d
+--- /dev/null
++++ b/ChangeLog.secondary
+@@ -0,0 +1,221 @@
++bfd/
++
++2012-09-11 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf-bfd.h (_bfd_elf_merge_symbol): Add a boolean argument to
++ indicate if the old definition is secondary.
++
++ * elf32-sh-symbian.c (sh_symbian_relocate_section): Pass FALSE
++ to _bfd_elf_merge_symbol.
++
++ * elflink.c (_bfd_elf_merge_symbol): Add a boolean argument to
++ indicate if the old definition is secondary. Set OLDSECONADRY if
++ it isn't TRUE. Treat old secondary symbol as weak.
++ (_bfd_elf_add_default_symbol): Add a boolean argument to if the
++ old definition is secondary.
++ (elf_link_add_object_symbols): Pass oldsecondary to
++ _bfd_elf_merge_symbol and _bfd_elf_add_default_symbol.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (is_global_data_symbol_definition): Renamed to ...
++ (is_global_symbol_definition): This. If secondary symbols are
++ ignored, count function and common symbols as global definition.
++ (elf_link_is_defined_archive_symbol): Updated.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (is_global_data_symbol_definition): Add an argument
++ to ignore secondary symbols.
++ (elf_link_is_defined_archive_symbol): Likewise and pass it to
++ is_global_data_symbol_definition.
++ (elf_link_add_archive_symbols): Ignore another secondary
++ definition.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (elf_link_output_extsym): Generate STB_SECONDARY
++ symbols if needed.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf.c (swap_out_syms): Output undefined secondary symbols
++ as weak.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elflink.c (_bfd_elf_merge_symbol): Allow overriding secondary
++ symbols.
++ (elf_link_add_object_symbols): Treat secondary symbols as weak
++ symbols. Allow overriding secondary symbols.
++ (elf_link_add_archive_symbols): Keep searching if a definition
++ is secondary.
++ (elf_link_output_extsym): Treat secondary symbols as weak
++ symbols.
++ * linker.c (_bfd_generic_link_add_one_symbol): Treat secondary
++ symbol as weak symbol. Mark secondary symbol.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * archive.c (_bfd_compute_and_write_armap): Treat BSF_SECONDARY
++ symbol as global.
++ * elf32-mips.c (mips_elf_sym_is_global): Likewise.
++ * elfn32-mips.c (mips_elf_sym_is_global): Likewise.
++ * elf.c (sym_is_global): Likewise.
++ (swap_out_syms): Handle SECONDARY symbol.
++ * elf64-ia64-vms.c (elf64_vms_link_add_object_symbols): Likewise.
++ * elfcode.h (elf_slurp_symbol_table): Likewise.
++ * elflink.c (elf_link_add_object_symbols): Likewise.
++
++ * syms.c (BSF_SECONDARY): New.
++ (bfd_print_symbol_vandf): Handle SECONDARY symbol.
++ (bfd_decode_symclass): Likewise.
++
++ * bfd-in2.h: Regenerated.
++
++binutils/
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * nm.c (filter_symbols): Treat BSF_SECONDARY symbol as global.
++
++ * readelf.c (get_symbol_binding): Handle STB_SECONDARY.
++
++gas/
++
++2012-09-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ * config/obj-elf.c (obj_elf_weak): Don't set symbol weak on
++ secondary symbol.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * config/obj-elf.c (elf_frob_symbol): Handle secondary symbol
++ for .symver. Also remove the unused secondary symbol.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * symbols.c (S_IS_SECONDARY): New.
++ (S_SET_SECONDARY): Likewise.
++ (S_FORCE_RELOC): Handle BSF_SECONDARY like BSF_WEAK.
++ (S_SET_EXTERNAL): Likewise.
++ (S_CLEAR_EXTERNAL): Likewise.
++ (S_CLEAR_WEAKREFD): Likewise.
++ (S_SET_WEAK): Also clear BSF_SECONDARY.
++
++ * symbols.h (S_IS_SECONDARY): New.
++ (S_SET_SECONDARY): Likewise.
++
++ * config/obj-elf.c (obj_elf_secondary): New.
++ (elf_pseudo_table): Add "secondary".
++ (elf_frob_symbol): Also check secondary symbols.
++
++ * doc/as.texinfo: Document .secondary directive.
++
++gas/testsuite/
++
++2012-09-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ * gas/elf/common3.d: New file.
++ * gas/elf/common3.l: Likewise.
++ * gas/elf/common3.s: Likewise.
++ * gas/elf/common4.d: Likewise.
++ * gas/elf/common4.l: Likewise.
++ * gas/elf/common4.s: Likewise.
++ * gas/elf/secondary1.e: Likewise.
++ * gas/elf/secondary1.s: Likewise.
++ * gas/elf/secondary2.e: Likewise.
++ * gas/elf/secondary2.s: Likewise.
++
++ * gas/elf/elf.exp: Run common3, common4, secondary1 and
++ secondary2.
++
++ * gas/elf/type.s: Add .secondary tests.
++ * gas/elf/type.e: Updated.
++
++include/
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_info): Add emit_secondary.
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_hash_entry): Add secondary.
++
++include/elf/
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * common.h (STB_SECONDARY): New.
++
++ld/
++
++2012-09-08 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld.texinfo: Change "-z secondary" to "-z nosecondary".
++
++ * ldmain.c (main): Initialize link_info.emit_secondary to TRUE.
++
++ * emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Set
++ to link_info.emit_secondary to FALSE for "-z nosecondary".
++ (gld${EMULATION_NAME}_list_options): Replace "-z secondary" with
++ "-z nosecondary".
++
++2012-06-30 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld.texinfo: Document "-z secondary".
++
++ * emultempl/elf32.em (gld${EMULATION_NAME}_handle_option): Set
++ to link_info.emit_secondary to TRUE for "-z secondary".
++ (gld${EMULATION_NAME}_list_options): Add "-z secondary".
++
++ld/testsuite/
++
++2012-09-08 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld-elf/secondary.exp: Update -Wl,-z,secondary with
++ -Wl,-z,nosecondary.
++
++2012-09-06 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ld-elf/library1.c: New file.
++ * ld-elf/library1.out: Likewise.
++ * ld-elf/library2.c: Likewise.
++ * ld-elf/library2.out: Likewise.
++ * ld-elf/library3.out: Likewise.
++ * ld-elf/library4.out: Likewise.
++ * ld-elf/library5a.c: Likewise.
++ * ld-elf/library5b.c: Likewise.
++ * ld-elf/library6a.c: Likewise.
++ * ld-elf/library6b.c: Likewise.
++ * ld-elf/library6c.c: Likewise.
++ * ld-elf/library7a.c: Likewise.
++ * ld-elf/library7b.c: Likewise.
++ * ld-elf/library7c.c: Likewise.
++ * ld-elf/secondary-foo.c: Likewise.
++ * ld-elf/secondary-main.c: Likewise.
++ * ld-elf/secondary.c: Likewise.
++ * ld-elf/secondary.exp: Likewise.
++ * ld-elf/secondary.rd: Likewise.
++ * ld-elf/secondary1.out: Likewise.
++ * ld-elf/secondary1.rd: Likewise.
++ * ld-elf/secondary2.rd: Likewise.
++ * ld-elf/secondary3.rd: Likewise.
++ * ld-elf/secondary3a.s: Likewise.
++ * ld-elf/secondary3b.s: Likewise.
++ * ld-elf/secondary4.rd: Likewise.
++ * ld-elf/secondary4.s: Likewise.
++ * ld-elf/secondary5.c: Likewise.
++ * ld-elf/secondary5.out: Likewise.
++ * ld-elf/secondary6.c: Likewise.
++ * ld-elf/secondary6.out: Likewise.
++ * ld-elf/secondary7.c: Likewise.
++ * ld-elf/secondary7.out: Likewise.
++ * ld-elf/library8.map: Likewise.
++ * ld-elf/library8a.c: Likewise.
++ * ld-elf/library8a.rd: Likewise.
++ * ld-elf/library8b.c: Likewise.
++ * ld-elf/library8b.rd: Likewise.
++ * ld-elf/library8c.c: Likewise.
++ * ld-elf/library8c.rd: Likewise.
+diff --git a/bfd/archive.c b/bfd/archive.c
+index 40a3395..0d80fc5 100644
+--- a/bfd/archive.c
++++ b/bfd/archive.c
+@@ -2337,6 +2337,7 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
+
+ if (((flags & (BSF_GLOBAL
+ | BSF_WEAK
++ | BSF_SECONDARY
+ | BSF_INDIRECT
+ | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_com_section (sec))
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index 27fc3fe..fdc1138 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -6168,6 +6168,10 @@ typedef struct bfd_symbol
+ with this name and type in use. BSF_OBJECT must also be set. */
+ #define BSF_GNU_UNIQUE (1 << 23)
+
++ /* A secondary global symbol, overridable without warnings by
++ a regular or weak global symbol of the same name. */
++#define BSF_SECONDARY (1 << 24)
++
+ flagword flags;
+
+ /* A pointer to the section to which this symbol is
+diff --git a/bfd/elf.c b/bfd/elf.c
+index 9dc6b6d..97816f4 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -3259,7 +3259,10 @@ sym_is_global (bfd *abfd, asymbol *sym)
+ if (bed->elf_backend_sym_is_global)
+ return (*bed->elf_backend_sym_is_global) (abfd, sym);
+
+- return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
++ return ((sym->flags & (BSF_GLOBAL
++ | BSF_WEAK
++ | BSF_SECONDARY
++ | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_und_section (bfd_get_section (sym))
+ || bfd_is_com_section (bfd_get_section (sym)));
+ }
+@@ -6922,8 +6925,9 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
+ #endif
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+ }
++ /* Output undefined secondary symbols as weak. */
+ else if (bfd_is_und_section (syms[idx]->section))
+- sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
++ sym.st_info = ELF_ST_INFO (((flags & (BSF_WEAK | BSF_SECONDARY))
+ ? STB_WEAK
+ : STB_GLOBAL),
+ type);
+@@ -6937,6 +6941,8 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"),
+ bind = STB_LOCAL;
+ else if (flags & BSF_GNU_UNIQUE)
+ bind = STB_GNU_UNIQUE;
++ else if (flags & BSF_SECONDARY)
++ bind = STB_SECONDARY;
+ else if (flags & BSF_WEAK)
+ bind = STB_WEAK;
+ else if (flags & BSF_GLOBAL)
+diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
+index af405bc..e84efad 100644
+--- a/bfd/elf32-mips.c
++++ b/bfd/elf32-mips.c
+@@ -2154,7 +2154,10 @@ mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
+ if (SGI_COMPAT (abfd))
+ return (sym->flags & BSF_SECTION_SYM) == 0;
+ else
+- return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
++ return ((sym->flags & (BSF_GLOBAL
++ | BSF_WEAK
++ | BSF_SECONDARY
++ | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_und_section (bfd_get_section (sym))
+ || bfd_is_com_section (bfd_get_section (sym)));
+ }
+diff --git a/bfd/elf64-ia64-vms.c b/bfd/elf64-ia64-vms.c
+index dd86e3c..0ff1798 100644
+--- a/bfd/elf64-ia64-vms.c
++++ b/bfd/elf64-ia64-vms.c
+@@ -4926,6 +4926,10 @@ error_free_dyn:
+ flags = BSF_WEAK;
+ break;
+
++ case STB_SECONDARY:
++ flags = BSF_SECONDARY;
++ break;
++
+ case STB_GNU_UNIQUE:
+ flags = BSF_GNU_UNIQUE;
+ break;
+diff --git a/bfd/elfcode.h b/bfd/elfcode.h
+index a49a708..b09ab77 100644
+--- a/bfd/elfcode.h
++++ b/bfd/elfcode.h
+@@ -1281,6 +1281,9 @@ elf_slurp_symbol_table (bfd *abfd, asymbol **symptrs, bfd_boolean dynamic)
+ case STB_WEAK:
+ sym->symbol.flags |= BSF_WEAK;
+ break;
++ case STB_SECONDARY:
++ sym->symbol.flags |= BSF_SECONDARY;
++ break;
+ case STB_GNU_UNIQUE:
+ sym->symbol.flags |= BSF_GNU_UNIQUE;
+ break;
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+index c1e7948..984cee6 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -885,7 +885,8 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h,
+ overriding a new definition. We set TYPE_CHANGE_OK if it is OK for
+ the type to change. We set SIZE_CHANGE_OK if it is OK for the size
+ to change. By OK to change, we mean that we shouldn't warn if the
+- type or size does change. */
++ type or size does change. If OLDSECONARY is TRUE, the old definion
++ is a secondary symbol. */
+
+ static bfd_boolean
+ _bfd_elf_merge_symbol (bfd *abfd,
+@@ -895,6 +896,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ asection **psec,
+ bfd_vma *pvalue,
+ struct elf_link_hash_entry **sym_hash,
++ bfd_boolean oldsecondary,
+ bfd **poldbfd,
+ bfd_boolean *pold_weak,
+ unsigned int *pold_alignment,
+@@ -910,7 +912,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ int bind;
+ bfd *oldbfd;
+ bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon;
+- bfd_boolean newweak, oldweak, newfunc, oldfunc;
++ bfd_boolean newweak, oldweak, newfunc, oldfunc, weakbind;
+ const struct elf_backend_data *bed;
+
+ *skip = FALSE;
+@@ -968,9 +970,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ if (poldbfd && *poldbfd == NULL)
+ *poldbfd = oldbfd;
+
++ /* Set OLDSECONADRY if it isn't TRUE. */
++ if (!oldsecondary)
++ oldsecondary = h->root.secondary != 0;
++
++ /* Treat secondary symbols as weak symbols. */
++ weakbind = bind == STB_WEAK || bind == STB_SECONDARY;
++
+ /* Differentiate strong and weak symbols. */
+- newweak = bind == STB_WEAK;
+- oldweak = (h->root.type == bfd_link_hash_defweak
++ newweak = weakbind;
++ oldweak = (oldsecondary
++ || h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_undefweak);
+ if (pold_weak)
+ *pold_weak = oldweak;
+@@ -1001,7 +1011,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ {
+ if (bfd_is_und_section (sec))
+ {
+- if (bind != STB_WEAK)
++ if (!weakbind)
+ {
+ h->ref_dynamic_nonweak = 1;
+ hi->ref_dynamic_nonweak = 1;
+@@ -1250,7 +1260,7 @@ _bfd_elf_merge_symbol (bfd *abfd,
+
+ if (newdef && !newdyn && olddyn)
+ newweak = FALSE;
+- if (olddef && newdyn)
++ if (olddef && newdyn && !oldsecondary)
+ oldweak = FALSE;
+
+ /* Allow changes between different types of function symbol. */
+@@ -1365,10 +1375,14 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ represent variables; this can cause confusion in principle, but
+ any such confusion would seem to indicate an erroneous program or
+ shared library. We also permit a common symbol in a regular
+- object to override a weak symbol in a shared object. */
++ object to override a weak symbol in a shared object.
++
++ We let a definition in a dynamic object override the old secondary
++ symbol. */
+
+ if (newdyn
+ && newdef
++ && !oldsecondary
+ && (olddef
+ || (h->root.type == bfd_link_hash_common
+ && (newweak || newfunc))))
+@@ -1407,8 +1421,9 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ *size_change_ok = TRUE;
+ }
+
+- /* Skip weak definitions of symbols that are already defined. */
+- if (newdef && olddef && newweak)
++ /* Skip weak definitions of symbols that are already defined unless
++ the old definition is secondary. */
++ if (newdef && olddef && newweak && !oldsecondary)
+ {
+ /* Don't skip new non-IR weak syms. */
+ if (!(oldbfd != NULL
+@@ -1439,18 +1454,20 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ always take precedence over symbols from dynamic objects, even if
+ they are defined after the dynamic object in the link.
+
++ The new non-secondary definition overrides the old secondary
++ definition.
++
+ As above, we again permit a common symbol in a regular object to
+ override a definition in a shared object if the shared object
+ symbol is a function or is weak. */
+
+ flip = NULL;
+- if (!newdyn
++ if (((!newdyn && olddyn && h->def_dynamic) || oldsecondary)
++ && bind != STB_SECONDARY
+ && (newdef
+ || (bfd_is_com_section (sec)
+ && (oldweak || oldfunc)))
+- && olddyn
+- && olddef
+- && h->def_dynamic)
++ && olddef)
+ {
+ /* Change the hash table entry to undefined, and let
+ _bfd_generic_link_add_one_symbol do the right thing with the
+@@ -1553,8 +1570,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
+
+ /* This function is called to create an indirect symbol from the
+ default for the symbol with the default version if needed. The
+- symbol is described by H, NAME, SYM, SEC, and VALUE. We
+- set DYNSYM if the new indirect symbol is dynamic. */
++ symbol is described by H, NAME, SYM, SEC, VALUE, and OLDSECONDARY.
++ We set DYNSYM if the new indirect symbol is dynamic. */
+
+ static bfd_boolean
+ _bfd_elf_add_default_symbol (bfd *abfd,
+@@ -1564,6 +1581,7 @@ _bfd_elf_add_default_symbol (bfd *abfd,
+ Elf_Internal_Sym *sym,
+ asection *sec,
+ bfd_vma value,
++ bfd_boolean oldsecondary,
+ bfd **poldbfd,
+ bfd_boolean *dynsym)
+ {
+@@ -1608,8 +1626,9 @@ _bfd_elf_add_default_symbol (bfd *abfd,
+ size_change_ok = FALSE;
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+- &hi, poldbfd, NULL, NULL, &skip, &override,
+- &type_change_ok, &size_change_ok))
++ &hi, oldsecondary, poldbfd, NULL, NULL,
++ &skip, &override, &type_change_ok
++ , &size_change_ok))
+ return FALSE;
+
+ if (skip)
+@@ -1723,8 +1742,8 @@ nondefault:
+ size_change_ok = FALSE;
+ tmp_sec = sec;
+ if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &tmp_sec, &value,
+- &hi, poldbfd, NULL, NULL, &skip, &override,
+- &type_change_ok, &size_change_ok))
++ &hi, oldsecondary, poldbfd, NULL, NULL, &skip,
++ &override, &type_change_ok, &size_change_ok))
+ return FALSE;
+
+ if (skip)
+@@ -2868,31 +2887,41 @@ _bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ return tls;
+ }
+
+-/* Return TRUE iff this is a non-common, definition of a non-function symbol. */
++/* Return TRUE iff this is a non-common, definition of a
++ non-function symbol, unless IGNORE_SECONDARY is TRUE. */
++
+ static bfd_boolean
+-is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
+- Elf_Internal_Sym *sym)
++is_global_symbol_definition (bfd *abfd, Elf_Internal_Sym *sym,
++ bfd_boolean ignore_secondary)
+ {
+- const struct elf_backend_data *bed;
++ /* Ignore secondary symbols. */
++ if (ignore_secondary && ELF_ST_BIND (sym->st_info) == STB_SECONDARY)
++ return FALSE;
+
+ /* Local symbols do not count, but target specific ones might. */
+ if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL
+ && ELF_ST_BIND (sym->st_info) < STB_LOOS)
+ return FALSE;
+
+- bed = get_elf_backend_data (abfd);
+- /* Function symbols do not count. */
+- if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
+- return FALSE;
+-
+ /* If the section is undefined, then so is the symbol. */
+ if (sym->st_shndx == SHN_UNDEF)
+ return FALSE;
+
+- /* If the symbol is defined in the common section, then
+- it is a common definition and so does not count. */
+- if (bed->common_definition (sym))
+- return FALSE;
++ /* If secondary symbols are ignored, count function and common
++ symbols as global definition. */
++ if (!ignore_secondary)
++ {
++ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++
++ /* Function symbols do not count. */
++ if (bed->is_function_type (ELF_ST_TYPE (sym->st_info)))
++ return FALSE;
++
++ /* If the symbol is defined in the common section, then
++ it is a common definition and so does not count. */
++ if (bed->common_definition (sym))
++ return FALSE;
++ }
+
+ /* If the symbol is in a target specific section then we
+ must rely upon the backend to tell us what it is. */
+@@ -2911,9 +2940,12 @@ is_global_data_symbol_definition (bfd *abfd ATTRIBUTE_UNUSED,
+
+ /* Search the symbol table of the archive element of the archive ABFD
+ whose archive map contains a mention of SYMDEF, and determine if
+- the symbol is defined in this element. */
++ the symbol is defined in this element. Igore seconday defintion,
++ it IGNORE_SECONDARY is TRUE. */
++
+ static bfd_boolean
+-elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
++elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef,
++ bfd_boolean ignore_secondary)
+ {
+ Elf_Internal_Shdr * hdr;
+ bfd_size_type symcount;
+@@ -2974,7 +3006,8 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
+
+ if (strcmp (name, symdef->name) == 0)
+ {
+- result = is_global_data_symbol_definition (abfd, isym);
++ result = is_global_symbol_definition (abfd, isym,
++ ignore_secondary);
+ break;
+ }
+ }
+@@ -3822,6 +3855,7 @@ error_free_dyn:
+ bfd_boolean common;
+ unsigned int old_alignment;
+ bfd *old_bfd;
++ bfd_boolean oldsecondary;
+
+ override = FALSE;
+
+@@ -3849,6 +3883,10 @@ error_free_dyn:
+ flags = BSF_WEAK;
+ break;
+
++ case STB_SECONDARY:
++ flags = BSF_SECONDARY;
++ break;
++
+ case STB_GNU_UNIQUE:
+ flags = BSF_GNU_UNIQUE;
+ break;
+@@ -4084,7 +4122,7 @@ error_free_dyn:
+ | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+
+ if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec, &value,
+- sym_hash, &old_bfd, &old_weak,
++ sym_hash, FALSE, &old_bfd, &old_weak,
+ &old_alignment, &skip, &override,
+ &type_change_ok, &size_change_ok))
+ goto error_free_vers;
+@@ -4104,7 +4142,12 @@ error_free_dyn:
+ && vernum > 1
+ && definition)
+ h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1];
++
++ /* Remember if the old definition is secondary. */
++ oldsecondary = h->root.secondary != 0;
+ }
++ else
++ oldsecondary = FALSE;
+
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect,
+@@ -4184,10 +4227,14 @@ error_free_dyn:
+ if (! definition)
+ {
+ h->ref_regular = 1;
+- if (bind != STB_WEAK)
++ /* Treat secondary symbols as weak symbols. */
++ if (bind != STB_WEAK && bind != STB_SECONDARY)
+ h->ref_regular_nonweak = 1;
+ }
+- else
++ /* Mark it defined in a regular object if it is a
++ non-secondary definition or it hasn't been defined
++ in a dynamic object. */
++ else if (!h->def_dynamic || bind != STB_SECONDARY)
+ {
+ h->def_regular = 1;
+ if (h->def_dynamic)
+@@ -4216,6 +4263,13 @@ error_free_dyn:
+ {
+ h->def_dynamic = 1;
+ hi->def_dynamic = 1;
++ /* Dynamic definition overrides regular old secondary
++ definition. */
++ if (oldsecondary)
++ {
++ h->def_regular = 0;
++ hi->def_regular = 0;
++ }
+ }
+
+ /* If the indirect symbol has been forced local, don't
+@@ -4234,7 +4288,8 @@ error_free_dyn:
+ if (definition
+ || (!override && h->root.type == bfd_link_hash_common))
+ if (!_bfd_elf_add_default_symbol (abfd, info, h, name, isym,
+- sec, value, &old_bfd, &dynsym))
++ sec, value, oldsecondary,
++ &old_bfd, &dynsym))
+ goto error_free_vers;
+
+ /* Check the alignment when a common symbol is involved. This
+@@ -5024,16 +5079,27 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
+ map alone. Instead we must read in the element's symbol
+ table and check that to see what kind of symbol definition
+ this is. */
+- if (! elf_link_is_defined_archive_symbol (abfd, symdef))
++ if (! elf_link_is_defined_archive_symbol (abfd, symdef,
++ FALSE))
+ continue;
+ }
+- else if (h->root.type != bfd_link_hash_undefined)
++ /* Keep searching if a definition is secondary. */
++ else if (h->root.type != bfd_link_hash_undefined
++ && !h->root.secondary)
+ {
+ if (h->root.type != bfd_link_hash_undefweak)
+ /* Symbol must be defined. Don't check it again. */
+ included[i] = TRUE;
+ continue;
+ }
++ else if (h->root.secondary
++ && h->root.type == bfd_link_hash_defweak)
++ {
++ /* Ignore another secondary definition. */
++ if (! elf_link_is_defined_archive_symbol (abfd, symdef,
++ TRUE))
++ continue;
++ }
+
+ /* We need to include this archive member. */
+ element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset);
+@@ -8807,7 +8873,21 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
+ sym.st_info = ELF_ST_INFO (STB_GNU_UNIQUE, h->type);
+ else if (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_defweak)
+- sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
++ {
++ /* Generate defined secondary symbols for "ld -shared -z secondary"
++ and "ld -r". For undefined secondary symbols, we convert them
++ to weak symbols. We also convert defined secondary symbols in
++ executables to weak symbols since their bindings in executables
++ are final and can't be changed. */
++ if ((flinfo->info->relocatable
++ || (!flinfo->info->executable
++ && flinfo->info->emit_secondary))
++ && h->root.type == bfd_link_hash_defweak
++ && h->root.secondary)
++ sym.st_info = ELF_ST_INFO (STB_SECONDARY, h->type);
++ else
++ sym.st_info = ELF_ST_INFO (STB_WEAK, h->type);
++ }
+ else
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type);
+ sym.st_target_internal = h->target_internal;
+@@ -8938,7 +9018,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
+ if (sym.st_shndx == SHN_UNDEF
+ && h->ref_regular
+ && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL
+- || ELF_ST_BIND (sym.st_info) == STB_WEAK))
++ || ELF_ST_BIND (sym.st_info) == STB_WEAK
++ || ELF_ST_BIND (sym.st_info) == STB_SECONDARY))
+ {
+ int bindtype;
+ unsigned int type = ELF_ST_TYPE (sym.st_info);
+@@ -8964,10 +9045,12 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
+ sym.st_size = 0;
+
+ /* If a non-weak symbol with non-default visibility is not defined
+- locally, it is a fatal error. */
++ locally, it is a fatal error. Treat secondary symbols as weak
++ symbols. */
+ if (!flinfo->info->relocatable
+ && ELF_ST_VISIBILITY (sym.st_other) != STV_DEFAULT
+ && ELF_ST_BIND (sym.st_info) != STB_WEAK
++ && ELF_ST_BIND (sym.st_info) != STB_SECONDARY
+ && h->root.type == bfd_link_hash_undefined
+ && !h->def_regular)
+ {
+diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
+index 1286cc1..b5c5fa2 100644
+--- a/bfd/elfn32-mips.c
++++ b/bfd/elfn32-mips.c
+@@ -3262,7 +3262,10 @@ mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
+ if (SGI_COMPAT (abfd))
+ return (sym->flags & BSF_SECTION_SYM) == 0;
+ else
+- return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0
++ return ((sym->flags & (BSF_GLOBAL
++ | BSF_WEAK
++ | BSF_SECONDARY
++ | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_und_section (bfd_get_section (sym))
+ || bfd_is_com_section (bfd_get_section (sym)));
+ }
+diff --git a/bfd/linker.c b/bfd/linker.c
+index abdf5b0..9cb5cc4 100644
+--- a/bfd/linker.c
++++ b/bfd/linker.c
+@@ -1444,6 +1444,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h;
+ struct bfd_link_hash_entry *inh = NULL;
+ bfd_boolean cycle;
++ unsigned int secondary;
+
+ BFD_ASSERT (section != NULL);
+
+@@ -1508,15 +1509,53 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ return FALSE;
+ }
+
++ /* Since secondary symbols have lower precedence than weak symbols,
++ we treat them as weak symbols here. */
++ secondary = (flags & BSF_SECONDARY) != 0;
++ if (secondary)
++ switch (row)
++ {
++ default:
++ break;
++
++ case UNDEF_ROW:
++ row = UNDEFW_ROW;
++ break;
++
++ case DEF_ROW:
++ row = DEFW_ROW;
++ break;
++ }
++
+ if (hashp != NULL)
+ *hashp = h;
+
+ do
+ {
+ enum link_action action;
++ enum bfd_link_hash_type type;
++
++ type = h->type;
++ /* Convert a secondary symbol to a weak symbol. Backend is
++ responsible to let a weak symbol override a secondary
++ symbol. */
++ if (h->secondary)
++ switch (type)
++ {
++ default:
++ break;
++
++ case bfd_link_hash_undefined:
++ type = bfd_link_hash_undefweak;
++ break;
++
++ case bfd_link_hash_defined:
++ type = bfd_link_hash_defweak;
++ break;
++ }
+
+ cycle = FALSE;
+- action = link_action[(int) row][(int) h->type];
++ action = link_action[(int) row][(int) type];
+ switch (action)
+ {
+ case FAIL:
+@@ -1561,6 +1600,9 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
+ h->u.def.section = section;
+ h->u.def.value = value;
+
++ /* Mark if this is a secondary symbol. */
++ h->secondary = secondary;
++
+ /* If we have been asked to, we act like collect2 and
+ identify all functions that might be global
+ constructors and destructors and pass them up in a
+diff --git a/bfd/syms.c b/bfd/syms.c
+index a1d1d77..6077121 100644
+--- a/bfd/syms.c
++++ b/bfd/syms.c
+@@ -306,6 +306,10 @@ CODE_FRAGMENT
+ . with this name and type in use. BSF_OBJECT must also be set. *}
+ .#define BSF_GNU_UNIQUE (1 << 23)
+ .
++. {* A secondary global symbol, overridable without warnings by
++. a regular or weak global symbol of the same name. *}
++.#define BSF_SECONDARY (1 << 24)
++.
+ . flagword flags;
+ .
+ . {* A pointer to the section to which this symbol is
+@@ -489,6 +493,7 @@ bfd_print_symbol_vandf (bfd *abfd, void *arg, asymbol *symbol)
+ ((type & BSF_LOCAL)
+ ? (type & BSF_GLOBAL) ? '!' : 'l'
+ : (type & BSF_GLOBAL) ? 'g'
++ : (type & BSF_SECONDARY) ? 's'
+ : (type & BSF_GNU_UNIQUE) ? 'u' : ' '),
+ (type & BSF_WEAK) ? 'w' : ' ',
+ (type & BSF_CONSTRUCTOR) ? 'C' : ' ',
+@@ -692,6 +697,15 @@ bfd_decode_symclass (asymbol *symbol)
+ }
+ if (symbol->flags & BSF_GNU_UNIQUE)
+ return 'u';
++ if (symbol->flags & BSF_SECONDARY)
++ {
++ /* If secondary, determine if it's specifically an object
++ or non-object weak. */
++ if (symbol->flags & BSF_OBJECT)
++ return 'Y';
++ else
++ return 'S';
++ }
+ if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL)))
+ return '?';
+
+diff --git a/binutils/nm.c b/binutils/nm.c
+index ecd147e..300fd13 100644
+--- a/binutils/nm.c
++++ b/binutils/nm.c
+@@ -444,6 +444,7 @@ filter_symbols (bfd *abfd, bfd_boolean is_dynamic, void *minisyms,
+ /* PR binutls/12753: Unique symbols are global too. */
+ keep = ((sym->flags & (BSF_GLOBAL
+ | BSF_WEAK
++ | BSF_SECONDARY
+ | BSF_GNU_UNIQUE)) != 0
+ || bfd_is_und_section (sym->section)
+ || bfd_is_com_section (sym->section));
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index 7463c55..6596a21 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -9262,6 +9262,7 @@ get_symbol_binding (unsigned int binding)
+ case STB_LOCAL: return "LOCAL";
+ case STB_GLOBAL: return "GLOBAL";
+ case STB_WEAK: return "WEAK";
++ case STB_SECONDARY: return "SECOND";
+ default:
+ if (binding >= STB_LOPROC && binding <= STB_HIPROC)
+ snprintf (buff, sizeof (buff), _("<processor specific>: %d"),
+diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
+index e2ef99e..ab61461 100644
+--- a/gas/config/obj-elf.c
++++ b/gas/config/obj-elf.c
+@@ -68,6 +68,7 @@ static void obj_elf_line (int);
+ static void obj_elf_size (int);
+ static void obj_elf_type (int);
+ static void obj_elf_ident (int);
++static void obj_elf_secondary (int);
+ static void obj_elf_weak (int);
+ static void obj_elf_local (int);
+ static void obj_elf_visibility (int);
+@@ -97,6 +98,7 @@ static const pseudo_typeS elf_pseudo_table[] =
+ {"type", obj_elf_type, 0},
+ {"version", obj_elf_version, 0},
+ {"weak", obj_elf_weak, 0},
++ {"secondary", obj_elf_secondary, 0},
+
+ /* These define symbol visibility. */
+ {"internal", obj_elf_visibility, STV_INTERNAL},
+@@ -443,6 +445,29 @@ obj_elf_local (int ignore ATTRIBUTE_UNUSED)
+ }
+
+ static void
++obj_elf_secondary (int ignore ATTRIBUTE_UNUSED)
++{
++ int c;
++ symbolS *symbolP;
++
++ do
++ {
++ symbolP = get_sym_from_input_line_and_check ();
++ c = *input_line_pointer;
++ S_SET_SECONDARY (symbolP);
++ if (c == ',')
++ {
++ input_line_pointer++;
++ SKIP_WHITESPACE ();
++ if (*input_line_pointer == '\n')
++ c = '\n';
++ }
++ }
++ while (c == ',');
++ demand_empty_rest_of_line ();
++}
++
++static void
+ obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
+ {
+ int c;
+@@ -452,7 +477,8 @@ obj_elf_weak (int ignore ATTRIBUTE_UNUSED)
+ {
+ symbolP = get_sym_from_input_line_and_check ();
+ c = *input_line_pointer;
+- S_SET_WEAK (symbolP);
++ if (!S_IS_SECONDARY (symbolP))
++ S_SET_WEAK (symbolP);
+ if (c == ',')
+ {
+ input_line_pointer++;
+@@ -2194,18 +2220,24 @@ elf_frob_symbol (symbolS *symp, int *puntp)
+ if (S_IS_WEAK (symp))
+ S_SET_WEAK (symp2);
+
++ if (S_IS_SECONDARY (symp))
++ S_SET_SECONDARY (symp2);
++
+ if (S_IS_EXTERNAL (symp))
+ S_SET_EXTERNAL (symp2);
+ }
+ }
+ }
+
+- /* Double check weak symbols. */
+- if (S_IS_WEAK (symp))
++ /* Double check weak and secondary symbols. */
++ if (S_IS_COMMON (symp))
+ {
+- if (S_IS_COMMON (symp))
++ if (S_IS_WEAK (symp))
+ as_bad (_("symbol `%s' can not be both weak and common"),
+ S_GET_NAME (symp));
++ else if (S_IS_SECONDARY (symp))
++ as_bad (_("symbol `%s' can not be both secondary and common"),
++ S_GET_NAME (symp));
+ }
+
+ #ifdef TC_MIPS
+@@ -2419,7 +2451,7 @@ elf_frob_file_before_adjust (void)
+ /* If there was .weak foo, but foo was neither defined nor
+ used anywhere, remove it. */
+
+- else if (S_IS_WEAK (symp)
++ else if ((S_IS_WEAK (symp) || S_IS_SECONDARY (symp))
+ && symbol_used_p (symp) == 0
+ && symbol_used_in_reloc_p (symp) == 0)
+ symbol_remove (symp, &symbol_rootP, &symbol_lastP);
+diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
+index 251b6d5..0cf993d 100644
+--- a/gas/doc/as.texinfo
++++ b/gas/doc/as.texinfo
+@@ -4270,6 +4270,7 @@ Some machine configurations provide additional directives.
+ * Print:: @code{.print @var{string}}
+ @ifset ELF
+ * Protected:: @code{.protected @var{names}}
++* Secondary:: @code{.secondary @var{names}}
+ @end ifset
+
+ * Psize:: @code{.psize @var{lines}, @var{columns}}
+@@ -5952,6 +5953,14 @@ their binding: local, global or weak). The directive sets the visibility to
+ components that defines them must be resolved to the definition in that
+ component, even if a definition in another component would normally preempt
+ this.
++
++@node Secondary
++@section @code{.secondary @var{names}}
++
++@cindex @code{secondary} directive
++This directive sets the secondary attribute on the comma separated list
++of symbol @code{names}. If the symbols do not already exist, they will
++be created.
+ @end ifset
+
+ @node Psize
+diff --git a/gas/symbols.c b/gas/symbols.c
+index 6af8604..87f22d6 100644
+--- a/gas/symbols.c
++++ b/gas/symbols.c
+@@ -2033,6 +2033,14 @@ S_IS_WEAK (symbolS *s)
+ }
+
+ int
++S_IS_SECONDARY (symbolS *s)
++{
++ if (LOCAL_SYMBOL_CHECK (s))
++ return 0;
++ return (s->bsym->flags & BSF_SECONDARY) != 0;
++}
++
++int
+ S_IS_WEAKREFR (symbolS *s)
+ {
+ if (LOCAL_SYMBOL_CHECK (s))
+@@ -2079,7 +2087,7 @@ S_FORCE_RELOC (symbolS *s, int strict)
+ return ((struct local_symbol *) s)->lsy_section == undefined_section;
+
+ return ((strict
+- && ((s->bsym->flags & BSF_WEAK) != 0
++ && ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0
+ || (EXTERN_FORCE_RELOC
+ && (s->bsym->flags & BSF_GLOBAL) != 0)))
+ || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0
+@@ -2215,9 +2223,9 @@ S_SET_EXTERNAL (symbolS *s)
+ {
+ if (LOCAL_SYMBOL_CHECK (s))
+ s = local_symbol_convert ((struct local_symbol *) s);
+- if ((s->bsym->flags & BSF_WEAK) != 0)
++ if ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0)
+ {
+- /* Let .weak override .global. */
++ /* Let .weak/.secondary override .global. */
+ return;
+ }
+ if (s->bsym->flags & BSF_SECTION_SYM)
+@@ -2240,7 +2248,7 @@ S_SET_EXTERNAL (symbolS *s)
+ }
+ #endif
+ s->bsym->flags |= BSF_GLOBAL;
+- s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK);
++ s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK | BSF_SECONDARY);
+
+ #ifdef TE_PE
+ if (! an_external_name && S_GET_NAME(s)[0] != '.')
+@@ -2253,13 +2261,13 @@ S_CLEAR_EXTERNAL (symbolS *s)
+ {
+ if (LOCAL_SYMBOL_CHECK (s))
+ return;
+- if ((s->bsym->flags & BSF_WEAK) != 0)
++ if ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0)
+ {
+- /* Let .weak override. */
++ /* Let .weak/.secondary override. */
+ return;
+ }
+ s->bsym->flags |= BSF_LOCAL;
+- s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
++ s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK | BSF_SECONDARY);
+ }
+
+ void
+@@ -2271,7 +2279,16 @@ S_SET_WEAK (symbolS *s)
+ obj_set_weak_hook (s);
+ #endif
+ s->bsym->flags |= BSF_WEAK;
+- s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL);
++ s->bsym->flags &= ~(BSF_GLOBAL | BSF_SECONDARY | BSF_LOCAL);
++}
++
++void
++S_SET_SECONDARY (symbolS *s)
++{
++ if (LOCAL_SYMBOL_CHECK (s))
++ s = local_symbol_convert ((struct local_symbol *) s);
++ s->bsym->flags |= BSF_SECONDARY;
++ s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK | BSF_LOCAL);
+ }
+
+ void
+@@ -2328,6 +2345,12 @@ S_CLEAR_WEAKREFD (symbolS *s)
+ s->bsym->flags &= ~BSF_WEAK;
+ s->bsym->flags |= BSF_LOCAL;
+ }
++ /* The same applies to secondary symbol. */
++ else if (s->bsym->flags & BSF_SECONDARY)
++ {
++ s->bsym->flags &= ~BSF_SECONDARY;
++ s->bsym->flags |= BSF_LOCAL;
++ }
+ }
+ }
+
+diff --git a/gas/symbols.h b/gas/symbols.h
+index 4c83033..f765aec 100644
+--- a/gas/symbols.h
++++ b/gas/symbols.h
+@@ -91,6 +91,7 @@ extern void S_SET_VALUE (symbolS *, valueT);
+ extern int S_IS_FUNCTION (symbolS *);
+ extern int S_IS_EXTERNAL (symbolS *);
+ extern int S_IS_WEAK (symbolS *);
++extern int S_IS_SECONDARY (symbolS *);
+ extern int S_IS_WEAKREFR (symbolS *);
+ extern int S_IS_WEAKREFD (symbolS *);
+ extern int S_IS_COMMON (symbolS *);
+@@ -109,6 +110,7 @@ extern void S_SET_EXTERNAL (symbolS *);
+ extern void S_SET_NAME (symbolS *, const char *);
+ extern void S_CLEAR_EXTERNAL (symbolS *);
+ extern void S_SET_WEAK (symbolS *);
++extern void S_SET_SECONDARY (symbolS *);
+ extern void S_SET_WEAKREFR (symbolS *);
+ extern void S_CLEAR_WEAKREFR (symbolS *);
+ extern void S_SET_WEAKREFD (symbolS *);
+diff --git a/gas/testsuite/gas/elf/common3.d b/gas/testsuite/gas/elf/common3.d
+new file mode 100644
+index 0000000..e73f6c5
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common3.d
+@@ -0,0 +1,2 @@
++#name: secondary and common directives
++#error-output: common3.l
+diff --git a/gas/testsuite/gas/elf/common3.l b/gas/testsuite/gas/elf/common3.l
+new file mode 100644
+index 0000000..58d5142
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common3.l
+@@ -0,0 +1,2 @@
++[^:]*: Assembler messages:
++[^:]*: Error: symbol `foobar' can not be both secondary and common
+diff --git a/gas/testsuite/gas/elf/common3.s b/gas/testsuite/gas/elf/common3.s
+new file mode 100644
+index 0000000..df8b7ed
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common3.s
+@@ -0,0 +1,2 @@
++ .secondary foobar
++ .comm foobar,30
+diff --git a/gas/testsuite/gas/elf/common4.d b/gas/testsuite/gas/elf/common4.d
+new file mode 100644
+index 0000000..aca59c0
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common4.d
+@@ -0,0 +1,2 @@
++#name: common and secondary directives
++#error-output: common4.l
+diff --git a/gas/testsuite/gas/elf/common4.l b/gas/testsuite/gas/elf/common4.l
+new file mode 100644
+index 0000000..58d5142
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common4.l
+@@ -0,0 +1,2 @@
++[^:]*: Assembler messages:
++[^:]*: Error: symbol `foobar' can not be both secondary and common
+diff --git a/gas/testsuite/gas/elf/common4.s b/gas/testsuite/gas/elf/common4.s
+new file mode 100644
+index 0000000..37bd0ce
+--- /dev/null
++++ b/gas/testsuite/gas/elf/common4.s
+@@ -0,0 +1,2 @@
++ .comm foobar,30
++ .secondary foobar
+diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
+index f17f7e0..65bb3c5 100644
+--- a/gas/testsuite/gas/elf/elf.exp
++++ b/gas/testsuite/gas/elf/elf.exp
+@@ -203,6 +203,11 @@ if { [is_elf_format] } then {
+
+ run_dump_test "common1"
+ run_dump_test "common2"
++ run_dump_test "common3"
++ run_dump_test "common4"
++
++ run_elf_list_test "secondary1" "" "" "-s" "| grep \"secondary_\""
++ run_elf_list_test "secondary2" "" "" "-s" "| grep \"secondary_\""
+
+ load_lib gas-dg.exp
+ dg-init
+diff --git a/gas/testsuite/gas/elf/secondary1.e b/gas/testsuite/gas/elf/secondary1.e
+new file mode 100644
+index 0000000..da00dfb
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary1.e
+@@ -0,0 +1,4 @@
++ +.: 0+0 +1 +FUNC +SECOND +DEFAULT +. secondary_function1
++ +.: 0+1 +1 +FUNC +SECOND +DEFAULT +. secondary_function2
++ +.: 0+0 +1 +OBJECT +SECOND +DEFAULT +. secondary_object1
++ +.: 0+1 +1 +OBJECT +SECOND +DEFAULT +. secondary_object2
+diff --git a/gas/testsuite/gas/elf/secondary1.s b/gas/testsuite/gas/elf/secondary1.s
+new file mode 100644
+index 0000000..6a3032d
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary1.s
+@@ -0,0 +1,33 @@
++ .text
++
++ .size secondary_function1,1
++ .secondary secondary_function1
++ .weak secondary_function1
++ .type secondary_function1,%function
++secondary_function1:
++ .byte 0x0
++ .size secondary_function1,1
++
++ .size secondary_function2,1
++ .weak secondary_function2
++ .secondary secondary_function2
++ .type secondary_function2,%function
++secondary_function2:
++ .byte 0x0
++ .size secondary_function2,1
++
++
++ .data
++ .type secondary_object1,%object
++ .weak secondary_object1
++ .secondary secondary_object1
++secondary_object1:
++ .byte 0x0
++ .size secondary_object1,1
++
++ .type secondary_object2,%object
++ .weak secondary_object2
++ .secondary secondary_object2
++secondary_object2:
++ .byte 0x0
++ .size secondary_object2,1
+diff --git a/gas/testsuite/gas/elf/secondary2.e b/gas/testsuite/gas/elf/secondary2.e
+new file mode 100644
+index 0000000..0470eb8
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary2.e
+@@ -0,0 +1 @@
++ +.: 0+ +0 +[A-Z]+ +WEAK +DEFAULT +UND secondary_function
+diff --git a/gas/testsuite/gas/elf/secondary2.s b/gas/testsuite/gas/elf/secondary2.s
+new file mode 100644
+index 0000000..234330a
+--- /dev/null
++++ b/gas/testsuite/gas/elf/secondary2.s
+@@ -0,0 +1,5 @@
++ .text
++ .secondary secondary_function
++ .dc.a secondary_function
++ .data
++ .secondary secondary_object
+diff --git a/gas/testsuite/gas/elf/type.e b/gas/testsuite/gas/elf/type.e
+index a1159bf..d4c0548 100644
+--- a/gas/testsuite/gas/elf/type.e
++++ b/gas/testsuite/gas/elf/type.e
+@@ -3,5 +3,7 @@
+ +.+: 0+0 +1 +OBJECT +LOCAL +DEFAULT +. object
+ +.+: 0+1 +1 +TLS +LOCAL +DEFAULT +. tls_object
+ +.+: 0+2 +1 +NOTYPE +LOCAL +DEFAULT +. notype
++ +.+: 0+2 +1 +FUNC +SECOND +DEFAULT +. secondary_function
+ +.+: 0+3 +1 +OBJECT +UNIQUE +DEFAULT +. unique_global
++ +.+: 0+4 +1 +OBJECT +SECOND +DEFAULT +. secondary_object
+ +.+: 0+1 +1 +(COMMON|OBJECT) +GLOBAL +DEFAULT +COM common
+diff --git a/gas/testsuite/gas/elf/type.s b/gas/testsuite/gas/elf/type.s
+index d0a1afd..bd7df2c 100644
+--- a/gas/testsuite/gas/elf/type.s
++++ b/gas/testsuite/gas/elf/type.s
+@@ -10,6 +10,12 @@ function:
+ indirect_function:
+ .byte 0x0
+
++ .size secondary_function,1
++ .secondary secondary_function
++ .type secondary_function,%function
++secondary_function:
++ .byte 0x0
++
+ .data
+
+ .type object,%object
+@@ -32,6 +38,11 @@ unique_global:
+ .byte 0x0
+ .size unique_global,1
+
++ .type secondary_object,%object
++ .secondary secondary_object
++secondary_object:
++ .byte 0x0
++ .size secondary_object,1
++
+ .comm common, 1
+ .type common,STT_COMMON
+-
+\ No newline at end of file
+diff --git a/include/bfdlink.h b/include/bfdlink.h
+index 125683d..5565050 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -93,6 +93,9 @@ struct bfd_link_hash_entry
+
+ unsigned int non_ir_ref : 1;
+
++ /* Set if it is a secondary symbol. */
++ unsigned int secondary : 1;
++
+ /* A union of information depending upon the type. */
+ union
+ {
+@@ -355,6 +358,9 @@ struct bfd_link_info
+ /* TRUE if .gnu.hash section should be created. */
+ unsigned int emit_gnu_hash: 1;
+
++ /* TRUE if secondary symbols should be generated. */
++ unsigned int emit_secondary: 1;
++
+ /* If TRUE reduce memory overheads, at the expense of speed. This will
+ cause map file generation to use an O(N^2) algorithm and disable
+ caching ELF symbol buffer. */
+diff --git a/include/elf/common.h b/include/elf/common.h
+index e8ae3ac..b1e66d4 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -664,6 +664,7 @@
+ #define STB_LOCAL 0 /* Symbol not visible outside obj */
+ #define STB_GLOBAL 1 /* Symbol visible outside obj */
+ #define STB_WEAK 2 /* Like globals, lower precedence */
++#define STB_SECONDARY 3 /* Like weaks, lower precedence */
+ #define STB_LOOS 10 /* OS-specific semantics */
+ #define STB_GNU_UNIQUE 10 /* Symbol is unique in namespace */
+ #define STB_HIOS 12 /* OS-specific semantics */
+diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
+index 67c437d..d842c5d 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -2326,6 +2326,8 @@ fragment <<EOF
+ link_info.error_textrel = FALSE;
+ else if (strcmp (optarg, "textoff") == 0)
+ link_info.error_textrel = FALSE;
++ else if (strcmp (optarg, "nosecondary") == 0)
++ link_info.emit_secondary = FALSE;
+ EOF
+ fi
+
+@@ -2453,6 +2455,8 @@ fragment <<EOF
+ -z relro Create RELRO program header\n"));
+ fprintf (file, _("\
+ -z stacksize=SIZE Set size of stack segment\n"));
++ fprintf (file, _("\
++ -z nosecondary Convert secondary symbols to weak symbols\n"));
+ EOF
+ fi
+
+diff --git a/ld/ld.texinfo b/ld/ld.texinfo
+index e71be5e..30dddd4 100644
+--- a/ld/ld.texinfo
++++ b/ld/ld.texinfo
+@@ -1121,6 +1121,10 @@ Marks the object may contain $ORIGIN.
+ @item relro
+ Create an ELF @code{PT_GNU_RELRO} segment header in the object.
+
++@item nosecondary
++Convert secondary symbols to weak symbols when generating a shared
++library.
++
+ @item max-page-size=@var{value}
+ Set the emulation maximum page size to @var{value}.
+
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index 77235d5..096ce2e 100644
+--- a/ld/ldmain.c
++++ b/ld/ldmain.c
+@@ -279,6 +279,7 @@ main (int argc, char **argv)
+ link_info.combreloc = TRUE;
+ link_info.strip_discarded = TRUE;
+ link_info.emit_hash = TRUE;
++ link_info.emit_secondary = TRUE;
+ link_info.callbacks = &link_callbacks;
+ link_info.input_bfds_tail = &link_info.input_bfds;
+ /* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
+diff --git a/ld/testsuite/ld-elf/library1.c b/ld/testsuite/ld-elf/library1.c
+new file mode 100644
+index 0000000..28e255d
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library1.c
+@@ -0,0 +1,11 @@
++#include <stdio.h>
++
++void
++bar (void)
++{
++#ifdef SHARED
++ printf ("library bar (SHARED)\n");
++#else
++ printf ("library bar\n");
++#endif
++}
+diff --git a/ld/testsuite/ld-elf/library1.out b/ld/testsuite/ld-elf/library1.out
+new file mode 100644
+index 0000000..2050e74
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library1.out
+@@ -0,0 +1 @@
++library bar
+diff --git a/ld/testsuite/ld-elf/library2.c b/ld/testsuite/ld-elf/library2.c
+new file mode 100644
+index 0000000..271ebd6
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library2.c
+@@ -0,0 +1,12 @@
++#include <stdio.h>
++
++void
++__attribute__((weak))
++bar (void)
++{
++#ifdef SHARED
++ printf ("weak library bar (SHARED)\n");
++#else
++ printf ("weak library bar\n");
++#endif
++}
+diff --git a/ld/testsuite/ld-elf/library2.out b/ld/testsuite/ld-elf/library2.out
+new file mode 100644
+index 0000000..ddd3d10
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library2.out
+@@ -0,0 +1 @@
++weak library bar
+diff --git a/ld/testsuite/ld-elf/library3.out b/ld/testsuite/ld-elf/library3.out
+new file mode 100644
+index 0000000..881856e
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library3.out
+@@ -0,0 +1 @@
++library bar (SHARED)
+diff --git a/ld/testsuite/ld-elf/library4.out b/ld/testsuite/ld-elf/library4.out
+new file mode 100644
+index 0000000..1ff1840
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library4.out
+@@ -0,0 +1 @@
++weak library bar (SHARED)
+diff --git a/ld/testsuite/ld-elf/library5a.c b/ld/testsuite/ld-elf/library5a.c
+new file mode 100644
+index 0000000..7e44bb4
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library5a.c
+@@ -0,0 +1,16 @@
++#include <stdio.h>
++
++asm (".secondary bar");
++asm (".weak bar");
++
++void
++bar (void)
++{
++ printf ("secondary bar\n");
++}
++
++void
++xxx (void)
++{
++ printf ("xxx\n");
++}
+diff --git a/ld/testsuite/ld-elf/library5b.c b/ld/testsuite/ld-elf/library5b.c
+new file mode 100644
+index 0000000..f44d97c
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library5b.c
+@@ -0,0 +1,10 @@
++#include <stdio.h>
++
++extern void bar (void);
++
++void
++foo (void)
++{
++ printf ("foo\n");
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library6a.c b/ld/testsuite/ld-elf/library6a.c
+new file mode 100644
+index 0000000..7de81b3
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6a.c
+@@ -0,0 +1,4 @@
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library6b.c b/ld/testsuite/ld-elf/library6b.c
+new file mode 100644
+index 0000000..528fd89
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6b.c
+@@ -0,0 +1,7 @@
++extern void bar (void);
++
++void
++xxx (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library6c.c b/ld/testsuite/ld-elf/library6c.c
+new file mode 100644
+index 0000000..60f4b92
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library6c.c
+@@ -0,0 +1,9 @@
++extern void abort (void);
++
++asm (".secondary bar");
++
++void
++bar (void)
++{
++ abort ();
++}
+diff --git a/ld/testsuite/ld-elf/library7a.c b/ld/testsuite/ld-elf/library7a.c
+new file mode 100644
+index 0000000..10cd8bf
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7a.c
+@@ -0,0 +1 @@
++int bar;
+diff --git a/ld/testsuite/ld-elf/library7b.c b/ld/testsuite/ld-elf/library7b.c
+new file mode 100644
+index 0000000..5f67848
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7b.c
+@@ -0,0 +1,7 @@
++extern int bar;
++
++int
++xxx (void)
++{
++ return bar;
++}
+diff --git a/ld/testsuite/ld-elf/library7c.c b/ld/testsuite/ld-elf/library7c.c
+new file mode 100644
+index 0000000..aa57fde
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library7c.c
+@@ -0,0 +1,3 @@
++asm (".secondary bar");
++
++int bar = 3;
+diff --git a/ld/testsuite/ld-elf/library8.map b/ld/testsuite/ld-elf/library8.map
+new file mode 100644
+index 0000000..bcbb4de
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8.map
+@@ -0,0 +1,4 @@
++VERS_1 {
++ global: bar; _bar;
++ local: *;
++};
+diff --git a/ld/testsuite/ld-elf/library8a.c b/ld/testsuite/ld-elf/library8a.c
+new file mode 100644
+index 0000000..29a7508
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8a.c
+@@ -0,0 +1,10 @@
++#if 1
++asm (".secondary bar");
++#else
++asm (".weak bar");
++#endif
++
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library8a.rd b/ld/testsuite/ld-elf/library8a.rd
+new file mode 100644
+index 0000000..a593fbd
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8a.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/library8b.c b/ld/testsuite/ld-elf/library8b.c
+new file mode 100644
+index 0000000..7de81b3
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8b.c
+@@ -0,0 +1,4 @@
++void
++bar (void)
++{
++}
+diff --git a/ld/testsuite/ld-elf/library8b.rd b/ld/testsuite/ld-elf/library8b.rd
+new file mode 100644
+index 0000000..fc18d1a
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8b.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +GLOBAL +DEFAULT +[0-9]+ +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/library8c.c b/ld/testsuite/ld-elf/library8c.c
+new file mode 100644
+index 0000000..dfb6a22
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8c.c
+@@ -0,0 +1,7 @@
++extern void bar ();
++
++void
++foo (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/library8c.rd b/ld/testsuite/ld-elf/library8c.rd
+new file mode 100644
+index 0000000..317631f
+--- /dev/null
++++ b/ld/testsuite/ld-elf/library8c.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +FUNC +GLOBAL +DEFAULT +UND +_?bar@@VERS_1
++#...
+diff --git a/ld/testsuite/ld-elf/secondary-foo.c b/ld/testsuite/ld-elf/secondary-foo.c
+new file mode 100644
+index 0000000..8b23ec8
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary-foo.c
+@@ -0,0 +1,7 @@
++extern void bar (void);
++
++void
++foo (void)
++{
++ bar ();
++}
+diff --git a/ld/testsuite/ld-elf/secondary-main.c b/ld/testsuite/ld-elf/secondary-main.c
+new file mode 100644
+index 0000000..f1cb6b4
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary-main.c
+@@ -0,0 +1,8 @@
++extern void foo (void);
++
++int
++main (void)
++{
++ foo ();
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary.c b/ld/testsuite/ld-elf/secondary.c
+new file mode 100644
+index 0000000..6d64ed7
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary.c
+@@ -0,0 +1,9 @@
++#include <stdio.h>
++
++asm (".secondary bar");
++
++void
++bar (void)
++{
++ printf ("secondary bar\n");
++}
+diff --git a/ld/testsuite/ld-elf/secondary.exp b/ld/testsuite/ld-elf/secondary.exp
+new file mode 100644
+index 0000000..5143262
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary.exp
+@@ -0,0 +1,176 @@
++# Expect script for ELF secondary symbol tests.
++# Copyright 2012
++# 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.
++#
++
++# Exclude non-ELF targets.
++
++# The following tests require running the executable generated by ld,
++# or enough of a build environment to create a fully linked executable.
++# This is not commonly available when testing a cross-built linker.
++if ![isnative] {
++ return
++}
++
++if ![is_elf_format] {
++ return
++}
++
++# Check to see if the C compiler works
++if { [which $CC] == 0 } {
++ return
++}
++
++set build_tests {
++ {"Build secondary1.o"
++ "-r -nostdlib" ""
++ {secondary.c} {{readelf {-s} secondary.rd}} "secondary1.o"}
++ {"Build secondary1.so"
++ "-Wl,-z,nosecondary -shared" "-fPIC"
++ {secondary.c} {{readelf {--dyn-syms} secondary1.rd}} "secondary1.so"}
++ {"Build secondary2.so"
++ "-shared" "-fPIC"
++ {secondary.c} {{readelf {--dyn-syms} secondary2.rd}} "secondary2.so"}
++ {"Build libfoo.so"
++ "-shared" "-fPIC"
++ {secondary-foo.c} {} "libfoo.so"}
++ {"Build secondary-main with secondary.o"
++ "tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} {{readelf {--dyn-syms} secondary1.rd}} "secondary"}
++ {"Build library1.so"
++ "-shared" "-fPIC -DSHARED"
++ {library1.c} {} "library1.so"}
++ {"Build library2.so"
++ "-shared" "-fPIC -DSHARED"
++ {library2.c} {} "library2.so"}
++ {"Build library1.a"
++ "" ""
++ {library1.c} {} "library1.a"}
++ {"Build library2.a"
++ "" ""
++ {library2.c} {} "library2.a"}
++ {"Build secondary3a.o"
++ "" ""
++ {secondary3a.s} {} "secondary3a.a"}
++ {"Build secondary3"
++ "-nostdlib tmpdir/secondary3a.o" ""
++ {secondary3b.s} {{readelf {-s} secondary3.rd}} "secondary3"}
++ {"Build secondary4.so"
++ "-nostdlib -shared tmpdir/secondary3a.o" ""
++ {secondary4.s} {{readelf {--dyn-syms} secondary4.rd}} "secondary4.so"}
++ {"Build library5a.a"
++ "" ""
++ {library5a.c} {} "library5a.a"}
++ {"Build library5b.a"
++ "" ""
++ {library5b.c} {} "library5b.a"}
++ {"Build secondary5.a"
++ "" ""
++ {secondary5.c} {} "secondary5.a"}
++ {"Build library6a.a"
++ "" ""
++ {library6a.c} {} "library6a.a"}
++ {"Build library6b.a"
++ "" ""
++ {library6b.c} {} "library6b.a"}
++ {"Build library6c.a"
++ "" ""
++ {library6c.c} {} "library6c.a"}
++ {"Build secondary6.a"
++ "" ""
++ {secondary6.c} {} "secondary6.a"}
++ {"Build library7a.a"
++ "" ""
++ {library7a.c} {} "library7a.a"}
++ {"Build library7b.a"
++ "" ""
++ {library7b.c} {} "library7b.a"}
++ {"Build library7c.a"
++ "" ""
++ {library7c.c} {} "library7c.a"}
++ {"Build secondary7.a"
++ "" ""
++ {secondary7.c} {} "secondary7.a"}
++ {"Build library8a.so"
++ "-shared -Wl,--version-script=library8.map" "-fPIC"
++ {library8a.c} {{readelf {-s} library8a.rd}} "library8a.so"}
++ {"Build library8b.so"
++ "-shared -Wl,--version-script=library8.map" "-fPIC"
++ {library8b.c} {{readelf {-s} library8b.rd}} "library8b.so"}
++ {"Build library8c.a"
++ "" "-fPIC"
++ {library8c.c} {} "library8c.a"}
++ {"Build library8c.so"
++ "-shared -Wl,--version-script=library8.map tmpdir/library8c.o tmpdir/library8a.so tmpdir/library8b.so"
++ "-fPIC"
++ {dummy.c} {{readelf {-s} library8c.rd}} "library8c.so"}
++}
++
++run_cc_link_tests $build_tests
++
++set run_tests {
++ {"Run secondary-main with secondary.o"
++ "tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary1" "secondary1.out"}
++ {"Run secondary-main with secondary1.so"
++ "tmpdir/secondary1.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary2" "secondary1.out"}
++ {"Run secondary-main with secondary.o library1.o"
++ "tmpdir/secondary.o tmpdir/secondary.o tmpdir/library1.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary3" "library1.out"}
++ {"Run secondary-main with library1.o secondary.o"
++ "tmpdir/library1.o tmpdir/secondary.o tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary4" "library1.out"}
++ {"Run secondary-main with secondary.o library2.o"
++ "tmpdir/secondary.o tmpdir/library2.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary5" "library2.out"}
++ {"Run secondary-main with library2.o secondary.o"
++ "tmpdir/library2.o tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary6" "library2.out"}
++ {"Run secondary-main with secondary.o library1.so"
++ "tmpdir/secondary.o tmpdir/library1.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary7" "library3.out"}
++ {"Run secondary-main with library1.so secondary.o"
++ "tmpdir/library1.so tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary8" "library3.out"}
++ {"Run secondary-main with secondary.o library2.so"
++ "tmpdir/secondary.o tmpdir/library2.so tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary9" "library4.out"}
++ {"Run secondary-main with library2.so secondary.o"
++ "tmpdir/library2.so tmpdir/secondary.o tmpdir/libfoo.so" ""
++ {secondary-main.c} "secondary10" "library4.out"}
++ {"Run secondary5 with library5a.a library5b.a"
++ "tmpdir/secondary5.o tmpdir/library5a.a tmpdir/library5b.a" ""
++ {dummy.c} "secondary5a" "secondary5.out"}
++ {"Run secondary5 with -( library5a.a library5b.a -)"
++ "tmpdir/secondary5.o -\\( tmpdir/library5a.a tmpdir/library5b.a -\\)" ""
++ {dummy.c} "secondary5b" "secondary5.out"}
++ {"Run secondary5 with -( library5a.a library5b.a -) -( library5a.a library5b.a -)"
++ "tmpdir/secondary5.o -\\( tmpdir/library5a.a tmpdir/library5b.a -\\) -\\( tmpdir/library5a.a tmpdir/library5b.a -\\)" ""
++ {dummy.c} "secondary5c" "secondary5.out"}
++ {"Run secondary6 with -( library6a.a library6b.a library6c.a -)"
++ "tmpdir/secondary6.o -\\( tmpdir/library6a.a tmpdir/library6b.a tmpdir/library6c.a -\\)" ""
++ {dummy.c} "secondary6" "secondary6.out"}
++ {"Run secondary7 with -( library7a.a library7b.a library7c.a -)"
++ "tmpdir/secondary7.o -\\( tmpdir/library7a.a tmpdir/library7b.a tmpdir/library7c.a -\\)" ""
++ {dummy.c} "secondary7" "secondary7.out"}
++}
++
++run_ld_link_exec_tests [] $run_tests
+diff --git a/ld/testsuite/ld-elf/secondary.rd b/ld/testsuite/ld-elf/secondary.rd
+new file mode 100644
+index 0000000..9931c04
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.symtab' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar
++#...
+diff --git a/ld/testsuite/ld-elf/secondary1.out b/ld/testsuite/ld-elf/secondary1.out
+new file mode 100644
+index 0000000..8d9378f
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary1.out
+@@ -0,0 +1 @@
++secondary bar
+diff --git a/ld/testsuite/ld-elf/secondary1.rd b/ld/testsuite/ld-elf/secondary1.rd
+new file mode 100644
+index 0000000..89d6d76
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary1.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +WEAK +DEFAULT +[0-9]+ +_?bar
++#...
+diff --git a/ld/testsuite/ld-elf/secondary2.rd b/ld/testsuite/ld-elf/secondary2.rd
+new file mode 100644
+index 0000000..ff618a0
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary2.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +FUNC +SECOND +DEFAULT +[0-9]+ +_?bar
++#...
+diff --git a/ld/testsuite/ld-elf/secondary3.rd b/ld/testsuite/ld-elf/secondary3.rd
+new file mode 100644
+index 0000000..93c3469
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.symtab' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +[A-Z]+ +WEAK +DEFAULT +UND +_?foo
++#...
+diff --git a/ld/testsuite/ld-elf/secondary3a.s b/ld/testsuite/ld-elf/secondary3a.s
+new file mode 100644
+index 0000000..16a1300
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3a.s
+@@ -0,0 +1,4 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .global bar
++bar:
++ .byte 0
+diff --git a/ld/testsuite/ld-elf/secondary3b.s b/ld/testsuite/ld-elf/secondary3b.s
+new file mode 100644
+index 0000000..cc6f37b
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary3b.s
+@@ -0,0 +1,20 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .secondary foo
++ .global bar
++foo:
++ .byte 0
++bar:
++ .byte 0
++ .data
++ .dc.a foo
++
++ .text
++ .global start /* Used by SH targets. */
++start:
++ .global _start
++_start:
++ .global __start
++__start:
++ .global main /* Used by HPPA targets. */
++main:
++ .dc.a bar
+diff --git a/ld/testsuite/ld-elf/secondary4.rd b/ld/testsuite/ld-elf/secondary4.rd
+new file mode 100644
+index 0000000..e84b1a6
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary4.rd
+@@ -0,0 +1,5 @@
++Symbol table '\.dynsym' contains [0-9]+ entries:
++ +Num: +Value +Size Type +Bind +Vis +Ndx Name
++#...
++ +[0-9]+: +0+ +0+ +[A-Z]+ +WEAK +DEFAULT +UND +_?foo
++#...
+diff --git a/ld/testsuite/ld-elf/secondary4.s b/ld/testsuite/ld-elf/secondary4.s
+new file mode 100644
+index 0000000..a2acf21
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary4.s
+@@ -0,0 +1,9 @@
++ .section .text,"axG",%progbits,foo_group,comdat
++ .secondary foo
++ .global bar
++foo:
++ .byte 0
++bar:
++ .byte 0
++ .data
++ .dc.a foo
+diff --git a/ld/testsuite/ld-elf/secondary5.c b/ld/testsuite/ld-elf/secondary5.c
+new file mode 100644
+index 0000000..a2b2f20
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary5.c
+@@ -0,0 +1,10 @@
++extern void foo (void);
++extern void xxx (void);
++
++int
++main (void)
++{
++ foo ();
++ xxx ();
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary5.out b/ld/testsuite/ld-elf/secondary5.out
+new file mode 100644
+index 0000000..730c35d
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary5.out
+@@ -0,0 +1,3 @@
++foo
++secondary bar
++xxx
+diff --git a/ld/testsuite/ld-elf/secondary6.c b/ld/testsuite/ld-elf/secondary6.c
+new file mode 100644
+index 0000000..2a7e17b
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary6.c
+@@ -0,0 +1,11 @@
++#include <stdio.h>
++
++extern void xxx (void);
++
++int
++main (void)
++{
++ xxx ();
++ printf ("OK\n");
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary6.out b/ld/testsuite/ld-elf/secondary6.out
+new file mode 100644
+index 0000000..d86bac9
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary6.out
+@@ -0,0 +1 @@
++OK
+diff --git a/ld/testsuite/ld-elf/secondary7.c b/ld/testsuite/ld-elf/secondary7.c
+new file mode 100644
+index 0000000..9a67352
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary7.c
+@@ -0,0 +1,13 @@
++#include <stdio.h>
++
++extern void abort (void);
++extern int xxx (void);
++
++int
++main (void)
++{
++ if (xxx () != 0)
++ abort ();
++ printf ("OK\n");
++ return 0;
++}
+diff --git a/ld/testsuite/ld-elf/secondary7.out b/ld/testsuite/ld-elf/secondary7.out
+new file mode 100644
+index 0000000..d86bac9
+--- /dev/null
++++ b/ld/testsuite/ld-elf/secondary7.out
+@@ -0,0 +1 @@
++OK
+--
+1.9.3
+
diff --git a/patches/binutils-sharable.patch b/patches/binutils-sharable.patch
new file mode 100644
index 0000000..0bd574a
--- /dev/null
+++ b/patches/binutils-sharable.patch
@@ -0,0 +1,1305 @@
+From d982080fe4d81ee0a863a0258b317377260a3a8f Mon Sep 17 00:00:00 2001
+From: "H.J. Lu" <hjl.tools@gmail.com>
+Date: Mon, 4 Nov 2013 09:44:13 -0800
+Subject: [PATCH] Add PT_GNU_SHR/SHF_GNU_SHARABLE/SHN_GNU_SHARABLE_COMMON
+ support to gas/ld
+
+PT_GNU_SHR/SHF_GNU_SHARABLE/SHN_GNU_SHARABLE_COMMON are used to group
+data into a PT_GNU_SHR to improve performance on NUMA system.
+---
+ ChangeLog.sharable | 140 ++++++++++++++++++++++++++
+ bfd/elf-bfd.h | 21 +++-
+ bfd/elf.c | 103 +++++++++++++++++++
+ bfd/elf32-i386.c | 55 ++++++++--
+ bfd/elf64-x86-64.c | 73 +++++++++++---
+ bfd/elflink.c | 228 +++++++++++++++++++++++++++++++++++++++++-
+ bfd/elfnn-ia64.c | 16 ++-
+ binutils/readelf.c | 5 +
+ gas/config/obj-elf.c | 42 ++++++++
+ include/bfdlink.h | 3 +
+ include/elf/common.h | 6 ++
+ ld/emulparams/elf32_x86_64.sh | 1 +
+ ld/emulparams/elf64_ia64.sh | 1 +
+ ld/emulparams/elf_i386.sh | 1 +
+ ld/emulparams/elf_x86_64.sh | 1 +
+ ld/emultempl/elf32.em | 7 ++
+ ld/ldmain.c | 1 +
+ ld/scripttempl/elf.sc | 35 +++++++
+ 18 files changed, 712 insertions(+), 27 deletions(-)
+ create mode 100644 ChangeLog.sharable
+
+diff --git a/ChangeLog.sharable b/ChangeLog.sharable
+new file mode 100644
+index 0000000..3ccf957
+--- /dev/null
++++ b/ChangeLog.sharable
+@@ -0,0 +1,140 @@
++bfd/
++
++2013-04-05 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf-bfd.h (struct elf_backend_data <merge_symbol>): Add abfd,
++ newdyn and olddyn. Remove const from oldsec.
++ (_bfd_elf_sharable_merge_symbol): Updated.
++ * elf64-x86-64.c (elf_x86_64_merge_symbol): Likewise.
++ * elflink.c (_bfd_elf_merge_symbol): Update bed->merge_symbol
++ call.
++
++2009-12-12 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf.c: Fix shadowed variable warnings.
++ * elf64-x86-64.c: Likewise.
++ * elflink.c: Likewise.
++
++2007-01-23 H.J. Lu <hongjiu.lu@intel.com>
++
++ * elf-bfd.h (_bfd_elf_sharable_com_section): New.
++ (_bfd_elf_add_sharable_symbol): Likewise.
++ (_bfd_elf_sharable_section_from_bfd_section): Likewise.
++ (_bfd_elf_sharable_symbol_processing): Likewise.
++ (_bfd_elf_sharable_common_definition): Likewise.
++ (_bfd_elf_sharable_common_section_index): Likewise.
++ (_bfd_elf_sharable_common_section): Likewise.
++ (_bfd_elf_sharable_merge_symbol): Likewise.
++
++ * elf.c (special_sections_g): Add ".gnu.linkonce.shrb" and
++ ".gnu.linkonce.shrd".
++ (special_sections_s): Add ".sharable_bss" and ".sharable_data".
++ (get_program_header_size): Handle PT_GNU_SHR segment.
++ (_bfd_elf_map_sections_to_segments): Likewise.
++ (assign_file_positions_for_load_sections): Likewise.
++
++ * elf32-i386.c (elf_i386_link_hash_table): Add sdynsharablebss
++ and srelsharablebss fields.
++ (elf_i386_link_hash_table_create): Initialize sdynsharablebss
++ and srelsharablebss.
++ (elf_i386_create_dynamic_sections): Handle sdynsharablebss and
++ srelsharablebss.
++ (elf_i386_adjust_dynamic_symbol): Likewise.
++ (elf_i386_size_dynamic_sections): Likewise.
++ (elf_i386_finish_dynamic_symbol): Likewise.
++ (elf_backend_add_symbol_hook): Defined.
++ (elf_backend_section_from_bfd_section): Likewise.
++ (elf_backend_symbol_processing): Likewise.
++ (elf_backend_common_section_index): Likewise.
++ (elf_backend_common_section): Likewise.
++ (elf_backend_common_definition): Likewise.
++ (elf_backend_merge_symbol): Likewise.
++
++ * elf64-x86-64.c (elf64_x86_64_link_hash_table): Add
++ sdynsharablebss and srelsharablebss fields.
++ (elf64_x86_64_link_hash_table_create): Initialize sdynsharablebss
++ and srelsharablebss.
++ (elf64_x86_64_create_dynamic_sections): Handle sdynsharablebss
++ and srelsharablebss.
++ (elf64_x86_64_adjust_dynamic_symbol): Likewise.
++ (elf64_x86_64_size_dynamic_sections): Likewise.
++ (elf64_x86_64_finish_dynamic_symbol): Likewise.
++ (elf64_x86_64_add_symbol_hook): Handle sharable symbols.
++ (elf64_x86_64_elf_section_from_bfd_section): Likewise.
++ (elf64_x86_64_symbol_processing): Likewise.
++ (elf64_x86_64_merge_symbol): Likewise.
++ (elf64_x86_64_common_definition): Handle sharable sections.
++ (elf64_x86_64_common_section_index): Likewise.
++ (elf64_x86_64_common_section): Likewise.
++
++ * elflink.c (_bfd_elf_create_dynamic_sections): Handle
++ .dynsharablebss section.
++ (_bfd_elf_sharable_com_section): New.
++ (get_sharable_common_section): Likewise.
++ (_bfd_elf_add_sharable_symbol): Likewise.
++ (_bfd_elf_sharable_section_from_bfd_section): Likewise.
++ (_bfd_elf_sharable_symbol_processing): Likewise.
++ (_bfd_elf_sharable_common_definition): Likewise.
++ (_bfd_elf_sharable_common_section_index): Likewise.
++ (_bfd_elf_sharable_common_section): Likewise.
++ (_bfd_elf_sharable_merge_symbol): Likewise.
++
++ * elfnn-ia64.c (elfNN_ia64_add_symbol_hook): Handle sharable
++ symbols.
++ (elf_backend_add_symbol_hook): Defined.
++ (elf_backend_section_from_bfd_section): Likewise.
++ (elf_backend_symbol_processing): Likewise.
++ (elf_backend_common_section_index): Likewise.
++ (elf_backend_common_section): Likewise.
++ (elf_backend_common_definition): Likewise.
++ (elf_backend_merge_symbol): Likewise.
++
++binutils/
++
++2007-01-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ * readelf.c (dump_relocations): Handle sharable sections.
++ (get_segment_type): Handle sharable segment.
++ (get_symbol_index_type): Handle sharable sections.
++
++gas/
++
++2007-01-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ * config/obj-elf.c (obj_elf_sharable_common): New.
++ (elf_pseudo_table): Add "sharable_common".
++ (obj_elf_change_section): Handle sharable sections.
++
++include/
++
++2007-01-23 H.J. Lu <hongjiu.lu@intel.com>
++
++ * bfdlink.h (bfd_link_info): Add sharable_sections.
++
++include/elf/
++
++2007-01-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ * common.h (PT_GNU_SHR): New.
++ (SHF_GNU_SHARABLE): Likewise.
++ (SHN_GNU_SHARABLE_COMMON): Likewise.
++
++ld/
++
++2011-01-08 H.J. Lu <hongjiu.lu@intel.com>
++
++ * emulparams/elf32_x86_64.sh (SHARABLE_SECTIONS): Set to yes.
++
++2007-01-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ * emulparams/elf64_ia64.sh (SHARABLE_SECTIONS): Set to yes.
++ * emulparams/elf_i386.sh (SHARABLE_SECTIONS): Likewise.
++ * emulparams/elf_x86_64.sh (SHARABLE_SECTIONS): Likewise.
++
++ * emultempl/elf32.em (gld${EMULATION_NAME}_before_parse): Set
++ link_info.sharable_sections based on $SHARABLE_SECTIONS.
++ (gld${EMULATION_NAME}_place_orphan): Don't allow orphaned
++ sharable sections.
++
++ * ldmain.c (main): Initialize link_info.sharable_sections.
++ * scripttempl/elf.sc: Support sharable sections.
+diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
+index 5e53cba..0b694e4 100644
+--- a/bfd/elf-bfd.h
++++ b/bfd/elf-bfd.h
+@@ -1218,8 +1218,9 @@ struct elf_backend_data
+ /* Return TRUE if we can merge 2 definitions. */
+ bfd_boolean (*merge_symbol) (struct elf_link_hash_entry *,
+ const Elf_Internal_Sym *, asection **,
++ bfd_boolean, bfd_boolean, bfd *,
+ bfd_boolean, bfd_boolean,
+- bfd *, const asection *);
++ bfd *, asection *);
+
+ /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
+ bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *);
+@@ -2150,6 +2151,24 @@ extern bfd_boolean bfd_elf_link_add_symbols
+ (bfd *, struct bfd_link_info *);
+ extern bfd_boolean _bfd_elf_add_dynamic_entry
+ (struct bfd_link_info *, bfd_vma, bfd_vma);
++extern asection _bfd_elf_sharable_com_section;
++extern bfd_boolean _bfd_elf_add_sharable_symbol
++ (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **,
++ flagword *, asection **, bfd_vma *);
++extern bfd_boolean _bfd_elf_sharable_section_from_bfd_section
++ (bfd *, asection *, int *);
++extern void _bfd_elf_sharable_symbol_processing
++ (bfd *, asymbol *);
++extern bfd_boolean _bfd_elf_sharable_common_definition
++ (Elf_Internal_Sym *);
++extern unsigned int _bfd_elf_sharable_common_section_index
++ (asection *);
++extern asection *_bfd_elf_sharable_common_section
++ (asection *);
++extern bfd_boolean _bfd_elf_sharable_merge_symbol
++ (struct elf_link_hash_entry *, const Elf_Internal_Sym *,
++ asection **, bfd_boolean, bfd_boolean, bfd *,
++ bfd_boolean, bfd_boolean, bfd *, asection *);
+
+ extern bfd_boolean bfd_elf_link_record_dynamic_symbol
+ (struct bfd_link_info *, struct elf_link_hash_entry *);
+diff --git a/bfd/elf.c b/bfd/elf.c
+index c8238ba..2f5162d 100644
+--- a/bfd/elf.c
++++ b/bfd/elf.c
+@@ -2244,6 +2244,8 @@ static const struct bfd_elf_special_section special_sections_g[] =
+ { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC },
++ { STRING_COMMA_LEN (".gnu.linkonce.shrb"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
++ { STRING_COMMA_LEN (".gnu.linkonce.shrd"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
+ { NULL, 0, 0, 0, 0 }
+ };
+
+@@ -2298,6 +2300,8 @@ static const struct bfd_elf_special_section special_sections_s[] =
+ /* See struct bfd_elf_special_section declaration for the semantics of
+ this special case where .prefix_length != strlen (.prefix). */
+ { ".stabstr", 5, 3, SHT_STRTAB, 0 },
++ { STRING_COMMA_LEN (".sharable_bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
++ { STRING_COMMA_LEN (".sharable_data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_GNU_SHARABLE},
+ { NULL, 0, 0, 0, 0 }
+ };
+
+@@ -3761,6 +3765,32 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info)
+ }
+ }
+
++ /* Check to see if we need a PT_GNU_SHR segment for sharable data
++ sections. */
++ for (s = abfd->sections; s != NULL; s = s->next)
++ {
++ if ((elf_section_flags (s) & SHF_GNU_SHARABLE) != 0
++ && elf_section_type (s) == SHT_PROGBITS)
++ {
++ /* We need a PT_GNU_SHR segment. */
++ ++segs;
++ break;
++ }
++ }
++
++ /* Check to see if we need a PT_GNU_SHR segment for sharable bss
++ sections. */
++ for (s = abfd->sections; s != NULL; s = s->next)
++ {
++ if ((elf_section_flags (s) & SHF_GNU_SHARABLE) != 0
++ && elf_section_type (s) == SHT_NOBITS)
++ {
++ /* We need a PT_GNU_SHR segment. */
++ ++segs;
++ break;
++ }
++ }
++
+ /* Let the backend count up any program headers it might need. */
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_additional_program_headers)
+@@ -3931,6 +3961,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+ bfd_boolean phdr_in_segment = TRUE;
+ bfd_boolean writable;
+ int tls_count = 0;
++ int sharable_data_count = 0, sharable_bss_count = 0;
++ asection *first_sharable_data = NULL, *first_sharable_bss = NULL;
+ asection *first_tls = NULL;
+ asection *dynsec, *eh_frame_hdr;
+ bfd_size_type amt;
+@@ -4239,6 +4271,22 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+ first_tls = s;
+ tls_count++;
+ }
++ if (elf_section_flags (s) & SHF_GNU_SHARABLE)
++ {
++ if (elf_section_type (s) == SHT_PROGBITS)
++ {
++ if (! sharable_data_count)
++ first_sharable_data = s;
++ sharable_data_count++;
++ }
++ else
++ {
++ BFD_ASSERT (elf_section_type (s) == SHT_NOBITS);
++ if (! sharable_bss_count)
++ first_sharable_bss = s;
++ sharable_bss_count++;
++ }
++ }
+ }
+
+ /* If there are any SHF_TLS output sections, add PT_TLS segment. */
+@@ -4286,6 +4334,60 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+ pm = &m->next;
+ }
+
++ /* If there are any output SHF_GNU_SHARABLE data sections, add a
++ PT_GNU_SHR segment. */
++ if (sharable_data_count > 0)
++ {
++ int j;
++
++ amt = sizeof (struct elf_segment_map);
++ amt += (sharable_data_count - 1) * sizeof (asection *);
++ m = bfd_zalloc (abfd, amt);
++ if (m == NULL)
++ goto error_return;
++ m->next = NULL;
++ m->p_type = PT_GNU_SHR;
++ m->count = sharable_data_count;
++ /* Mandated PF_R. */
++ m->p_flags = PF_R;
++ m->p_flags_valid = 1;
++ for (j = 0; j < sharable_data_count; ++j)
++ {
++ m->sections[j] = first_sharable_data;
++ first_sharable_data = first_sharable_data->next;
++ }
++
++ *pm = m;
++ pm = &m->next;
++ }
++
++ /* If there are any output SHF_GNU_SHARABLE bss sections, add a
++ PT_GNU_SHR segment. */
++ if (sharable_bss_count > 0)
++ {
++ int j;
++
++ amt = sizeof (struct elf_segment_map);
++ amt += (sharable_bss_count - 1) * sizeof (asection *);
++ m = bfd_zalloc (abfd, amt);
++ if (m == NULL)
++ goto error_return;
++ m->next = NULL;
++ m->p_type = PT_GNU_SHR;
++ m->count = sharable_bss_count;
++ /* Mandated PF_R. */
++ m->p_flags = PF_R;
++ m->p_flags_valid = 1;
++ for (j = 0; j < sharable_bss_count; ++j)
++ {
++ m->sections[j] = first_sharable_bss;
++ first_sharable_bss = first_sharable_bss->next;
++ }
++
++ *pm = m;
++ pm = &m->next;
++ }
++
+ /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+ segment. */
+ eh_frame_hdr = elf_eh_frame_hdr (abfd);
+@@ -4826,6 +4928,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
+ align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
+
+ if ((p->p_type == PT_LOAD
++ || p->p_type == PT_GNU_SHR
+ || p->p_type == PT_TLS)
+ && (this_hdr->sh_type != SHT_NOBITS
+ || ((this_hdr->sh_flags & SHF_ALLOC) != 0
+diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
+index e0eef28..e14ca09 100644
+--- a/bfd/elf32-i386.c
++++ b/bfd/elf32-i386.c
+@@ -842,6 +842,9 @@ struct elf_i386_link_hash_table
+
+ /* The index of the next unused R_386_IRELATIVE slot in .rel.plt. */
+ bfd_vma next_irelative_index;
++
++ asection *sdynsharablebss;
++ asection *srelsharablebss;
+ };
+
+ /* Get the i386 ELF linker hash table from a link_info structure. */
+@@ -1023,10 +1026,19 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
+
+ htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
+ if (!info->shared)
+- htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
++ {
++ htab->srelbss = bfd_get_linker_section (dynobj, ".rel.bss");
++ htab->sdynsharablebss
++ = bfd_get_linker_section (dynobj, ".dynsharablebss");
++ htab->srelsharablebss
++ = bfd_get_linker_section (dynobj, ".rel.sharable_bss");
++ }
+
+ if (!htab->sdynbss
+- || (!info->shared && !htab->srelbss))
++ || (!info->shared
++ && (!htab->srelbss
++ || !htab->sdynsharablebss
++ || !htab->srelsharablebss)))
+ abort ();
+
+ if (get_elf_i386_backend_data (dynobj)->is_vxworks
+@@ -2218,17 +2230,23 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info,
+ both the dynamic object and the regular object will refer to the
+ same memory location for the variable. */
+
++ s = htab->sdynbss;
++
+ /* We must generate a R_386_COPY reloc to tell the dynamic linker to
+ copy the initial value out of the dynamic object and into the
+ runtime process image. */
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
+ {
+- htab->srelbss->size += sizeof (Elf32_External_Rel);
++ if (elf_section_flags (h->root.u.def.section) & SHF_GNU_SHARABLE)
++ {
++ htab->srelsharablebss->size += sizeof (Elf32_External_Rel);
++ s = htab->sdynsharablebss;
++ }
++ else
++ htab->srelbss->size += sizeof (Elf32_External_Rel);
+ h->needs_copy = 1;
+ }
+
+- s = htab->sdynbss;
+-
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
+ }
+
+@@ -2993,6 +3011,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
+ || s == htab->elf.igotplt
+ || s == htab->plt_got
+ || s == htab->plt_eh_frame
++ || s == htab->sdynsharablebss
+ || s == htab->sdynbss)
+ {
+ /* Strip these too. */
+@@ -4852,20 +4871,26 @@ do_glob_dat:
+ if (h->needs_copy)
+ {
+ Elf_Internal_Rela rel;
++ asection *s;
++
++ if (h->root.u.def.section == htab->sdynsharablebss)
++ s = htab->srelsharablebss;
++ else
++ s = htab->srelbss;
+
+ /* This symbol needs a copy reloc. Set it up. */
+
+ if (h->dynindx == -1
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+- || htab->srelbss == NULL)
++ || s == NULL)
+ abort ();
+
+ rel.r_offset = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY);
+- elf_append_rel (output_bfd, htab->srelbss, &rel);
++ elf_append_rel (output_bfd, s, &rel);
+ }
+
+ return TRUE;
+@@ -5260,7 +5285,8 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
+- return TRUE;
++ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++ secp, valp);
+ }
+
+ #define TARGET_LITTLE_SYM i386_elf32_vec
+@@ -5311,6 +5337,19 @@ elf_i386_add_symbol_hook (bfd * abfd,
+ #define elf_backend_hash_symbol elf_i386_hash_symbol
+ #define elf_backend_add_symbol_hook elf_i386_add_symbol_hook
+
++#define elf_backend_section_from_bfd_section \
++ _bfd_elf_sharable_section_from_bfd_section
++#define elf_backend_symbol_processing \
++ _bfd_elf_sharable_symbol_processing
++#define elf_backend_common_section_index \
++ _bfd_elf_sharable_common_section_index
++#define elf_backend_common_section \
++ _bfd_elf_sharable_common_section
++#define elf_backend_common_definition \
++ _bfd_elf_sharable_common_definition
++#define elf_backend_merge_symbol \
++ _bfd_elf_sharable_merge_symbol
++
+ #include "elf32-target.h"
+
+ /* FreeBSD support. */
+diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
+index 4aff9b0..dd996cf 100644
+--- a/bfd/elf64-x86-64.c
++++ b/bfd/elf64-x86-64.c
+@@ -866,6 +866,9 @@ struct elf_x86_64_link_hash_table
+ bfd_vma next_jump_slot_index;
+ /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt. */
+ bfd_vma next_irelative_index;
++
++ asection *sdynsharablebss;
++ asection *srelsharablebss;
+ };
+
+ /* Get the x86-64 ELF linker hash table from a link_info structure. */
+@@ -1074,10 +1077,10 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
+ if (info->executable)
+ {
+ /* Always allow copy relocs for building executables. */
++ const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+ asection *s = bfd_get_linker_section (dynobj, ".rela.bss");
+ if (s == NULL)
+ {
+- const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
+ s = bfd_make_section_anyway_with_flags (dynobj,
+ ".rela.bss",
+ (bed->dynamic_sec_flags
+@@ -1088,6 +1091,32 @@ elf_x86_64_create_dynamic_sections (bfd *dynobj,
+ return FALSE;
+ }
+ htab->srelbss = s;
++
++ s = bfd_get_linker_section (dynobj, ".dynsharablebss");
++ if (s == NULL)
++ {
++ s = bfd_make_section_anyway_with_flags (dynobj,
++ ".dynsharablebss",
++ (SEC_ALLOC
++ | SEC_LINKER_CREATED));
++ if (s == NULL)
++ return FALSE;
++ }
++ htab->sdynsharablebss = s;
++
++ s = bfd_get_linker_section (dynobj, ".rela.sharable_bss");
++ if (s == NULL)
++ {
++ s = bfd_make_section_anyway_with_flags (dynobj,
++ ".rela.sharable_bss",
++ (bed->dynamic_sec_flags
++ | SEC_READONLY));
++ if (s == NULL
++ || ! bfd_set_section_alignment (dynobj, s,
++ bed->s->log_file_align))
++ return FALSE;
++ }
++ htab->srelsharablebss = s;
+ }
+
+ if (!info->no_ld_generated_unwind_info
+@@ -2444,6 +2473,8 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
+ if (htab == NULL)
+ return FALSE;
+
++ s = htab->sdynbss;
++
+ /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker
+ to copy the initial value out of the dynamic object and into the
+ runtime process image. */
+@@ -2451,12 +2482,16 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info,
+ {
+ const struct elf_backend_data *bed;
+ bed = get_elf_backend_data (info->output_bfd);
+- htab->srelbss->size += bed->s->sizeof_rela;
++ if (elf_section_flags (h->root.u.def.section) & SHF_GNU_SHARABLE)
++ {
++ htab->srelsharablebss->size += bed->s->sizeof_rela;
++ s = htab->sdynsharablebss;
++ }
++ else
++ htab->srelbss->size += bed->s->sizeof_rela;
+ h->needs_copy = 1;
+ }
+
+- s = htab->sdynbss;
+-
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
+ }
+
+@@ -3243,6 +3278,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd,
+ || s == htab->plt_bnd
+ || s == htab->plt_got
+ || s == htab->plt_eh_frame
++ || s == htab->sdynsharablebss
+ || s == htab->sdynbss)
+ {
+ /* Strip this section if we don't need it; see the
+@@ -5206,13 +5242,19 @@ do_glob_dat:
+ if (h->needs_copy)
+ {
+ Elf_Internal_Rela rela;
++ asection *s;
++
++ if (h->root.u.def.section == htab->sdynsharablebss)
++ s = htab->srelsharablebss;
++ else
++ s = htab->srelbss;
+
+ /* This symbol needs a copy reloc. Set it up. */
+
+ if (h->dynindx == -1
+ || (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+- || htab->srelbss == NULL)
++ || s == NULL)
+ abort ();
+
+ rela.r_offset = (h->root.u.def.value
+@@ -5220,7 +5262,7 @@ do_glob_dat:
+ + h->root.u.def.section->output_offset);
+ rela.r_info = htab->r_info (h->dynindx, R_X86_64_COPY);
+ rela.r_addend = 0;
+- elf_append_rela (output_bfd, htab->srelbss, &rela);
++ elf_append_rela (output_bfd, s, &rela);
+ }
+
+ return TRUE;
+@@ -5665,7 +5707,8 @@ elf_x86_64_add_symbol_hook (bfd *abfd,
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
+- return TRUE;
++ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++ secp, valp);
+ }
+
+
+@@ -5681,7 +5724,8 @@ elf_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
+ *index_return = SHN_X86_64_LCOMMON;
+ return TRUE;
+ }
+- return FALSE;
++ return _bfd_elf_sharable_section_from_bfd_section (abfd, sec,
++ index_return);
+ }
+
+ /* Process a symbol. */
+@@ -5699,22 +5743,26 @@ elf_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ asym->value = elfsym->internal_elf_sym.st_size;
+ /* Common symbol doesn't set BSF_GLOBAL. */
+ asym->flags &= ~BSF_GLOBAL;
++ return;
+ break;
+ }
++
++ _bfd_elf_sharable_symbol_processing (abfd, asym);
+ }
+
+ static bfd_boolean
+ elf_x86_64_common_definition (Elf_Internal_Sym *sym)
+ {
+ return (sym->st_shndx == SHN_COMMON
+- || sym->st_shndx == SHN_X86_64_LCOMMON);
++ || sym->st_shndx == SHN_X86_64_LCOMMON
++ || _bfd_elf_sharable_common_definition (sym));
+ }
+
+ static unsigned int
+ elf_x86_64_common_section_index (asection *sec)
+ {
+ if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+- return SHN_COMMON;
++ return _bfd_elf_sharable_common_section_index (sec);
+ else
+ return SHN_X86_64_LCOMMON;
+ }
+@@ -5723,7 +5771,7 @@ static asection *
+ elf_x86_64_common_section (asection *sec)
+ {
+ if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+- return bfd_com_section_ptr;
++ return _bfd_elf_sharable_common_section (sec);
+ else
+ return &_bfd_elf_large_com_section;
+ }
+@@ -5733,9 +5781,12 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+ const Elf_Internal_Sym *sym,
+ asection **psec,
+ bfd_boolean newdef,
++ bfd_boolean newdyn,
++ bfd *abfd,
+ bfd_boolean olddef,
++ bfd_boolean olddyn,
+ bfd *oldbfd,
+- const asection *oldsec)
++ asection *oldsec)
+ {
+ /* A normal common symbol and a large common symbol result in a
+ normal common symbol. We turn the large common symbol into a
+@@ -5744,7 +5795,8 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+ && h->root.type == bfd_link_hash_common
+ && !newdef
+ && bfd_is_com_section (*psec)
+- && oldsec != *psec)
++ && oldsec != *psec
++ && _bfd_elf_sharable_common_section_index (oldsec) == SHN_COMMON)
+ {
+ if (sym->st_shndx == SHN_COMMON
+ && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) != 0)
+@@ -5752,13 +5804,19 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h,
+ h->root.u.c.p->section
+ = bfd_make_section_old_way (oldbfd, "COMMON");
+ h->root.u.c.p->section->flags = SEC_ALLOC;
++ return TRUE;
+ }
+ else if (sym->st_shndx == SHN_X86_64_LCOMMON
+ && (elf_section_flags (oldsec) & SHF_X86_64_LARGE) == 0)
+- *psec = bfd_com_section_ptr;
++ {
++ *psec = bfd_com_section_ptr;
++ return TRUE;
++ }
+ }
+
+- return TRUE;
++ return _bfd_elf_sharable_merge_symbol (h, sym, psec, newdef, newdyn,
++ abfd, olddef, olddyn, oldbfd,
++ oldsec);
+ }
+
+ static int
+diff --git a/bfd/elflink.c b/bfd/elflink.c
+index 2da6d1b..983874d 100644
+--- a/bfd/elflink.c
++++ b/bfd/elflink.c
+@@ -386,6 +386,27 @@ _bfd_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+ if (s == NULL
+ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+ return FALSE;
++
++ if (info->sharable_sections)
++ {
++ s = bfd_make_section (abfd, ".dynsharablebss");
++ if (s == NULL
++ || ! bfd_set_section_flags (abfd, s,
++ (SEC_ALLOC
++ | SEC_LINKER_CREATED)))
++ return FALSE;
++
++ s = bfd_make_section (abfd,
++ (bed->default_use_rela_p
++ ? ".rela.sharable_bss"
++ : ".rel.sharable_bss"));
++ if (s == NULL
++ || ! bfd_set_section_flags (abfd, s,
++ flags | SEC_READONLY)
++ || ! bfd_set_section_alignment (abfd, s,
++ bed->s->log_file_align))
++ return FALSE;
++ }
+ }
+ }
+
+@@ -1327,7 +1348,8 @@ _bfd_elf_merge_symbol (bfd *abfd,
+ backend to check if we can merge them. */
+ if (bed->merge_symbol != NULL)
+ {
+- if (!bed->merge_symbol (h, sym, psec, newdef, olddef, oldbfd, oldsec))
++ if (!bed->merge_symbol (h, sym, psec, newdef, newdyn, abfd,
++ olddef, olddyn, oldbfd, oldsec))
+ return FALSE;
+ sec = *psec;
+ }
+@@ -13233,3 +13255,207 @@ elf_append_rel (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+ BFD_ASSERT (loc + bed->s->sizeof_rel <= s->contents + s->size);
+ bed->s->swap_reloc_out (abfd, rel, loc);
+ }
++
++asection _bfd_elf_sharable_com_section
++ = BFD_FAKE_SECTION (_bfd_elf_sharable_com_section, SEC_IS_COMMON,
++ NULL, "SHARABLE_COMMON", 0);
++
++static asection *
++get_sharable_common_section (bfd *abfd)
++{
++ asection *scomm = bfd_get_section_by_name (abfd, "SHARABLE_COMMON");
++
++ if (scomm == NULL)
++ {
++ scomm = bfd_make_section_with_flags (abfd,
++ "SHARABLE_COMMON",
++ (SEC_ALLOC
++ | SEC_IS_COMMON
++ | SEC_LINKER_CREATED));
++ if (scomm == NULL)
++ return scomm;
++ elf_section_flags (scomm) |= SHF_GNU_SHARABLE;
++ }
++
++ return scomm;
++}
++
++bfd_boolean
++_bfd_elf_add_sharable_symbol (bfd *abfd ATTRIBUTE_UNUSED,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ Elf_Internal_Sym *sym,
++ const char **namep ATTRIBUTE_UNUSED,
++ flagword *flagsp ATTRIBUTE_UNUSED,
++ asection **secp,
++ bfd_vma *valp)
++{
++ asection *scomm;
++
++ switch (sym->st_shndx)
++ {
++ case SHN_GNU_SHARABLE_COMMON:
++ scomm = get_sharable_common_section (abfd);
++ if (scomm == NULL)
++ return FALSE;
++ *secp = scomm;
++ *valp = sym->st_size;
++ break;
++ }
++ return TRUE;
++}
++
++bfd_boolean
++_bfd_elf_sharable_section_from_bfd_section
++ (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, int *index_return)
++{
++ if (sec == &_bfd_elf_sharable_com_section)
++ {
++ *index_return = SHN_GNU_SHARABLE_COMMON;
++ return TRUE;
++ }
++ return FALSE;
++}
++
++void
++_bfd_elf_sharable_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
++ asymbol *asym)
++{
++ elf_symbol_type *elfsym = (elf_symbol_type *) asym;
++
++ switch (elfsym->internal_elf_sym.st_shndx)
++ {
++ case SHN_GNU_SHARABLE_COMMON:
++ asym->section = &_bfd_elf_sharable_com_section;
++ asym->value = elfsym->internal_elf_sym.st_size;
++ asym->flags &= ~BSF_GLOBAL;
++ break;
++ }
++}
++
++bfd_boolean
++_bfd_elf_sharable_common_definition (Elf_Internal_Sym *sym)
++{
++ return (sym->st_shndx == SHN_COMMON
++ || sym->st_shndx == SHN_GNU_SHARABLE_COMMON);
++}
++
++unsigned int
++_bfd_elf_sharable_common_section_index (asection *sec)
++{
++ if ((elf_section_flags (sec) & SHF_GNU_SHARABLE) == 0)
++ return SHN_COMMON;
++ else
++ return SHN_GNU_SHARABLE_COMMON;
++}
++
++asection *
++_bfd_elf_sharable_common_section (asection *sec)
++{
++ if ((elf_section_flags (sec) & SHF_GNU_SHARABLE) == 0)
++ return bfd_com_section_ptr;
++ else
++ return &_bfd_elf_sharable_com_section;
++}
++
++bfd_boolean
++_bfd_elf_sharable_merge_symbol (struct elf_link_hash_entry *h,
++ const Elf_Internal_Sym *sym,
++ asection **psec,
++ bfd_boolean newdef,
++ bfd_boolean newdyn,
++ bfd *abfd,
++ bfd_boolean olddef,
++ bfd_boolean olddyn,
++ bfd *oldbfd,
++ asection *oldsec)
++{
++ asection *sec = *psec;
++
++ /* Check sharable symbol. If one is undefined, it is OK. */
++ if (oldsec && !bfd_is_und_section (sec))
++ {
++ bfd_boolean sharable, oldsharable;
++
++ sharable = (elf_section_data (sec)
++ && (elf_section_flags (sec) & SHF_GNU_SHARABLE));
++ oldsharable = (elf_section_data (oldsec)
++ && (elf_section_flags (oldsec)
++ & SHF_GNU_SHARABLE));
++
++ if (sharable != oldsharable)
++ {
++ bfd *nsbfd, *sbfd;
++ asection *nssec, *ssec;
++ bfd_boolean nsdyn, sdyn, nsdef, sdef;
++
++ if (oldsharable)
++ {
++ sbfd = oldbfd;
++ nsbfd = abfd;
++ ssec = oldsec;
++ nssec = sec;
++ sdyn = olddyn;
++ nsdyn = newdyn;
++ sdef = olddef;
++ nsdef = newdef;
++ }
++ else
++ {
++ sbfd = abfd;
++ nsbfd = oldbfd;
++ ssec = sec;
++ nssec = oldsec;
++ sdyn = newdyn;
++ nsdyn = olddyn;
++ sdef = newdef;
++ nsdef = olddef;
++ }
++
++ if (sdef && !sdyn)
++ {
++ /* If the sharable definition comes from a relocatable
++ file, it will override the non-sharable one in DSO. */
++ return TRUE;
++ }
++ else if (!nsdef
++ && !nsdyn
++ && (h->root.type == bfd_link_hash_common
++ || bfd_is_com_section (nssec)))
++ {
++ asection *scomm;
++
++ /* When the non-sharable common symbol in a relocatable
++ file, we can turn it into sharable. If the sharable
++ symbol isn't common, the non-sharable common symbol
++ will be overidden. We only need to handle the
++ sharable common symbol and the non-sharable common
++ symbol. We just turn the non-sharable common symbol
++ into the sharable one. */
++ if (sym->st_shndx == SHN_GNU_SHARABLE_COMMON)
++ {
++ scomm = get_sharable_common_section (oldbfd);
++ if (scomm == NULL)
++ return FALSE;
++ h->root.u.c.p->section = scomm;
++ }
++ else
++ {
++ scomm = get_sharable_common_section (abfd);
++ if (scomm == NULL)
++ return FALSE;
++ *psec = scomm;
++ }
++
++ return TRUE;
++ }
++
++ (*_bfd_error_handler)
++ (_("%s: sharable symbol in %B section %A mismatches non-shrable symbol in %B section %A"),
++ sbfd, ssec, nsbfd, nssec, h->root.root.string);
++ bfd_set_error (bfd_error_bad_value);
++ return FALSE;
++ }
++ }
++
++ return TRUE;
++}
+diff --git a/bfd/elfnn-ia64.c b/bfd/elfnn-ia64.c
+index a8d8d0b..02420ec 100644
+--- a/bfd/elfnn-ia64.c
++++ b/bfd/elfnn-ia64.c
+@@ -1055,7 +1055,8 @@ elfNN_ia64_add_symbol_hook (bfd *abfd,
+ *valp = sym->st_size;
+ }
+
+- return TRUE;
++ return _bfd_elf_add_sharable_symbol (abfd, info, sym, namep, flagsp,
++ secp, valp);
+ }
+
+ /* Return the number of additional phdrs we will need. */
+@@ -5068,6 +5069,19 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ #define elf_backend_special_sections elfNN_ia64_special_sections
+ #define elf_backend_default_execstack 0
+
++#define elf_backend_section_from_bfd_section \
++ _bfd_elf_sharable_section_from_bfd_section
++#define elf_backend_symbol_processing \
++ _bfd_elf_sharable_symbol_processing
++#define elf_backend_common_section_index \
++ _bfd_elf_sharable_common_section_index
++#define elf_backend_common_section \
++ _bfd_elf_sharable_common_section
++#define elf_backend_common_definition \
++ _bfd_elf_sharable_common_definition
++#define elf_backend_merge_symbol \
++ _bfd_elf_sharable_merge_symbol
++
+ /* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with
+ SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields.
+ We don't want to flood users with so many error messages. We turn
+diff --git a/binutils/readelf.c b/binutils/readelf.c
+index d9ddb35..67adbb7 100644
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -1538,6 +1538,8 @@ dump_relocations (FILE * file,
+ sec_name = "ABS";
+ else if (psym->st_shndx == SHN_COMMON)
+ sec_name = "COMMON";
++ else if (psym->st_shndx == SHN_GNU_SHARABLE_COMMON)
++ sec_name = "GNU_SHARABLE_COMMON";
+ else if ((elf_header.e_machine == EM_MIPS
+ && psym->st_shndx == SHN_MIPS_SCOMMON)
+ || (elf_header.e_machine == EM_TI_C6000
+@@ -3478,6 +3480,7 @@ get_segment_type (unsigned long p_type)
+ case PT_SHLIB: return "SHLIB";
+ case PT_PHDR: return "PHDR";
+ case PT_TLS: return "TLS";
++ case PT_GNU_SHR: return "GNU_SHR";
+
+ case PT_GNU_EH_FRAME:
+ return "GNU_EH_FRAME";
+@@ -9998,6 +10001,8 @@ get_symbol_index_type (unsigned int type)
+ case SHN_UNDEF: return "UND";
+ case SHN_ABS: return "ABS";
+ case SHN_COMMON: return "COM";
++ case SHN_GNU_SHARABLE_COMMON:
++ return "GNU_SHARABLE_COM";
+ default:
+ if (type == SHN_IA_64_ANSI_COMMON
+ && elf_header.e_machine == EM_IA_64
+diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
+index e2ef99e..d2b6f7b 100644
+--- a/gas/config/obj-elf.c
++++ b/gas/config/obj-elf.c
+@@ -76,6 +76,7 @@ static void obj_elf_subsection (int);
+ static void obj_elf_popsection (int);
+ static void obj_elf_gnu_attribute (int);
+ static void obj_elf_tls_common (int);
++static void obj_elf_sharable_common (int);
+ static void obj_elf_lcomm (int);
+ static void obj_elf_struct (int);
+
+@@ -136,6 +137,8 @@ static const pseudo_typeS elf_pseudo_table[] =
+
+ {"tls_common", obj_elf_tls_common, 0},
+
++ {"sharable_common", obj_elf_sharable_common, 0},
++
+ /* End sentinel. */
+ {NULL, NULL, 0},
+ };
+@@ -391,6 +394,39 @@ obj_elf_tls_common (int ignore ATTRIBUTE_UNUSED)
+ }
+
+ static void
++obj_elf_sharable_common (int ignore ATTRIBUTE_UNUSED)
++{
++ static segT sharable_bss_section;
++ asection *saved_com_section_ptr = elf_com_section_ptr;
++ asection *saved_bss_section = bss_section;
++
++ if (sharable_bss_section == NULL)
++ {
++ flagword applicable;
++ segT seg = now_seg;
++ subsegT subseg = now_subseg;
++
++ /* The .sharable_bss section is for local .sharable_common
++ symbols. */
++ sharable_bss_section = subseg_new (".sharable_bss", 0);
++ applicable = bfd_applicable_section_flags (stdoutput);
++ bfd_set_section_flags (stdoutput, sharable_bss_section,
++ applicable & SEC_ALLOC);
++ seg_info (sharable_bss_section)->bss = 1;
++
++ subseg_set (seg, subseg);
++ }
++
++ elf_com_section_ptr = &_bfd_elf_sharable_com_section;
++ bss_section = sharable_bss_section;
++
++ s_comm_internal (0, elf_common_parse);
++
++ elf_com_section_ptr = saved_com_section_ptr;
++ bss_section = saved_bss_section;
++}
++
++static void
+ obj_elf_lcomm (int ignore ATTRIBUTE_UNUSED)
+ {
+ symbolS *symbolP = s_comm_internal (0, s_lcomm_internal);
+@@ -609,11 +645,17 @@ obj_elf_change_section (const char *name,
+
+ .section .lbss,"aw",@progbits
+
++ "@progbits" is incorrect. Also for sharable bss
++ sections, gcc, as of 2005-07-06, will emit
++
++ .section .sharable_bss,"aw",@progbits
++
+ "@progbits" is incorrect. */
+ #ifdef TC_I386
+ && (bed->s->arch_size != 64
+ || !(ssect->attr & SHF_X86_64_LARGE))
+ #endif
++ && !(ssect->attr & SHF_GNU_SHARABLE)
+ && ssect->type != SHT_INIT_ARRAY
+ && ssect->type != SHT_FINI_ARRAY
+ && ssect->type != SHT_PREINIT_ARRAY)
+diff --git a/include/bfdlink.h b/include/bfdlink.h
+index f3181ba..f1bfaf2 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -396,6 +396,9 @@ struct bfd_link_info
+ --dynamic-list command line options. */
+ unsigned int dynamic: 1;
+
++ /* TRUE if sharables sections may be created. */
++ unsigned int sharable_sections: 1;
++
+ /* TRUE if PT_GNU_STACK segment should be created with PF_R|PF_W|PF_X
+ flags. */
+ unsigned int execstack: 1;
+diff --git a/include/elf/common.h b/include/elf/common.h
+index 1d68f80..b27021f 100644
+--- a/include/elf/common.h
++++ b/include/elf/common.h
+@@ -435,6 +435,7 @@
+ #define PT_SUNW_EH_FRAME PT_GNU_EH_FRAME /* Solaris uses the same value */
+ #define PT_GNU_STACK (PT_LOOS + 0x474e551) /* Stack flags */
+ #define PT_GNU_RELRO (PT_LOOS + 0x474e552) /* Read-only after relocation */
++#define PT_GNU_SHR (PT_LOOS + 0x474e554) /* Sharable segment */
+
+ /* Program segment permissions, in program header p_flags field. */
+
+@@ -517,6 +518,8 @@
+ are not to be further
+ relocated. */
+
++#define SHF_GNU_SHARABLE 0x01000000 /* sharable section */
++
+ /* Values of note segment descriptor types for core files. */
+
+ #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+@@ -686,6 +689,9 @@
+ #define STT_LOPROC 13 /* Processor-specific semantics */
+ #define STT_HIPROC 15 /* Processor-specific semantics */
+
++/* Associated symbol is in common sharable */
++#define SHN_GNU_SHARABLE_COMMON (SHN_LOOS + 10)
++
+ /* The following constants control how a symbol may be accessed once it has
+ become part of an executable or shared library. */
+
+diff --git a/ld/emulparams/elf32_x86_64.sh b/ld/emulparams/elf32_x86_64.sh
+index 11d17ad..012ca78 100644
+--- a/ld/emulparams/elf32_x86_64.sh
++++ b/ld/emulparams/elf32_x86_64.sh
+@@ -16,6 +16,7 @@ LARGE_SECTIONS=yes
+ LARGE_BSS_AFTER_BSS=
+ SEPARATE_GOTPLT="SIZEOF (.got.plt) >= 24 ? 24 : 0"
+ IREL_IN_PLT=
++SHARABLE_SECTIONS=yes
+
+ if [ "x${host}" = "x${target}" ]; then
+ case " $EMULATION_LIBPATH " in
+diff --git a/ld/emulparams/elf64_ia64.sh b/ld/emulparams/elf64_ia64.sh
+index 7e5e54d..d8cf531 100644
+--- a/ld/emulparams/elf64_ia64.sh
++++ b/ld/emulparams/elf64_ia64.sh
+@@ -37,3 +37,4 @@ OTHER_READONLY_SECTIONS="${OTHER_READONLY_SECTIONS}
+ # .dtors. They have to be next to .sbss/.sbss2/.sdata/.sdata2.
+ SMALL_DATA_CTOR=" "
+ SMALL_DATA_DTOR=" "
++SHARABLE_SECTIONS=yes
+diff --git a/ld/emulparams/elf_i386.sh b/ld/emulparams/elf_i386.sh
+index 2ebfaac..d1b8eb1 100644
+--- a/ld/emulparams/elf_i386.sh
++++ b/ld/emulparams/elf_i386.sh
+@@ -17,6 +17,7 @@ IREL_IN_PLT=
+ TINY_READONLY_SECTION="
+ .plt.got ${RELOCATING-0} : { *(.plt.got) }
+ "
++SHARABLE_SECTIONS=yes
+
+ # Linux modify the default library search path to first include
+ # a 32-bit specific directory.
+diff --git a/ld/emulparams/elf_x86_64.sh b/ld/emulparams/elf_x86_64.sh
+index aa26a1b..b33143a 100644
+--- a/ld/emulparams/elf_x86_64.sh
++++ b/ld/emulparams/elf_x86_64.sh
+@@ -21,6 +21,7 @@ TINY_READONLY_SECTION="
+ .plt.got ${RELOCATING-0} : { *(.plt.got) }
+ .plt.bnd ${RELOCATING-0} : { *(.plt.bnd) }
+ "
++SHARABLE_SECTIONS=yes
+
+ if [ "x${host}" = "x${target}" ]; then
+ case " $EMULATION_LIBPATH " in
+diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
+index 137446f..1d402e6 100644
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -102,6 +102,7 @@ gld${EMULATION_NAME}_before_parse (void)
+ input_flags.dynamic = ${DYNAMIC_LINK-TRUE};
+ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
+ config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
++ link_info.sharable_sections = `if test "$SHARABLE_SECTIONS" = "yes" ; then echo TRUE ; else echo FALSE ; fi`;
+ }
+
+ EOF
+@@ -1788,6 +1789,12 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
+ int iself = s->owner->xvec->flavour == bfd_target_elf_flavour;
+ unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL;
+
++ /* Orphaned sharable sections won't have correct page
++ requirements. */
++ if (elf_section_flags (s) & SHF_GNU_SHARABLE)
++ einfo ("%F%P: unable to place orphaned sharable section %A (%B)\n",
++ s, s->owner);
++
+ if (! link_info.relocatable
+ && link_info.combreloc
+ && (s->flags & SEC_ALLOC))
+diff --git a/ld/ldmain.c b/ld/ldmain.c
+index bc24957..4295ba7 100644
+--- a/ld/ldmain.c
++++ b/ld/ldmain.c
+@@ -289,6 +289,7 @@ main (int argc, char **argv)
+ link_info.pei386_auto_import = -1;
+ link_info.spare_dynamic_tags = 5;
+ link_info.path_separator = ':';
++ link_info.sharable_sections = FALSE;
+
+ ldfile_add_arch ("");
+ emulation = get_emulation (argc, argv);
+diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
+index 4368fd9..0904495 100644
+--- a/ld/scripttempl/elf.sc
++++ b/ld/scripttempl/elf.sc
+@@ -303,6 +303,40 @@ STACK=" .stack ${RELOCATING-0}${RELOCATING+${STACK_ADDR}} :
+ ${RELOCATING+${USER_LABEL_PREFIX}_stack = .;}
+ *(.stack)
+ }"
++test "${SHARABLE_SECTIONS}" = "yes" && OTHER_READWRITE_SECTIONS="
++ ${OTHER_READWRITE_SECTIONS}
++ /* Sharable data sections. */
++ .sharable_data ${RELOCATING-0} : ${RELOCATING+ALIGN(${MAXPAGESIZE})}
++ {
++ ${RELOCATING+PROVIDE_HIDDEN (__sharable_data_start = .);}
++ *(.sharable_data${RELOCATING+ .sharable_data.* .gnu.linkonce.shrd.*})
++ /* Align here to ensure that the sharable data section ends at the
++ page boundary. */
++ ${RELOCATING+. = ALIGN(. != 0 ? ${MAXPAGESIZE} : 1);}
++ ${RELOCATING+PROVIDE_HIDDEN (__sharable_data_end = .);}
++ }
++"
++test "${SHARABLE_SECTIONS}" = "yes" && OTHER_BSS_SECTIONS="
++ ${OTHER_BSS_SECTIONS}
++ /* Sharable bss sections */
++ .sharable_bss ${RELOCATING-0} : ${RELOCATING+ALIGN(${MAXPAGESIZE})}
++ {
++ ${RELOCATING+PROVIDE_HIDDEN (__sharable_bss_start = .);}
++ *(.dynsharablebss)
++ *(.sharable_bss${RELOCATING+ .sharable_bss.* .gnu.linkonce.shrb.*})
++ *(SHARABLE_COMMON)
++ /* Align here to ensure that the sharable bss section ends at the
++ page boundary. */
++ ${RELOCATING+. = ALIGN(. != 0 ? ${MAXPAGESIZE} : 1);}
++ ${RELOCATING+PROVIDE_HIDDEN (__sharable_bss_end = .);}
++ }
++"
++test "${SHARABLE_SECTIONS}" = "yes" && REL_SHARABLE="
++ .rel.sharable_data ${RELOCATING-0} : { *(.rel.sharable_data${RELOCATING+ .rel.sharable_data.* .rel.gnu.linkonce.shrd.*}) }
++ .rela.sharable_data ${RELOCATING-0} : { *(.rela.sharable_data${RELOCATING+ .rela.sharable_data.* .rela.gnu.linkonce.shrd.*}) }
++ .rel.sharable_bss ${RELOCATING-0} : { *(.rel.sharable_bss${RELOCATING+ .rel.sharable_bss.* .rel.gnu.linkonce.shrb.*}) }
++ .rela.sharable_bss ${RELOCATING-0} : { *(.rela.sharable_bss${RELOCATING+ .rela.sharable_bss.* .rela.gnu.linkonce.shrb.*}) }
++"
+
+ TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${TEXT_START_ADDR})"
+ SHLIB_TEXT_START_ADDR="SEGMENT_START(\"text-segment\", ${SHLIB_TEXT_START_ADDR:-0})"
+@@ -403,6 +437,7 @@ eval $COMBRELOCCAT <<EOF
+ .rel.got ${RELOCATING-0} : { *(.rel.got) }
+ .rela.got ${RELOCATING-0} : { *(.rela.got) }
+ ${OTHER_GOT_RELOC_SECTIONS}
++ ${REL_SHARABLE}
+ ${REL_SDATA}
+ ${REL_SBSS}
+ ${REL_SDATA2}