From 16dbc36a7ff358f82b95abe892e23575f502f1d9 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sat, 1 Feb 2020 08:19:00 -0800 Subject: [PATCH] x86: Keep __patchable_function_entries sections with --gc-sections After all text sections have been garbage collected, if a __patchable_function_entries section references a section which wasn't marked, mark it with SEC_EXCLUDE and return NULL. Otherwise, keep it. Issue an error if a __patchable_function_entries section references both kept and garbage collected sections. bfd/ PR ld/25490 * elfxx-x86.c (_bfd_x86_elf_gc_mark_hook): Handle __patchable_function_entries sections. (_bfd_x86_elf_gc_mark_extra_sections): New function. * elfxx-x86.h (_bfd_x86_elf_gc_mark_extra_sections): New. (elf_backend_gc_mark_extra_sections): Likewise. ld/ PR ld/25490 * testsuite/ld-i386/i386.exp: Run PR ld/25490 tests. * testsuite/ld-x86-64/x86-64.exp: Likewise. * testsuite/ld-i386/pr25490-1.d: New file. * testsuite/ld-i386/pr25490-2a.d: Likewise. * testsuite/ld-i386/pr25490-2b.d: Likewise. * testsuite/ld-i386/pr25490-3.d: Likewise. * testsuite/ld-x86-64/pr25490-1-x32.d: Likewise. * testsuite/ld-x86-64/pr25490-1.d: Likewise. * testsuite/ld-x86-64/pr25490-1.s: Likewise. * testsuite/ld-x86-64/pr25490-2.s: Likewise. * testsuite/ld-x86-64/pr25490-2a-x32.d: Likewise. * testsuite/ld-x86-64/pr25490-2a.d: Likewise. * testsuite/ld-x86-64/pr25490-2b-x32.d: Likewise. * testsuite/ld-x86-64/pr25490-2b.d: Likewise. * testsuite/ld-x86-64/pr25490-3-x32.d: Likewise. * testsuite/ld-x86-64/pr25490-3.d: Likewise. * testsuite/ld-x86-64/pr25490-3.s: Likewise. --- bfd/elfxx-x86.c | 49 +++++++++++++++++++++++++ bfd/elfxx-x86.h | 5 +++ ld/testsuite/ld-i386/i386.exp | 4 ++ ld/testsuite/ld-i386/pr25490-1.d | 8 ++++ ld/testsuite/ld-i386/pr25490-2a.d | 8 ++++ ld/testsuite/ld-i386/pr25490-2b.d | 9 +++++ ld/testsuite/ld-i386/pr25490-3.d | 4 ++ ld/testsuite/ld-x86-64/pr25490-1-x32.d | 8 ++++ ld/testsuite/ld-x86-64/pr25490-1.d | 7 ++++ ld/testsuite/ld-x86-64/pr25490-1.s | 13 +++++++ ld/testsuite/ld-x86-64/pr25490-2.s | 26 +++++++++++++ ld/testsuite/ld-x86-64/pr25490-2a-x32.d | 8 ++++ ld/testsuite/ld-x86-64/pr25490-2a.d | 8 ++++ ld/testsuite/ld-x86-64/pr25490-2b-x32.d | 9 +++++ ld/testsuite/ld-x86-64/pr25490-2b.d | 9 +++++ ld/testsuite/ld-x86-64/pr25490-3-x32.d | 4 ++ ld/testsuite/ld-x86-64/pr25490-3.d | 3 ++ ld/testsuite/ld-x86-64/pr25490-3.s | 28 ++++++++++++++ ld/testsuite/ld-x86-64/x86-64.exp | 8 ++++ 19 files changed, 218 insertions(+) create mode 100644 ld/testsuite/ld-i386/pr25490-1.d create mode 100644 ld/testsuite/ld-i386/pr25490-2a.d create mode 100644 ld/testsuite/ld-i386/pr25490-2b.d create mode 100644 ld/testsuite/ld-i386/pr25490-3.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-1-x32.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-1.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-1.s create mode 100644 ld/testsuite/ld-x86-64/pr25490-2.s create mode 100644 ld/testsuite/ld-x86-64/pr25490-2a-x32.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-2a.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-2b-x32.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-2b.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-3-x32.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-3.d create mode 100644 ld/testsuite/ld-x86-64/pr25490-3.s diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index fc783b0e988..758717d99ae 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -2110,10 +2110,59 @@ _bfd_x86_elf_gc_mark_hook (asection *sec, case R_X86_64_GNU_VTENTRY: return NULL; } + else if (CONST_STRNEQ (bfd_section_name (sec), + "__patchable_function_entries")) + { + /* After all text sections have been garbage collected, if a + __patchable_function_entries section references a section + which wasn't marked, mark it with SEC_EXCLUDE and return + NULL. */ + asection *tsec = bfd_section_from_elf_index (sec->owner, + sym->st_shndx); + /* NB: A __patchable_function_entries section may reference both + kept and garbage collected sections. */ + if (tsec->gc_mark) + sec->flags |= SEC_KEEP; + else + sec->flags |= SEC_EXCLUDE; + } return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } +/* Prevent __patchable_function_entries sections from being discarded + with --gc-sections. */ + +bfd_boolean +_bfd_x86_elf_gc_mark_extra_sections (struct bfd_link_info *info, + elf_gc_mark_hook_fn gc_mark_hook) +{ + bfd *sub; + + _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); + + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + for (o = sub->sections; o != NULL; o = o->next) + if (!o->gc_mark + && (o->flags & SEC_EXCLUDE) == 0 + && (o->flags & SEC_KEEP) == 0 + && CONST_STRNEQ (bfd_section_name (o), + "__patchable_function_entries")) + { + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + if ((o->flags & SEC_EXCLUDE) && (o->flags & SEC_KEEP)) + info->callbacks->einfo (_("%F%pB(%pA): reference to garbage collected section\n"), + o->owner, o); + } + } + + return TRUE; +} + static bfd_vma elf_i386_get_plt_got_vma (struct elf_x86_plt *plt_p ATTRIBUTE_UNUSED, bfd_vma off, diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index bef17dc2bac..1e43f1d786c 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -688,6 +688,9 @@ extern asection * _bfd_x86_elf_gc_mark_hook (asection *, struct bfd_link_info *, Elf_Internal_Rela *, struct elf_link_hash_entry *, Elf_Internal_Sym *); +extern bfd_boolean _bfd_x86_elf_gc_mark_extra_sections + (struct bfd_link_info *, elf_gc_mark_hook_fn); + extern long _bfd_x86_elf_get_synthetic_symtab (bfd *, long, long, bfd_vma, struct elf_x86_plt [], asymbol **, asymbol **); @@ -737,6 +740,8 @@ extern void _bfd_x86_elf_link_fixup_ifunc_symbol _bfd_x86_elf_adjust_dynamic_symbol #define elf_backend_gc_mark_hook \ _bfd_x86_elf_gc_mark_hook +#define elf_backend_gc_mark_extra_sections \ + _bfd_x86_elf_gc_mark_extra_sections #define elf_backend_omit_section_dynsym \ _bfd_elf_omit_section_dynsym_all #define elf_backend_parse_gnu_properties \ diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 7bb3636d3b0..e13f23cdc67 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -496,6 +496,10 @@ run_dump_test "pr23930" run_dump_test "pr24322a" run_dump_test "pr24322b" run_dump_test "align-branch-1" +run_dump_test "pr25490-1" +run_dump_test "pr25490-2a" +run_dump_test "pr25490-2b" +run_dump_test "pr25490-3" if { !([istarget "i?86-*-linux*"] || [istarget "i?86-*-gnu*"] diff --git a/ld/testsuite/ld-i386/pr25490-1.d b/ld/testsuite/ld-i386/pr25490-1.d new file mode 100644 index 00000000000..67cc5e86ec2 --- /dev/null +++ b/ld/testsuite/ld-i386/pr25490-1.d @@ -0,0 +1,8 @@ +#source: ../ld-x86-64/pr25490-1.s +#as: --32 +#ld: --gc-sections -melf_i386 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+4 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-i386/pr25490-2a.d b/ld/testsuite/ld-i386/pr25490-2a.d new file mode 100644 index 00000000000..5096252829f --- /dev/null +++ b/ld/testsuite/ld-i386/pr25490-2a.d @@ -0,0 +1,8 @@ +#source: ../ld-x86-64/pr25490-2.s +#as: --32 +#ld: --gc-sections -melf_i386 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries._start +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+4 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-i386/pr25490-2b.d b/ld/testsuite/ld-i386/pr25490-2b.d new file mode 100644 index 00000000000..3f9cab548be --- /dev/null +++ b/ld/testsuite/ld-i386/pr25490-2b.d @@ -0,0 +1,9 @@ +#source: ../ld-x86-64/pr25490-2.s +#as: --32 +#ld: --gc-sections -melf_i386 +#readelf: -SW + +#failif +#... + +\[ *[0-9]+\] __patchable_function_entries.bar +PROGBITS +.* +#pass diff --git a/ld/testsuite/ld-i386/pr25490-3.d b/ld/testsuite/ld-i386/pr25490-3.d new file mode 100644 index 00000000000..4da1f85d630 --- /dev/null +++ b/ld/testsuite/ld-i386/pr25490-3.d @@ -0,0 +1,4 @@ +#source: ../ld-x86-64/pr25490-3.s +#as: --32 +#ld: --gc-sections -melf_i386 +#error: .*\(__patchable_function_entries\): reference to garbage collected section diff --git a/ld/testsuite/ld-x86-64/pr25490-1-x32.d b/ld/testsuite/ld-x86-64/pr25490-1-x32.d new file mode 100644 index 00000000000..65bc2bee28c --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-1-x32.d @@ -0,0 +1,8 @@ +#source: pr25490-1.s +#as: --x32 +#ld: --gc-sections -melf32_x86_64 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+4 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-1.d b/ld/testsuite/ld-x86-64/pr25490-1.d new file mode 100644 index 00000000000..dc1d912076b --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-1.d @@ -0,0 +1,7 @@ +#as: --64 +#ld: --gc-sections -melf_x86_64 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+8 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-1.s b/ld/testsuite/ld-x86-64/pr25490-1.s new file mode 100644 index 00000000000..21123ad8aa0 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-1.s @@ -0,0 +1,13 @@ + .text + .p2align 4 + .globl _start + .type _start, %function +_start: + .section __patchable_function_entries,"aw",%progbits + .dc.a .LPFE1 + .text +.LPFE1: + nop + ret + .size _start, .-_start + .section .note.GNU-stack,"",%progbits diff --git a/ld/testsuite/ld-x86-64/pr25490-2.s b/ld/testsuite/ld-x86-64/pr25490-2.s new file mode 100644 index 00000000000..1f8df870316 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-2.s @@ -0,0 +1,26 @@ + .text + .p2align 4 + .section .text.bar,"ax",%progbits + .globl bar + .type bar, %function +bar: + .section __patchable_function_entries.bar,"aw",%progbits + .dc.a .LPFE1 + .section .text.bar,"ax",%progbits +.LPFE1: + nop + ret + .size bar, .-bar + .p2align 4 + .section .text._start,"ax",%progbits + .globl _start + .type _start, %function +_start: + .section __patchable_function_entries._start,"aw",%progbits + .dc.a .LPFE2 + .section .text._start,"ax",%progbits +.LPFE2: + nop + ret + .size _start, .-_start + .section .note.GNU-stack,"",%progbits diff --git a/ld/testsuite/ld-x86-64/pr25490-2a-x32.d b/ld/testsuite/ld-x86-64/pr25490-2a-x32.d new file mode 100644 index 00000000000..2029029a0f3 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-2a-x32.d @@ -0,0 +1,8 @@ +#source: pr25490-2.s +#as: --x32 +#ld: --gc-sections -melf32_x86_64 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries._start +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+4 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-2a.d b/ld/testsuite/ld-x86-64/pr25490-2a.d new file mode 100644 index 00000000000..a5f0b141c87 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-2a.d @@ -0,0 +1,8 @@ +#source: pr25490-2.s +#as: --64 +#ld: --gc-sections -melf_x86_64 +#readelf: -SW + +#... + +\[ *[0-9]+\] __patchable_function_entries._start +PROGBITS +[0-9a-f]+ +[0-9a-f]+000 +0+8 +00 +WA +0 +0 +1 +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-2b-x32.d b/ld/testsuite/ld-x86-64/pr25490-2b-x32.d new file mode 100644 index 00000000000..a9fe6ba6b3c --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-2b-x32.d @@ -0,0 +1,9 @@ +#source: pr25490-2.s +#as: --x32 +#ld: --gc-sections -melf32_x86_64 +#readelf: -SW + +#failif +#... + +\[ *[0-9]+\] __patchable_function_entries.bar +PROGBITS +.* +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-2b.d b/ld/testsuite/ld-x86-64/pr25490-2b.d new file mode 100644 index 00000000000..5eb933f5b36 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-2b.d @@ -0,0 +1,9 @@ +#source: pr25490-2.s +#as: --64 +#ld: --gc-sections -melf_x86_64 +#readelf: -SW + +#failif +#... + +\[ *[0-9]+\] __patchable_function_entries.bar +PROGBITS +.* +#pass diff --git a/ld/testsuite/ld-x86-64/pr25490-3-x32.d b/ld/testsuite/ld-x86-64/pr25490-3-x32.d new file mode 100644 index 00000000000..4979a3e7978 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-3-x32.d @@ -0,0 +1,4 @@ +#source: pr25490-3.s +#as: --x32 +#ld: --gc-sections -melf32_x86_64 +#error: .*\(__patchable_function_entries\): reference to garbage collected section diff --git a/ld/testsuite/ld-x86-64/pr25490-3.d b/ld/testsuite/ld-x86-64/pr25490-3.d new file mode 100644 index 00000000000..27a11480b60 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-3.d @@ -0,0 +1,3 @@ +#as: --64 +#ld: --gc-sections -melf_x86_64 +#error: .*\(__patchable_function_entries\): reference to garbage collected section diff --git a/ld/testsuite/ld-x86-64/pr25490-3.s b/ld/testsuite/ld-x86-64/pr25490-3.s new file mode 100644 index 00000000000..c7fae78314c --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr25490-3.s @@ -0,0 +1,28 @@ + .text + .section .text.bar,"ax",%progbits + .p2align 4 + .globl bar + .type bar, %function +bar: + .section __patchable_function_entries,"aw",%progbits + .align 8 + .dc.a .LPFE1 + .section .text.bar +.LPFE1: + nop + ret + .size bar, .-bar + .section .text._start,"ax",%progbits + .p2align 4 + .globl _start + .type _start, %function +_start: + .section __patchable_function_entries + .align 8 + .dc.a .LPFE2 + .section .text._start +.LPFE2: + nop + ret + .size _start, .-_start + .section .note.GNU-stack,"",%progbits diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index c78b0fd7576..48912ace1c1 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -467,6 +467,14 @@ run_dump_test "pr25416-2a" run_dump_test "pr25416-2b" run_dump_test "pr25416-3" run_dump_test "pr25416-4" +run_dump_test "pr25490-1" +run_dump_test "pr25490-1-x32" +run_dump_test "pr25490-2a" +run_dump_test "pr25490-2a-x32" +run_dump_test "pr25490-2b" +run_dump_test "pr25490-2b-x32" +run_dump_test "pr25490-3" +run_dump_test "pr25490-3-x32" if { ![istarget "x86_64-*-linux*"] && ![istarget "x86_64-*-nacl*"]} { return -- 2.24.1