~alpine/aports

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

alpine-mips-patches <info@mobile-stream.com>
Details
Message ID
<20181219085624.58E965B32D@mx12.valuehost.ru>
Sender timestamp
1545205486
DKIM signature
missing
Download raw message
Patch: +949 -2
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 <ncopa@alpinelinux.org>
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 <macro@mips.com>
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 <macro@mips.com>
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 <macro@mips.com>
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:  alpine-aports+unsubscribe@lists.alpinelinux.org
Help:         alpine-aports+help@lists.alpinelinux.org
---
Reply to thread Export thread (mbox)