Keep input SHF_GNU_RETAIN sections and strip output SHF_GNU_RETAIN for GNU/FreBSD ELFOSABIs.

2020-12-14  H.J. Lu  <hjl.tools@gmail.com>
	    Cary Coutant  <ccoutant@gmail.com>

elfcpp/
	PR gold/27039
	* elfcpp.h (SHF): Add SHF_GNU_RETAIN.

gold/
    	PR gold/27039
	* layout.cc (Layout::layout): Strip SHF_GNU_RETAIN.
	* object.cc (Sized_relobj_file::Sized_relobj_file): Initialize osabi_.
	(Sized_relobj_file::do_layout): Keep SHF_GNU_RETAIN sections for
	GNU/FreBSD ELFOSABIs.
	* object.h (Osabi) New class.
	(Sized_relobj_file): Add osabi() and osabi_.
	* testsuite/Makefile.am (check_SCRIPTS): Add retain.sh.
	(check_DATA): Add retain_1.out retain_2.out.
	(MOSTLYCLEANFILES): Add retain_1 retain_2.
	(retain_1.out): New target.
	(retain_1): Likewise.
	(retain_1.o): Likewise.
	(retain_2.out): Likewise.
	(retain_2): Likewise.
	(retain_2.o): Likewise.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/retain.sh: New file.
	* testsuite/retain_1.s: Likewise.
	* testsuite/retain_2.s: Likewise.
This commit is contained in:
Cary Coutant 2020-12-14 15:46:47 -08:00
parent 8cd6d968de
commit ff4bc37d77
9 changed files with 294 additions and 20 deletions

View File

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

View File

@ -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();

View File

@ -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));
}

View File

@ -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_;

View File

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

View File

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

60
gold/testsuite/retain.sh Executable file
View File

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

104
gold/testsuite/retain_1.s Normal file
View File

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

22
gold/testsuite/retain_2.s Normal file
View File

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