X-Original-To: alpine-aports@lists.alpinelinux.org Received: from mx12.valuehost.ru (mx12.valuehost.ru [217.112.42.215]) by lists.alpinelinux.org (Postfix) with ESMTP id 283A9F8516D for ; Wed, 19 Dec 2018 08:56:25 +0000 (UTC) Received: from mx7.valuehost.ru (unknown [127.0.0.255]) by mx12.valuehost.ru (Postfix) with ESMTP id 58E965B32D for ; Wed, 19 Dec 2018 11:56:24 +0300 (MSK) From: alpine-mips-patches Date: Wed, 19 Dec 2018 07:44:46 +0000 Subject: [alpine-aports] [PATCH] main/binutils: fix -static-pie generation on mips* To: alpine-aports@lists.alpinelinux.org Message-Id: <20181219085624.58E965B32D@mx12.valuehost.ru> X-Mailinglist: alpine-aports Precedence: list List-Id: Alpine Development List-Unsubscribe: List-Post: List-Help: List-Subscribe: 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 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 +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) + : 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 +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 +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", + + + [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, + + + [3] "SYSTEM V APPLICATION BINARY INTERFACE, MIPS RISC Processor + Supplement, 3rd Edition", Section "Global Offset Table", p. 5-10, + + + [4] "Undo dynamic symbol state after regular object sym type mismatch", + + + 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 <]*> 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 ---