Subject: [alpine-aports] [PATCH] main/binutils: fix -static-pie generation on mips*

From: alpine-mips-patches <[email-masked]>
Date: Wed, 19 Dec 2018 07:44:46 +0000

This is upstream PR ld/21375.

Only mips-specific files are changed by the main patch and prereq-2
so these are safe for other architectures. And prereq-1 adds single
bit-field in the common code so should be safe too.

This commit assumes -static-pie handling fix for main/gcc.
---
 main/binutils/APKBUILD                   |  10 +-
 main/binutils/PR-ld-21375-prereq-1.patch | 117 ++++
 main/binutils/PR-ld-21375-prereq-2.patch |  59 ++
 main/binutils/PR-ld-21375.patch          | 765 +++++++++++++++++++++++
 4 files changed, 949 insertions(+), 2 deletions(-)
 create mode 100644 main/binutils/PR-ld-21375-prereq-1.patch
 create mode 100644 main/binutils/PR-ld-21375-prereq-2.patch
 create mode 100644 main/binutils/PR-ld-21375.patch

diff --git a/main/binutils/APKBUILD b/main/binutils/APKBUILD
index add96323a4..2ac56f3606 100644
--- a/main/binutils/APKBUILD
+++ b/main/binutils/APKBUILD
@@ -1,7 +1,7 @@
 # Maintainer: Natanael Copa <[email-masked]>
 pkgname=binutils
 pkgver=2.31.1
-pkgrel=1
+pkgrel=2
 pkgdesc="Tools necessary to build programs"
 url="https://www.gnu.org/software/binutils/"
 depends=""
@@ -17,6 +17,9 @@ source="https://ftp.gnu.org/gnu/$pkgname/$pkgname-$pkgver.tar.bz2
 	x86-Properly-add-X86_ISA_1_NEEDED-property.patch
 	binutils-ld-fix-static-linking.patch
 	gold-mips.patch
+	PR-ld-21375-prereq-1.patch
+	PR-ld-21375-prereq-2.patch
+	PR-ld-21375.patch
 	"
 builddir="$srcdir/$pkgname-$pkgver"
 
@@ -114,4 +117,7 @@ d95fd77e1c2c4670a2a11979d6811b358ba0f067b917b33d241eca20cfe66553f6a6fccc5ec26d8d
 ce5d3c935057d624c1ce75722e7b5e4583812d46797edce8c381a94b2643f44f7bd0165e7e9b8e358955f4d979074ee487598efbf24389a4013681f99ff7c595  x86-Properly-merge-GNU_PROPERTY_X86_ISA_1_USED.patch
 1878bed194529afb2430af21ba9712d6819c5fdfdc5c8db652175bf86d0a0c710ac2bd3ec728bf874887301bd187d91bf60a374c47850c7bd2eafbf6653d74d8  x86-Properly-add-X86_ISA_1_NEEDED-property.patch
 ecee33b0e435aa704af1c334e560f201638ff79e199aa11ed78a72f7c9b46f85fbb227af5748e735fd681d1965fcc42ac81b0c8824e540430ce0c706c81e8b49  binutils-ld-fix-static-linking.patch
-f55cf2e0bf82f97583a1abe10710e4013ecf7d64f1da2ef8659a44a06d0dd8beaf58dab98a183488ea137f03e32d62efc878d95f018f836f8cec870bc448556f  gold-mips.patch"
+f55cf2e0bf82f97583a1abe10710e4013ecf7d64f1da2ef8659a44a06d0dd8beaf58dab98a183488ea137f03e32d62efc878d95f018f836f8cec870bc448556f  gold-mips.patch
+a2a3b5d6fa6dce9462fcdf80ff075c13e3b97b128b3bbeac35ea5d726bdd727e5f3c57d97f1139f2380d282b93b96c9f277a9bca63917a12153080bacff5cca0  PR-ld-21375-prereq-1.patch
+6c7db5732777199edb618c8e913799df669d87a5021f3e468b467455ef5de6dc0f008a227cf3b36288c16a7e0a07b641ee75eb86665131269ee475e6c8e2bf0e  PR-ld-21375-prereq-2.patch
+65b8a5d5933b976475e7c972789032ab120016c30d6fcab8d2dfce4293135ad377d4096a2b6d9f45660b70a68ec1bd99ca7606e5fc14a7a7f9933fb3ca611ade  PR-ld-21375.patch"
diff --git a/main/binutils/PR-ld-21375-prereq-1.patch b/main/binutils/PR-ld-21375-prereq-1.patch
new file mode 100644
index 0000000000..c59fc4ea89
--- /dev/null
+++ b/main/binutils/PR-ld-21375-prereq-1.patch
@@ -0,0 +1,117 @@
+commit d5c928c05356b22af08450bf43b262ccc1b1d8ee
+Author: Maciej W. Rozycki <[email-masked]>
+Date:   Tue Jul 17 20:04:53 2018 +0100
+
+    LD: Export relative-from-absolute symbol marking to BFD
+    
+    It is usually possible to tell absolute and ordinary symbols apart in
+    BFD throughout the link, by checking whether the section that owns the
+    symbol is absolute or not.
+    
+    That however does not work for ordinary symbols defined in a linker
+    script outside an output section statement.  Initially such symbols are
+    entered into to the link hash as absolute symbols, owned by the absolute
+    section.  A flag is set in the internal linker expression defining such
+    symbols to tell the linker to convert them to section-relative ones in
+    the final phase of the link.  That flag is however not accessible to BFD
+    linker code, including BFD target code in particular.
+    
+    Add a flag to the link hash then to copy the information held in the
+    linker expression.  Define a macro, `bfd_is_abs_symbol', for BFD code to
+    use where determining whether a symbol is absolute or ordinary is
+    required before the final link phase.
+    
+    This macro will correctly identify the special `__ehdr_start' symbol as
+    ordinary throughout link, for example, even though early on it will be
+    assigned to the absolute section.  Of course this does not let BFD code
+    identify what the symbol's ultimate section will be before the final
+    link phase has converted this symbol (in `update_definedness').
+    
+            include/
+            * bfdlink.h (bfd_link_hash_entry): Add `rel_from_abs' member.
+    
+            bfd/
+            * linker.c (bfd_is_abs_symbol): New macro.
+            * bfd-in2.h: Regenerate.
+    
+            ld/
+            * ldexp.c (exp_fold_tree_1) <etree_assign, etree_provide>
+            <etree_provided>: Copy expression's `rel_from_abs' flag to the
+            link hash.
+
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index 93745bd3fd..3414682988 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -7802,6 +7802,17 @@ bfd_boolean bfd_set_format (bfd *abfd, bfd_format format);
+ const char *bfd_format_string (bfd_format format);
+ 
+ /* Extracted from linker.c.  */
++/* Return TRUE if the symbol described by a linker hash entry H
++   is going to be absolute.  Linker-script defined symbols can be
++   converted from absolute to section-relative ones late in the
++   link.  Use this macro to correctly determine whether the symbol
++   will actually end up absolute in output.  */
++#define bfd_is_abs_symbol(H) \
++  (((H)->type == bfd_link_hash_defined \
++    || (H)->type == bfd_link_hash_defweak) \
++   && bfd_is_abs_section ((H)->u.def.section) \
++   && !(H)->rel_from_abs)
++
+ bfd_boolean bfd_link_split_section (bfd *abfd, asection *sec);
+ 
+ #define bfd_link_split_section(abfd, sec) \
+diff --git a/bfd/linker.c b/bfd/linker.c
+index 6b4c8e57e1..9fee90d101 100644
+--- a/bfd/linker.c
++++ b/bfd/linker.c
+@@ -484,7 +484,20 @@ _bfd_link_hash_table_init
+ 
+ /* Look up a symbol in a link hash table.  If follow is TRUE, we
+    follow bfd_link_hash_indirect and bfd_link_hash_warning links to
+-   the real symbol.  */
++   the real symbol.
++
++.{* Return TRUE if the symbol described by a linker hash entry H
++.   is going to be absolute.  Linker-script defined symbols can be
++.   converted from absolute to section-relative ones late in the
++.   link.  Use this macro to correctly determine whether the symbol
++.   will actually end up absolute in output.  *}
++.#define bfd_is_abs_symbol(H) \
++.  (((H)->type == bfd_link_hash_defined \
++.    || (H)->type == bfd_link_hash_defweak) \
++.   && bfd_is_abs_section ((H)->u.def.section) \
++.   && !(H)->rel_from_abs)
++.
++*/
+ 
+ struct bfd_link_hash_entry *
+ bfd_link_hash_lookup (struct bfd_link_hash_table *table,
+diff --git a/include/bfdlink.h b/include/bfdlink.h
+index 773407f861..249108132c 100644
+--- a/include/bfdlink.h
++++ b/include/bfdlink.h
+@@ -115,6 +115,11 @@ struct bfd_link_hash_entry
+   /* Symbol defined in a linker script.  */
+   unsigned int ldscript_def : 1;
+ 
++  /* Symbol will be converted from absolute to section-relative.  Set for
++     symbols defined by a script from "dot" (also SEGMENT_START or ORIGIN)
++     outside of an output section statement.  */
++  unsigned int rel_from_abs : 1;
++
+   /* A union of information depending upon the type.  */
+   union
+     {
+diff --git a/ld/ldexp.c b/ld/ldexp.c
+index 6fa251e79e..4ca812e9b2 100644
+--- a/ld/ldexp.c
++++ b/ld/ldexp.c
+@@ -1200,6 +1200,7 @@ exp_fold_tree_1 (etree_type *tree)
+ 		  h->u.def.section = expld.result.section;
+ 		  h->linker_def = ! tree->assign.type.lineno;
+ 		  h->ldscript_def = 1;
++		  h->rel_from_abs = expld.rel_from_abs;
+ 		  if (tree->assign.hidden)
+ 		    bfd_link_hide_symbol (link_info.output_bfd,
+ 					  &link_info, h);
diff --git a/main/binutils/PR-ld-21375-prereq-2.patch b/main/binutils/PR-ld-21375-prereq-2.patch
new file mode 100644
index 0000000000..a55fa80da7
--- /dev/null
+++ b/main/binutils/PR-ld-21375-prereq-2.patch
@@ -0,0 +1,59 @@
+commit 98e10ffadbeb42c5adef14c1d5dd4093d57d57a1
+Author: Maciej W. Rozycki <[email-masked]>
+Date:   Fri Sep 14 20:22:56 2018 +0100
+
+    MIPS/BFD: Factor out relocated field storing
+    
+    Move code used to store the contents of a relocated field in output into
+    a separate function, `mips_elf_store_contents', complementing existing
+    `mips_elf_obtain_contents'.
+    
+            bfd/
+            * elfxx-mips.c (mips_elf_store_contents): New function...
+            (mips_elf_perform_relocation): ... factored out from here.
+
+diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
+index 14621cd09e..0573e93394 100644
+--- a/bfd/elfxx-mips.c
++++ b/bfd/elfxx-mips.c
+@@ -5234,6 +5234,21 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
+     }
+ }
+ 
++/* Store the field relocated by RELOCATION.  */
++
++static void
++mips_elf_store_contents (reloc_howto_type *howto,
++			 const Elf_Internal_Rela *relocation,
++			 bfd *input_bfd, bfd_byte *contents, bfd_vma x)
++{
++  bfd_byte *location = contents + relocation->r_offset;
++  unsigned int size = bfd_get_reloc_size (howto);
++
++  /* Put the value into the output.  */
++  if (size != 0)
++    bfd_put (8 * size, input_bfd, x, location);
++}
++
+ /* Calculate the value produced by the RELOCATION (which comes from
+    the INPUT_BFD).  The ADDEND is the addend to use for this
+    RELOCATION; RELOCATION->R_ADDEND is ignored.
+@@ -6346,7 +6361,6 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
+   bfd_vma x;
+   bfd_byte *location;
+   int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+-  unsigned int size;
+ 
+   /* Figure out where the relocation is occurring.  */
+   location = contents + relocation->r_offset;
+@@ -6505,9 +6519,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
+     }
+ 
+   /* Put the value into the output.  */
+-  size = bfd_get_reloc_size (howto);
+-  if (size != 0)
+-    bfd_put (8 * size, input_bfd, x, location);
++  mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+ 
+   _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
+ 			       location);
diff --git a/main/binutils/PR-ld-21375.patch b/main/binutils/PR-ld-21375.patch
new file mode 100644
index 0000000000..010244abc4
--- /dev/null
+++ b/main/binutils/PR-ld-21375.patch
@@ -0,0 +1,765 @@
+commit 47275900adcda29161e2853179c1fbde4da4c86a
+Author: Maciej W. Rozycki <[email-masked]>
+Date:   Fri Sep 14 20:22:56 2018 +0100
+
+    PR ld/21375: MIPS: Fix non-zero run-time value for undefined weaks
+    
+    We have an issue in the MIPS backend, with the handling of undefined
+    hidden and internal weak symbols.  References to such symbols are
+    supposed to resolve to 0 according to the ELF gABI[1]:
+    
+    "Unresolved weak symbols have a zero value."
+    
+    and the 64-bit MIPS psABI[2]:
+    
+    "If a symbol with one of these [hidden or internal] attributes has no
+    definition within the executable/DSO being linked, then it must be
+    resolved to allocated space if common, resolved to zero if weak, or an
+    error reported otherwise."
+    
+    however if a GOT relocation is used, then a local GOT entry is created
+    and used to satisfy the reference.  Such an entry is then (in DSO and
+    PIE binaries) subject to the usual load-time relocation, which means a
+    non-zero value will be returned if the base address is non-zero.  This
+    will defeat the usual run-time sequence like:
+    
+    void a (void) __attribute__ ((visibility ("hidden"), weak));
+    
+    void
+    x (void)
+    {
+      if (a)
+        a ();
+    }
+    
+    This can be reproduced with this simple code:
+    
+    $ cat libtest.c
+    extern int a __attribute__ ((visibility ("hidden"), weak));
+    
+    int *
+    x (void)
+    {
+      return &a;
+    }
+    $ cat test.c
+    
+    int *x (void);
+    
+    int
+    main (void)
+    {
+      printf ("a: %p\n", x ());
+    
+      return 0;
+    }
+    $ gcc -shared -fPIC -o libtest.so libtest.c
+    $ gcc -o test test.c -Wl,-rpath,$(pwd) libtest.so
+    $ ./test
+    a: 0x77184000
+    $
+    
+    The usual approach targets take is making all the steps required to
+    assign a GOT entry for the symbol referred, and then leave its contents
+    at zero with no dynamic relocation attached, therefore ensuring that the
+    value does not change at load time.  However this is not going to work
+    with the implicitly relocated GOT the MIPS psABI specifies[3]:
+    
+    "The dynamic linker relocates the global offset table by first adding
+    the difference between the base where the shared object is loaded and
+    the value of the dynamic tag DT_MIPS_BASE_ADDRESS to all local global
+    offset table entries."
+    
+    and we cannot therefore use the local GOT part.
+    
+    And we cannot offhand use the global part either, as the symbol would
+    then have to be exported and possibly wrongly preempt symbols in other
+    modules involved in the dynamic load, because as per the ELF gABI[1] we
+    are not allowed to enter a hidden or internal symbol into the dynamic
+    symbol table (and then use its associated GOT entry):
+    
+    "A hidden symbol contained in a relocatable object must be either
+    removed or converted to STB_LOCAL binding by the link-editor when the
+    relocatable object is included in an executable file or shared object."
+    
+    and:
+    
+    "An internal symbol contained in a relocatable object must be either
+    removed or converted to STB_LOCAL binding by the link-editor when the
+    relocatable object is included in an executable file or shared object."
+    
+    So we have to choose something else.
+    
+    Our choice is further limited by the need for the reference associated
+    with the GOT relocation to stay within the signed 16-bit limit from the
+    GOT pointer base register, while being compliant with the ELF gABI and
+    the MIPS psABI.  However as Alan Modra has observed[4] one possibility
+    is to edit (relax) the code such that the GOT reference is removed
+    altogether.
+    
+    Based on these observations then modify MIPS BFD linker backend code to:
+    
+    1. Interpret code associated with GOT relocations and relax the usual LW
+       or LD instructions into a corresponding immediate load operation that
+       places the value of 0 in the intended register, while leaving the GOT
+       entry allocated and initialized as usually.
+    
+    2. Leave any other instructions associated with GOT relocations in place
+       and instead redirect the reference to a global GOT entry associated
+       with a special `__gnu_absolute_zero' symbol created for this purpose,
+       whose value is 0, SHN_ABS section marks it absolute, binding is
+       global and export class protected, ensuring that the locally provided
+       value is always used at load time, and that the value is not
+       relocated by the dynamic loader.
+    
+    3. Adjust any high-part GOT relocation used, typically associated with
+       a LUI instruction, accordingly, so that run-time consistency is
+       maintained, either by resolving to the original entry if the
+       instruction associated with the corresponding low-part GOT relocation
+       has been relaxed to an immediate load (in which case the value loaded
+       with LUI will be overwritten), or by also redirecting the reference
+       to `__gnu_absolute_zero' to complete the GOT access sequence if that
+       symbol has been used.
+    
+    4. Add a target `elf_backend_hide_symbol' hook, for the three MIPS ABIs,
+       which prevents the `__gnu_absolute_zero' symbol from being forced
+       local, to ensure that the redirection works and the symbol remains
+       global/protected with existing linker scripts unchanged.
+    
+    5. Observing the issue with handling SHN_ABS symbols in the GNU dynamic
+       loader, covered by glibc PR 19818, set the EI_ABIVERSION field in the
+       ELF file header produced to 4 (ABI_ABSOLUTE) if `__gnu_absolute_zero'
+       symbol has been produced and the target configured indicates the GNU
+       operating system, so that broken versions of the GNU dynamic loader
+       gracefully reject the file in loading rather than going astray.  Keep
+       EI_ABIVERSION at the original value for other operating systems or if
+       no `__gnu_absolute_zero' symbol has been made.
+    
+    The name of the special `__gnu_absolute_zero' has no meaning other than
+    how a human reader can interpret it, as it is ignored in dynamic loading
+    in the handling of the scenarios concerned.  This is because the symbol
+    resolves locally, and it's only the symbol's attributes that matter so
+    that the associated GOT entry remains unchanged at load time.
+    
+    Therefore the name is somewhat arbitrary, observing however the need to
+    use the name space reserved for the system so that it does not conflict
+    with a possible user symbol, and hence the leading underscore, and also
+    the `gnu' infix to denote a GNU feature.  Other implementations wishing
+    to address the problem in a similar way may choose a different name and
+    have the solution still work, possibly with a mixture of modules used in
+    a dynamic having symbols of different names provided, which will however
+    not interact with each other due to the protected export class.
+    
+    The symbol can be referred explicitly, however the name is an internal
+    implementation detail rather than a part of the ABI, and therefore no
+    specific semantics is guaranteed.
+    
+    One limitation of this change is that if `__gnu_absolute_zero' has been
+    already defined, then we do not wipe the old definition and all kinds of
+    odd behavior can result.  This is however like with other symbols we
+    internally define, such as `_GLOBAL_OFFSET_TABLE_' or `__rld_map', and
+    therefore left as a possible future enhancement.
+    
+    As an optimization the relaxation of LW and LD instructions to a load of
+    immediate zero is always made, even SVR4 PIC code for code that will end
+    up in a regular (non-PIE) executable, because there is a cache advantage
+    with the avoidance of a load from the GOT, even if it is otherwise
+    guaranteed to remain zero.  It does not reliably happen though, due to a
+    symbol exportation issue affecting executables, covered by PR ld/21805.
+    
+    One existing test case needs to be updated, as it triggers relaxation
+    introduced with this change and consequently linker output does not
+    match expectations anymore.  As we want to keep the original issue
+    covered with the test case modify it then to use the LWL instruction in
+    place of LW, and adjust the output expected accordingly.
+    
+    References:
+    
+    [1] "System V Application Binary Interface - DRAFT - 19 October 2010",
+        The SCO Group, Section "Symbol Table",
+        <http://www.sco.com/developers/gabi/2012-12-31/ch4.symtab.html>
+    
+    [2] "64-bit ELF Object File Specification, Draft Version 2.5", MIPS
+        Technologies / Silicon Graphics Computer Systems, Order Number
+        007-4658-001, Section 2.5 "Symbol Table", p. 22,
+        <http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf>
+    
+    [3] "SYSTEM V APPLICATION BINARY INTERFACE, MIPS RISC Processor
+        Supplement, 3rd Edition", Section "Global Offset Table", p. 5-10,
+        <http://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf>
+    
+    [4] "Undo dynamic symbol state after regular object sym type mismatch",
+        <https://sourceware.org/ml/binutils/2017-07/msg00265.html>
+    
+            bfd/
+            PR ld/21375
+            * elfxx-mips.h (_bfd_mips_elf_hide_symbol): New prototype.
+            (_bfd_mips_elf_linker_flags): Update prototype.
+            * elf32-mips.c (elf_backend_hide_symbol): New macro.
+            * elf64-mips.c (elf_backend_hide_symbol): Likewise.
+            * elfn32-mips.c (elf_backend_hide_symbol): Likewise.
+            * elfxx-mips.c (mips_elf_link_hash_table): Add
+            `use_absolute_zero' and `gnu_target' members.
+            (mips_elf_record_global_got_symbol): Call
+            `_bfd_mips_elf_hide_symbol' rather than
+            `_bfd_elf_link_hash_hide_symbol'.
+            (mips_use_local_got_p): Return FALSE if the symbol is absolute.
+            (mips_elf_obtain_contents): Reorder function.
+            (mips_elf_nullify_got_load): New function.
+            (mips_elf_calculate_relocation): Add `contents' parameter.
+            Nullify GOT loads or if it is not possible, then redirect GOT
+            relocations to the `__gnu_absolute_zero' symbol, for references
+            that are supposed to resolve to zero.
+            (mips_elf_define_absolute_zero): New function.
+            (_bfd_mips_elf_check_relocs): Prepare for arrangements made in
+            `mips_elf_calculate_relocation' for references made via the GOT
+            that are supposed to resolve to zero.
+            (_bfd_mips_elf_hide_symbol): New function.
+            (_bfd_mips_elf_linker_flags): Add the `gnu_target' parameter,
+            set the `gnu_target' member of the MIPS hash table.
+            (MIPS_LIBC_ABI_ABSOLUTE): New enumeration constant.
+            (_bfd_mips_post_process_headers): Use it.
+    
+            ld/
+            PR ld/21375
+            * emultempl/mipself.em: Set `gnu_target' according to ${target}.
+            (mips_create_output_section_statements): Update call to
+            `_bfd_mips_elf_linker_flags'.
+            * testsuite/ld-mips-elf/pr21334.s: Use LWL rather than LW.
+            * testsuite/ld-mips-elf/pr21334.dd: Update accordingly.
+
+diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
+index 23a5712d46..b085744f00 100644
+--- a/bfd/elf32-mips.c
++++ b/bfd/elf32-mips.c
+@@ -2534,6 +2534,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
+ #define elf_backend_gc_mark_hook	_bfd_mips_elf_gc_mark_hook
+ #define elf_backend_copy_indirect_symbol \
+ 					_bfd_mips_elf_copy_indirect_symbol
++#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
+ #define elf_backend_fixup_symbol	elf32_mips_fixup_symbol
+ #define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
+ #define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
+diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
+index 7c9916f67f..ebf16bb1f1 100644
+--- a/bfd/elf64-mips.c
++++ b/bfd/elf64-mips.c
+@@ -4772,6 +4772,7 @@ const struct elf_size_info mips_elf64_size_info =
+ #define elf_backend_gc_mark_hook	_bfd_mips_elf_gc_mark_hook
+ #define elf_backend_copy_indirect_symbol \
+ 					_bfd_mips_elf_copy_indirect_symbol
++#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
+ #define elf_backend_ignore_discarded_relocs \
+ 					_bfd_mips_elf_ignore_discarded_relocs
+ #define elf_backend_mips_irix_compat	elf64_mips_irix_compat
+diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
+index 10e10bfcd7..0b68a5d058 100644
+--- a/bfd/elfn32-mips.c
++++ b/bfd/elfn32-mips.c
+@@ -4136,6 +4136,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
+ #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
+ #define elf_backend_copy_indirect_symbol \
+ 					_bfd_mips_elf_copy_indirect_symbol
++#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
+ #define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
+ #define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
+ #define elf_backend_grok_freebsd_prstatus \
+diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
+index 0573e93394..dfb3601406 100644
+--- a/bfd/elfxx-mips.c
++++ b/bfd/elfxx-mips.c
+@@ -455,6 +455,12 @@ struct mips_elf_link_hash_table
+   /* True if we already reported the small-data section overflow.  */
+   bfd_boolean small_data_overflow_reported;
+ 
++  /* True if we use the special `__gnu_absolute_zero' symbol.  */
++  bfd_boolean use_absolute_zero;
++
++  /* True if we have been configured for a GNU target.  */
++  bfd_boolean gnu_target;
++
+   /* Shortcuts to some dynamic sections, or NULL if they are not
+      being used.  */
+   asection *srelplt2;
+@@ -3977,7 +3983,7 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
+ 	{
+ 	case STV_INTERNAL:
+ 	case STV_HIDDEN:
+-	  _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
++	  _bfd_mips_elf_hide_symbol (info, h, TRUE);
+ 	  break;
+ 	}
+       if (!bfd_elf_link_record_dynamic_symbol (info, h))
+@@ -4434,6 +4440,12 @@ mips_use_local_got_p (struct bfd_link_info *info,
+   if (h->root.dynindx == -1)
+     return TRUE;
+ 
++  /* Absolute symbols, if ever they need a GOT entry, cannot ever go
++     to the local GOT, as they would be implicitly relocated by the
++     base address by the dynamic loader.  */
++  if (bfd_is_abs_symbol (&h->root.root))
++    return FALSE;
++
+   /* Symbols that bind locally can (and in the case of forced-local
+      symbols, must) live in the local GOT.  */
+   if (h->got_only_for_calls
+@@ -5234,6 +5246,24 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
+     }
+ }
+ 
++/* Obtain the field relocated by RELOCATION.  */
++
++static bfd_vma
++mips_elf_obtain_contents (reloc_howto_type *howto,
++			  const Elf_Internal_Rela *relocation,
++			  bfd *input_bfd, bfd_byte *contents)
++{
++  bfd_vma x = 0;
++  bfd_byte *location = contents + relocation->r_offset;
++  unsigned int size = bfd_get_reloc_size (howto);
++
++  /* Obtain the bytes.  */
++  if (size != 0)
++    x = bfd_get (8 * size, input_bfd, location);
++
++  return x;
++}
++
+ /* Store the field relocated by RELOCATION.  */
+ 
+ static void
+@@ -5249,6 +5279,52 @@ mips_elf_store_contents (reloc_howto_type *howto,
+     bfd_put (8 * size, input_bfd, x, location);
+ }
+ 
++/* Try to patch a load from GOT instruction in CONTENTS pointed to by
++   RELOCATION described by HOWTO, with a move of 0 to the load target
++   register, returning TRUE if that is successful and FALSE otherwise.
++   If DOIT is FALSE, then only determine it patching is possible and
++   return status without actually changing CONTENTS.
++*/
++
++static bfd_boolean
++mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
++			   const Elf_Internal_Rela *relocation,
++			   reloc_howto_type *howto, bfd_boolean doit)
++{
++  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
++  bfd_byte *location = contents + relocation->r_offset;
++  bfd_boolean nullified = TRUE;
++  bfd_vma x;
++
++  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
++
++  /* Obtain the current value.  */
++  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
++
++  /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
++     while RY is at bits [18:16] of the combined 32-bit instruction word.  */
++  if (mips16_reloc_p (r_type)
++      && (((x >> 22) & 0x3ff) == 0x3d3				/* LW */
++	  || ((x >> 22) & 0x3ff) == 0x3c7))			/* LD */
++    x = (0x3cd << 22) | (x & (7 << 16)) << 3;			/* LI */
++  else if (micromips_reloc_p (r_type)
++	   && ((x >> 26) & 0x37) == 0x37)			/* LW/LD */
++    x = (0xc << 26) | (x & (0x1f << 21));			/* ADDIU */
++  else if (((x >> 26) & 0x3f) == 0x23				/* LW */
++	   || ((x >> 26) & 0x3f) == 0x37)			/* LD */
++    x = (0x9 << 26) | (x & (0x1f << 16));			/* ADDIU */
++  else
++    nullified = FALSE;
++
++  /* Put the value into the output.  */
++  if (doit && nullified)
++    mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
++
++  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, FALSE, location);
++
++  return nullified;
++}
++
+ /* Calculate the value produced by the RELOCATION (which comes from
+    the INPUT_BFD).  The ADDEND is the addend to use for this
+    RELOCATION; RELOCATION->R_ADDEND is ignored.
+@@ -5264,7 +5340,7 @@ mips_elf_store_contents (reloc_howto_type *howto,
+ 
+ static bfd_reloc_status_type
+ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
+-			       asection *input_section,
++			       asection *input_section, bfd_byte *contents,
+ 			       struct bfd_link_info *info,
+ 			       const Elf_Internal_Rela *relocation,
+ 			       bfd_vma addend, reloc_howto_type *howto,
+@@ -5660,6 +5736,48 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
+ 				&& (target_is_16_bit_code_p
+ 				    || target_is_micromips_code_p))));
+ 
++  resolved_to_zero = (h != NULL
++		      && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
++
++  switch (r_type)
++    {
++    case R_MIPS16_CALL16:
++    case R_MIPS16_GOT16:
++    case R_MIPS_CALL16:
++    case R_MIPS_GOT16:
++    case R_MIPS_GOT_PAGE:
++    case R_MIPS_GOT_DISP:
++    case R_MIPS_GOT_LO16:
++    case R_MIPS_CALL_LO16:
++    case R_MICROMIPS_CALL16:
++    case R_MICROMIPS_GOT16:
++    case R_MICROMIPS_GOT_PAGE:
++    case R_MICROMIPS_GOT_DISP:
++    case R_MICROMIPS_GOT_LO16:
++    case R_MICROMIPS_CALL_LO16:
++      if (resolved_to_zero
++	  && !bfd_link_relocatable (info)
++	  && mips_elf_nullify_got_load (input_bfd, contents,
++					relocation, howto, TRUE))
++	return bfd_reloc_continue;
++
++      /* Fall through.  */
++    case R_MIPS_GOT_HI16:
++    case R_MIPS_CALL_HI16:
++    case R_MICROMIPS_GOT_HI16:
++    case R_MICROMIPS_CALL_HI16:
++      if (resolved_to_zero
++	  && htab->use_absolute_zero
++	  && bfd_link_pic (info))
++	{
++	  /* Redirect to the special `__gnu_absolute_zero' symbol.  */
++	  h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
++					 FALSE, FALSE, FALSE);
++	  BFD_ASSERT (h != NULL);
++	}
++      break;
++    }
++
+   local_p = (h == NULL || mips_use_local_got_p (info, h));
+ 
+   gp0 = _bfd_get_gp_value (input_bfd);
+@@ -5680,10 +5798,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
+       addend = 0;
+     }
+ 
+-  resolved_to_zero = (h != NULL
+-		      && UNDEFWEAK_NO_DYNAMIC_RELOC (info,
+-							  &h->root));
+-
+   /* If we haven't already determined the GOT offset, and we're going
+      to need it, get it now.  */
+   switch (r_type)
+@@ -6323,24 +6437,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
+   return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
+ }
+ 
+-/* Obtain the field relocated by RELOCATION.  */
+-
+-static bfd_vma
+-mips_elf_obtain_contents (reloc_howto_type *howto,
+-			  const Elf_Internal_Rela *relocation,
+-			  bfd *input_bfd, bfd_byte *contents)
+-{
+-  bfd_vma x = 0;
+-  bfd_byte *location = contents + relocation->r_offset;
+-  unsigned int size = bfd_get_reloc_size (howto);
+-
+-  /* Obtain the bytes.  */
+-  if (size != 0)
+-    x = bfd_get (8 * size, input_bfd, location);
+-
+-  return x;
+-}
+-
+ /* It has been determined that the result of the RELOCATION is the
+    VALUE.  Use HOWTO to place VALUE into the output file at the
+    appropriate position.  The SECTION is the section to which the
+@@ -8109,6 +8205,47 @@ mips_elf_make_plt_record (bfd *abfd)
+   return entry;
+ }
+ 
++/* Define the special `__gnu_absolute_zero' symbol.  We only need this
++   for PIC code, as otherwise there is no load-time relocation involved
++   and local GOT entries whose value is zero at static link time will
++   retain their value at load time.  */
++
++static bfd_boolean
++mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
++			       struct mips_elf_link_hash_table *htab,
++			       unsigned int r_type)
++{
++  union
++    {
++      struct elf_link_hash_entry *eh;
++      struct bfd_link_hash_entry *bh;
++    }
++  hzero;
++
++  BFD_ASSERT (!htab->use_absolute_zero);
++  BFD_ASSERT (bfd_link_pic (info));
++
++  hzero.bh = NULL;
++  if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
++					 BSF_GLOBAL, bfd_abs_section_ptr, 0,
++					 NULL, FALSE, FALSE, &hzero.bh))
++    return FALSE;
++
++  BFD_ASSERT (hzero.bh != NULL);
++  hzero.eh->size = 0;
++  hzero.eh->type = STT_NOTYPE;
++  hzero.eh->other = STV_PROTECTED;
++  hzero.eh->def_regular = 1;
++  hzero.eh->non_elf = 0;
++
++  if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, TRUE, r_type))
++    return FALSE;
++
++  htab->use_absolute_zero = TRUE;
++
++  return TRUE;
++}
++
+ /* Look through the relocs for a section during the first phase, and
+    allocate space in the global offset table and record the need for
+    standard MIPS and compressed procedure linkage table entries.  */
+@@ -8461,24 +8598,52 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
+ 	  /* Fall through.  */
+ 
+ 	case R_MIPS_GOT16:
+-	case R_MIPS_GOT_HI16:
+ 	case R_MIPS_GOT_LO16:
+ 	case R_MIPS_GOT_PAGE:
+-	case R_MIPS_GOT_OFST:
+ 	case R_MIPS_GOT_DISP:
++	case R_MIPS16_GOT16:
++	case R_MICROMIPS_GOT16:
++	case R_MICROMIPS_GOT_LO16:
++	case R_MICROMIPS_GOT_PAGE:
++	case R_MICROMIPS_GOT_DISP:
++	  /* If we have a symbol that will resolve to zero at static link
++	     time and it is used by a GOT relocation applied to code we
++	     cannot relax to an immediate zero load, then we will be using
++	     the special `__gnu_absolute_zero' symbol whose value is zero
++	     at dynamic load time.  We ignore HI16-type GOT relocations at
++	     this stage, because their handling will depend entirely on
++	     the corresponding LO16-type GOT relocation.  */
++	  if (!call_hi16_reloc_p (r_type)
++	      && h != NULL
++	      && bfd_link_pic (info)
++	      && !htab->use_absolute_zero
++	      && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
++	    {
++	      bfd_boolean rel_reloc;
++
++	      if (!mips_elf_get_section_contents (abfd, sec, &contents))
++		return FALSE;
++
++	      rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
++	      howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
++
++	      if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
++					      FALSE))
++		if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
++		  return FALSE;
++	    }
++
++	  /* Fall through.  */
++	case R_MIPS_GOT_HI16:
++	case R_MIPS_GOT_OFST:
+ 	case R_MIPS_TLS_GOTTPREL:
+ 	case R_MIPS_TLS_GD:
+ 	case R_MIPS_TLS_LDM:
+-	case R_MIPS16_GOT16:
+ 	case R_MIPS16_TLS_GOTTPREL:
+ 	case R_MIPS16_TLS_GD:
+ 	case R_MIPS16_TLS_LDM:
+-	case R_MICROMIPS_GOT16:
+ 	case R_MICROMIPS_GOT_HI16:
+-	case R_MICROMIPS_GOT_LO16:
+-	case R_MICROMIPS_GOT_PAGE:
+ 	case R_MICROMIPS_GOT_OFST:
+-	case R_MICROMIPS_GOT_DISP:
+ 	case R_MICROMIPS_TLS_GOTTPREL:
+ 	case R_MICROMIPS_TLS_GD:
+ 	case R_MICROMIPS_TLS_LDM:
+@@ -10280,10 +10445,10 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
+ 
+       /* Figure out what value we are supposed to relocate.  */
+       switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
+-					     input_section, info, rel,
+-					     addend, howto, local_syms,
+-					     local_sections, &value,
+-					     &name, &cross_mode_jump_p,
++					     input_section, contents,
++					     info, rel, addend, howto,
++					     local_syms, local_sections,
++					     &value, &name, &cross_mode_jump_p,
+ 					     use_saved_addend_p))
+ 	{
+ 	case bfd_reloc_continue:
+@@ -12589,6 +12754,27 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
+   if (indmips->has_nonpic_branches)
+     dirmips->has_nonpic_branches = TRUE;
+ }
++
++/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
++   to hide it.  It has to remain global (it will also be protected) so as to
++   be assigned a global GOT entry, which will then remain unchanged at load
++   time.  */
++
++void
++_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
++			   struct elf_link_hash_entry *entry,
++			   bfd_boolean force_local)
++{
++  struct mips_elf_link_hash_table *htab;
++
++  htab = mips_elf_hash_table (info);
++  BFD_ASSERT (htab != NULL);
++  if (htab->use_absolute_zero
++      && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
++    return;
++
++  _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
++}
+ 
+ #define PDR_SIZE 32
+ 
+@@ -13991,14 +14177,17 @@ _bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
+ 
+ /* A function that the linker calls to select between all or only
+    32-bit microMIPS instructions, and between making or ignoring
+-   branch relocation checks for invalid transitions between ISA modes.  */
++   branch relocation checks for invalid transitions between ISA modes.
++   Also record whether we have been configured for a GNU target.  */
+ 
+ void
+ _bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
+-			    bfd_boolean ignore_branch_isa)
++			    bfd_boolean ignore_branch_isa,
++			    bfd_boolean gnu_target)
+ {
+   mips_elf_hash_table (info)->insn32 = insn32;
+   mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
++  mips_elf_hash_table (info)->gnu_target = gnu_target;
+ }
+ 
+ /* Structure for saying that BFD machine EXTENSION extends BASE.  */
+@@ -16271,13 +16460,14 @@ enum
+   MIPS_LIBC_ABI_MIPS_PLT,
+   MIPS_LIBC_ABI_UNIQUE,
+   MIPS_LIBC_ABI_MIPS_O32_FP64,
++  MIPS_LIBC_ABI_ABSOLUTE,
+   MIPS_LIBC_ABI_MAX
+ };
+ 
+ void
+ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
+ {
+-  struct mips_elf_link_hash_table *htab;
++  struct mips_elf_link_hash_table *htab = NULL;
+   Elf_Internal_Ehdr *i_ehdrp;
+ 
+   i_ehdrp = elf_elfheader (abfd);
+@@ -16285,15 +16475,19 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
+     {
+       htab = mips_elf_hash_table (link_info);
+       BFD_ASSERT (htab != NULL);
+-
+-      if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
+-	i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
+     }
+ 
++  if (htab != NULL && htab->use_plts_and_copy_relocs && !htab->is_vxworks)
++    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
++
+   if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
+       || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
+     i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+ 
++  /* Mark that we need support for absolute symbols in the dynamic loader.  */
++  if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
++    i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
++
+   _bfd_elf_post_process_headers (abfd, link_info);
+ }
+ 
+diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
+index b8ea714307..9652fbc4b1 100644
+--- a/bfd/elfxx-mips.h
++++ b/bfd/elfxx-mips.h
+@@ -81,6 +81,8 @@ extern asection * _bfd_mips_elf_gc_mark_hook
+ extern void _bfd_mips_elf_copy_indirect_symbol
+   (struct bfd_link_info *, struct elf_link_hash_entry *,
+    struct elf_link_hash_entry *);
++extern void _bfd_mips_elf_hide_symbol
++  (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean);
+ extern bfd_boolean _bfd_mips_elf_ignore_discarded_relocs
+   (asection *);
+ extern bfd_boolean _bfd_mips_elf_is_target_special_symbol
+@@ -147,7 +149,7 @@ extern bfd_boolean _bfd_mips_elf_ignore_undef_symbol
+ extern void _bfd_mips_elf_use_plts_and_copy_relocs
+   (struct bfd_link_info *);
+ extern void _bfd_mips_elf_linker_flags
+-  (struct bfd_link_info *, bfd_boolean, bfd_boolean);
++  (struct bfd_link_info *, bfd_boolean, bfd_boolean, bfd_boolean);
+ extern bfd_boolean _bfd_mips_elf_init_stubs
+   (struct bfd_link_info *,
+    asection *(*) (const char *, asection *, asection *));
+diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em
+index c7c164274e..ec8a086c92 100644
+--- a/ld/emultempl/mipself.em
++++ b/ld/emultempl/mipself.em
+@@ -18,6 +18,15 @@
+ # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ # MA 02110-1301, USA.
+ 
++case ${target} in
++  *-*-*gnu*)
++    gnu_target=TRUE
++    ;;
++  *)
++    gnu_target=FALSE
++    ;;
++esac
++
+ fragment <<EOF
+ 
+ #include "ldctor.h"
+@@ -203,7 +212,8 @@ mips_create_output_section_statements (void)
+ 
+   htab = elf_hash_table (&link_info);
+   if (is_elf_hash_table (htab) && is_mips_elf (link_info.output_bfd))
+-    _bfd_mips_elf_linker_flags (&link_info, insn32, ignore_branch_isa);
++    _bfd_mips_elf_linker_flags (&link_info, insn32, ignore_branch_isa,
++				${gnu_target});
+ 
+   if (is_mips_elf (link_info.output_bfd))
+     _bfd_mips_elf_init_stubs (&link_info, mips_add_stub_section);
+diff --git a/ld/testsuite/ld-mips-elf/pr21334.dd b/ld/testsuite/ld-mips-elf/pr21334.dd
+index 01c37181fa..60f0553a59 100644
+--- a/ld/testsuite/ld-mips-elf/pr21334.dd
++++ b/ld/testsuite/ld-mips-elf/pr21334.dd
+@@ -4,7 +4,7 @@ Disassembly of section \.text:
+ [0-9a-f]+ <[^>]*> lui	gp,0x1
+ [0-9a-f]+ <[^>]*> addiu	gp,gp,-32736
+ [0-9a-f]+ <[^>]*> addu	gp,gp,t9
+-[0-9a-f]+ <[^>]*> lw	v0,-32744\(gp\)
++[0-9a-f]+ <[^>]*> lwl	v0,-32744\(gp\)
+ [0-9a-f]+ <[^>]*> jr	ra
+ [0-9a-f]+ <[^>]*> addiu	v0,v0,4
+ 	\.\.\.
+diff --git a/ld/testsuite/ld-mips-elf/pr21334.s b/ld/testsuite/ld-mips-elf/pr21334.s
+index d62c18c318..7f26318abf 100644
+--- a/ld/testsuite/ld-mips-elf/pr21334.s
++++ b/ld/testsuite/ld-mips-elf/pr21334.s
+@@ -8,7 +8,7 @@ foo:
+ 	.mask	0x00000000, 0
+ 	.fmask	0x00000000, 0
+ 	.cpload	$25
+-	lw	$2, %got(bar)($28)
++	lwl	$2, %got(bar)($28)
+ 	jr	$31
+ 	 addiu	$2, $2, 4
+ 	.end	foo
-- 
2.19.2

---
Unsubscribe:  [email-masked]
Help:         [email-masked]
---