diff options
-rw-r--r-- | elfcpp/elfcpp.h | 1 | ||||
-rw-r--r-- | gold/layout.cc | 31 | ||||
-rw-r--r-- | gold/object.cc | 4 | ||||
-rw-r--r-- | gold/object.h | 50 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 16 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 26 | ||||
-rwxr-xr-x | gold/testsuite/retain.sh | 60 | ||||
-rw-r--r-- | gold/testsuite/retain_1.s | 104 | ||||
-rw-r--r-- | gold/testsuite/retain_2.s | 22 |
9 files changed, 294 insertions, 20 deletions
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h index 4b6ff94..2d333e9 100644 --- a/elfcpp/elfcpp.h +++ b/elfcpp/elfcpp.h @@ -438,6 +438,7 @@ enum SHF SHF_TLS = 0x400, SHF_COMPRESSED = 0x800, SHF_MASKOS = 0x0ff00000, + SHF_GNU_RETAIN = 0x200000, SHF_MASKPROC = 0xf0000000, // Indicates this section requires ordering in relation to diff --git a/gold/layout.cc b/gold/layout.cc index 8acfb96..dc88a9d 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -1173,14 +1173,20 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx, { // Some flags in the input section should not be automatically // copied to the output section. - elfcpp::Elf_Xword flags = (shdr.get_sh_flags() - & ~ elfcpp::SHF_COMPRESSED); + elfcpp::Elf_Xword sh_flags = (shdr.get_sh_flags() + & ~ elfcpp::SHF_COMPRESSED); name = this->namepool_.add(name, true, NULL); - os = this->make_output_section(name, sh_type, flags, - ORDER_INVALID, false); + os = this->make_output_section(name, sh_type, sh_flags, ORDER_INVALID, + false); } else { + // Get the section flags and mask out any flags that do not + // take part in section matching. + elfcpp::Elf_Xword sh_flags + = (this->get_output_section_flags(shdr.get_sh_flags()) + & ~object->osabi().ignored_sh_flags()); + // All ".text.unlikely.*" sections can be moved to a unique // segment with --text-unlikely-segment option. bool text_unlikely_segment @@ -1189,13 +1195,10 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx, object->section_name(shndx).c_str())); if (text_unlikely_segment) { - elfcpp::Elf_Xword flags - = this->get_output_section_flags(shdr.get_sh_flags()); - Stringpool::Key name_key; const char* os_name = this->namepool_.add(".text.unlikely", true, &name_key); - os = this->get_output_section(os_name, name_key, sh_type, flags, + os = this->get_output_section(os_name, name_key, sh_type, sh_flags, ORDER_INVALID, false); // Map this output section to a unique segment. This is done to // separate "text" that is not likely to be executed from "text" @@ -1213,22 +1216,18 @@ Layout::layout(Sized_relobj_file<size, big_endian>* object, unsigned int shndx, if (it == this->section_segment_map_.end()) { os = this->choose_output_section(object, name, sh_type, - shdr.get_sh_flags(), true, - ORDER_INVALID, false, false, - true); + sh_flags, true, ORDER_INVALID, + false, false, true); } else { // We know the name of the output section, directly call // get_output_section here by-passing choose_output_section. - elfcpp::Elf_Xword flags - = this->get_output_section_flags(shdr.get_sh_flags()); - const char* os_name = it->second->name; Stringpool::Key name_key; os_name = this->namepool_.add(os_name, true, &name_key); - os = this->get_output_section(os_name, name_key, sh_type, flags, - ORDER_INVALID, false); + os = this->get_output_section(os_name, name_key, sh_type, + sh_flags, ORDER_INVALID, false); if (!os->is_unique_segment()) { os->set_is_unique_segment(); diff --git a/gold/object.cc b/gold/object.cc index 23ce206..072563b 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -464,6 +464,7 @@ Sized_relobj_file<size, big_endian>::Sized_relobj_file( const elfcpp::Ehdr<size, big_endian>& ehdr) : Sized_relobj<size, big_endian>(name, input_file, offset), elf_file_(this, ehdr), + osabi_(ehdr), symtab_shndx_(-1U), local_symbol_count_(0), output_local_symbol_count_(0), @@ -1706,7 +1707,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, if (this->is_section_name_included(name) || layout->keep_input_section (this, name) || sh_type == elfcpp::SHT_INIT_ARRAY - || sh_type == elfcpp::SHT_FINI_ARRAY) + || sh_type == elfcpp::SHT_FINI_ARRAY + || this->osabi().has_shf_retain(shdr.get_sh_flags())) { symtab->gc()->worklist().push_back(Section_id(this, i)); } diff --git a/gold/object.h b/gold/object.h index b7bd38f..4afee99 100644 --- a/gold/object.h +++ b/gold/object.h @@ -384,6 +384,49 @@ build_compressed_section_map(const unsigned char* pshdrs, unsigned int shnum, const char* names, section_size_type names_size, Object* obj, bool decompress_if_needed); +// Osabi represents the EI_OSABI field from the ELF header. + +template <int size, bool big_endian> +class Osabi +{ + public: + Osabi(const elfcpp::Ehdr<size, big_endian>& ehdr) + : ei_osabi_(static_cast<elfcpp::ELFOSABI>( + ehdr.get_e_ident()[elfcpp::EI_OSABI])) + { } + + bool + has_shf_retain(elfcpp::Elf_Xword sh_flags) const + { + switch (this->ei_osabi_) + { + case elfcpp::ELFOSABI_GNU: + case elfcpp::ELFOSABI_FREEBSD: + return (sh_flags & elfcpp::SHF_GNU_RETAIN) != 0; + default: + break; + } + return false; + } + + elfcpp::Elf_Xword + ignored_sh_flags() const + { + switch (this->ei_osabi_) + { + case elfcpp::ELFOSABI_GNU: + case elfcpp::ELFOSABI_FREEBSD: + return elfcpp::SHF_GNU_RETAIN; + default: + break; + } + return 0; + } + + private: + elfcpp::ELFOSABI ei_osabi_; +}; + // Object is an abstract base class which represents either a 32-bit // or a 64-bit input object. This can be a regular object file // (ET_REL) or a shared object (ET_DYN). @@ -2205,6 +2248,11 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian> e_type() const { return this->e_type_; } + // Return the EI_OSABI. + const Osabi<size, big_endian>& + osabi() const + { return this->osabi_; } + // Return the number of symbols. This is only valid after // Object::add_symbols has been called. unsigned int @@ -2845,6 +2893,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian> // General access to the ELF file. elfcpp::Elf_file<size, big_endian, Object> elf_file_; + // The EI_OSABI. + const Osabi<size, big_endian> osabi_; // Type of ELF file (ET_REL or ET_EXEC). ET_EXEC files are allowed // as input files only for the --just-symbols option. int e_type_; diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 72a296f..38e5481 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -4418,4 +4418,20 @@ pr26936c.o: pr26936c.s pr26936d.o: pr26936d.s $(TEST_AS) --gen-debug -mx86-used-note=yes -o $@ $< +check_SCRIPTS += retain.sh +check_DATA += retain_1.out retain_2.out +MOSTLYCLEANFILES += retain_1 retain_2 +retain_1.out: retain_1 + $(TEST_NM) $< >$@ +retain_1: retain_1.o ../ld-new + ../ld-new -e _start --gc-sections -o $@ retain_1.o +retain_1.o: retain_1.s + $(TEST_AS) -o $@ $< +retain_2.out: retain_2 + $(TEST_READELF) -d $< >$@ +retain_2: retain_2.o ../ld-new + ../ld-new -pie -e _start --gc-sections -o $@ retain_2.o +retain_2.o: retain_2.s + $(TEST_AS) -o $@ $< + endif DEFAULT_TARGET_X86_64 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 5575408..7b4b783 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -1130,12 +1130,13 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ @DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ split_s390x_z4_ns split_s390x_n1_ns split_s390x_n2_ns split_s390x_r @DEFAULT_TARGET_X86_64_TRUE@am__append_114 = *.dwo *.dwp pr26936a \ -@DEFAULT_TARGET_X86_64_TRUE@ pr26936b +@DEFAULT_TARGET_X86_64_TRUE@ pr26936b retain_1 retain_2 @DEFAULT_TARGET_X86_64_TRUE@am__append_115 = dwp_test_1.sh \ -@DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.sh pr26936.sh +@DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.sh pr26936.sh retain.sh @DEFAULT_TARGET_X86_64_TRUE@am__append_116 = dwp_test_1.stdout \ @DEFAULT_TARGET_X86_64_TRUE@ dwp_test_2.stdout pr26936a.stdout \ -@DEFAULT_TARGET_X86_64_TRUE@ pr26936b.stdout +@DEFAULT_TARGET_X86_64_TRUE@ pr26936b.stdout retain_1.out \ +@DEFAULT_TARGET_X86_64_TRUE@ retain_2.out subdir = testsuite ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../config/ax_pthread.m4 \ @@ -6451,6 +6452,13 @@ pr26936.sh.log: pr26936.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +retain.sh.log: retain.sh + @p='retain.sh'; \ + b='retain.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) object_unittest.log: object_unittest$(EXEEXT) @p='object_unittest$(EXEEXT)'; \ b='object_unittest'; \ @@ -10394,6 +10402,18 @@ uninstall-am: @DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) --gen-debug -mx86-used-note=yes -o $@ $< @DEFAULT_TARGET_X86_64_TRUE@pr26936d.o: pr26936d.s @DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) --gen-debug -mx86-used-note=yes -o $@ $< +@DEFAULT_TARGET_X86_64_TRUE@retain_1.out: retain_1 +@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_NM) $< >$@ +@DEFAULT_TARGET_X86_64_TRUE@retain_1: retain_1.o ../ld-new +@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new -e _start --gc-sections -o $@ retain_1.o +@DEFAULT_TARGET_X86_64_TRUE@retain_1.o: retain_1.s +@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $< +@DEFAULT_TARGET_X86_64_TRUE@retain_2.out: retain_2 +@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_READELF) -d $< >$@ +@DEFAULT_TARGET_X86_64_TRUE@retain_2: retain_2.o ../ld-new +@DEFAULT_TARGET_X86_64_TRUE@ ../ld-new -pie -e _start --gc-sections -o $@ retain_2.o +@DEFAULT_TARGET_X86_64_TRUE@retain_2.o: retain_2.s +@DEFAULT_TARGET_X86_64_TRUE@ $(TEST_AS) -o $@ $< # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/gold/testsuite/retain.sh b/gold/testsuite/retain.sh new file mode 100755 index 0000000..0f5c695 --- /dev/null +++ b/gold/testsuite/retain.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# retain.sh -- Tests for SHF_GNU_RETAIN. + +# Copyright (C) 2020 Free Software Foundation, Inc. + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +set -e + +check() +{ + number_of_occurrence=`egrep "$2" ./$1 -o | wc -l` + if [ $number_of_occurrence != $3 ] + then + echo "$1: \"$2\" $3: Failed" + status=1 + fi +} + +status=0 +check retain_1.out " T fnretain1" 1 +check retain_1.out " b lsretain0.2" 1 +check retain_1.out " b lsretain1.1" 1 +check retain_1.out " d lsretain2.0" 1 +check retain_1.out " B retain0" 1 +check retain_1.out " B retain1" 1 +check retain_1.out " D retain2" 1 +check retain_1.out " b sretain0" 1 +check retain_1.out " b sretain1" 1 +check retain_1.out " d sretain2" 1 +if grep discard retain_1.out +then + echo "retain_1.out: Garbage collection failed" + status=1 +fi + +check retain_2.out " \(PREINIT_ARRAY\)" 1 +check retain_2.out " \(PREINIT_ARRAYSZ\)" 1 +check retain_2.out " \(INIT_ARRAY\)" 1 +check retain_2.out " \(INIT_ARRAYSZ\)" 1 +check retain_2.out " \(FINI_ARRAY\)" 1 +check retain_2.out " \(FINI_ARRAYSZ\)" 1 + +exit $status diff --git a/gold/testsuite/retain_1.s b/gold/testsuite/retain_1.s new file mode 100644 index 0000000..f7716fa --- /dev/null +++ b/gold/testsuite/retain_1.s @@ -0,0 +1,104 @@ + .global discard0 + .section .bss.discard0,"aw" + .type discard0, %object +discard0: + .zero 2 + + .global discard1 + .section .bss.discard1,"aw" + .type discard1, %object +discard1: + .zero 2 + + .global discard2 + .section .data.discard2,"aw" + .type discard2, %object +discard2: + .word 1 + + .section .bss.sdiscard0,"aw" + .type sdiscard0, %object +sdiscard0: + .zero 2 + + .section .bss.sdiscard1,"aw" + .type sdiscard1, %object +sdiscard1: + .zero 2 + + .section .data.sdiscard2,"aw" + .type sdiscard2, %object +sdiscard2: + .word 1 + + .section .text.fndiscard0,"ax" + .global fndiscard0 + .type fndiscard0, %function +fndiscard0: + .word 0 + + .global retain0 + .section .bss.retain0,"awR" + .type retain0, %object +retain0: + .zero 2 + + .global retain1 + .section .bss.retain1,"awR" + .type retain1, %object +retain1: + .zero 2 + + .global retain2 + .section .data.retain2,"awR" + .type retain2, %object +retain2: + .word 1 + + .section .bss.sretain0,"awR" + .type sretain0, %object +sretain0: + .zero 2 + + .section .bss.sretain1,"awR" + .type sretain1, %object +sretain1: + .zero 2 + + .section .data.sretain2,"aRw" + .type sretain2, %object +sretain2: + .word 1 + + .section .text.fnretain1,"Rax" + .global fnretain1 + .type fnretain1, %function +fnretain1: + .word 0 + + .section .text.fndiscard2,"ax" + .global fndiscard2 + .type fndiscard2, %function +fndiscard2: + .word 0 + + .section .bss.lsretain0,"awR" + .type lsretain0.2, %object +lsretain0.2: + .zero 2 + + .section .bss.lsretain1,"aRw" + .type lsretain1.1, %object +lsretain1.1: + .zero 2 + + .section .data.lsretain2,"aRw" + .type lsretain2.0, %object +lsretain2.0: + .word 1 + + .section .text._start,"ax" + .global _start + .type _start, %function +_start: + .word 0 diff --git a/gold/testsuite/retain_2.s b/gold/testsuite/retain_2.s new file mode 100644 index 0000000..67d86d1 --- /dev/null +++ b/gold/testsuite/retain_2.s @@ -0,0 +1,22 @@ + .section .preinit_array.01000,"aw",%preinit_array + .dc.a 0 + + .section .init_array.01000,"aw",%init_array + .dc.a 0 + + .section .fini_array.01000,"aw",%fini_array + .dc.a 0 + + .section .preinit_array.01000,"awR",%preinit_array + .dc.a 0 + + .section .init_array.01000,"awR",%init_array + .dc.a 0 + + .section .fini_array.01000,"awR",%fini_array + .dc.a 0 + + .text + .globl _start +_start: + .dc.a 0 |