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
---