diff options
author | Cary Coutant <ccoutant@gmail.com> | 2018-06-22 23:36:50 -0700 |
---|---|---|
committer | Cary Coutant <ccoutant@gmail.com> | 2018-06-22 23:36:50 -0700 |
commit | a2575bec2413d361c6ecfc4aecb2a31c86123f95 (patch) | |
tree | 100be502c00550c9c70593d47c36625b3c4f8e4f /gold/layout.cc | |
parent | a1893a821c4a2e953d13b97360b85650f2127134 (diff) | |
download | gdb-a2575bec2413d361c6ecfc4aecb2a31c86123f95.zip gdb-a2575bec2413d361c6ecfc4aecb2a31c86123f95.tar.gz gdb-a2575bec2413d361c6ecfc4aecb2a31c86123f95.tar.bz2 |
Update support for .note.gnu.property sections.
The original patch did not give the target enough hooks to discover that
an input object file does not have a particular property. For the
GNU_PROPERTY_X86_FEATURE_1_AND property, for example, where a missing
property should be assumed to be all zeroes, and ANDed with other
object modules, this is essential. We now store the target-specific
properties locally in the Target structure as native uint32_t fields,
then AND the per-object feature bits with the program's feature bits
when we're finished processing each input object file. The target-specific
properties are then added back to the output note section during
finalization.
gold/
PR gold/22914
* layout.cc (read_sized_value): Fix spelling of section name.
(Layout::layout_gnu_property): Call Sized_target::record_gnu_property
for target-specific properties;
don't store them with target-independent properties yet.
(Layout::merge_gnu_properties): New method.
(Layout::add_gnu_property): New method.
(Layout::create_gnu_properties_note): Call target to finalize
target-specific properties. Fix spelling of output section name.
* layout.h (Layout::merge_gnu_properties): New method.
(Layout::add_gnu_property): New method.
* object.cc (Sized_relobj_file::do_layout): Call
Layout::merge_gnu_properties.
* target.h (Target::merge_gnu_property): Remove.
(Target::finalize_gnu_properties): New method.
(Target::do_merge_gnu_property): Move to Sized_target and rename.
(Target::do_finalize_gnu_properties): New virtual method.
(Sized_target::record_gnu_property): Moved and renamed from
Target::do_merge_gnu_property.
(Sized_target::merge_gnu_properties): New virtual method.
* x86_64.cc (Target_x86_64::isa_1_used_, isa_1_needed_)
(feature_1_, object_feature_1_, seen_first_object_): New data members.
(Target_x86_64::do_merge_gnu_property): Rename to ...
(Target_x86_64::record_gnu_property): ... this. Save target-specific
properties in Target class object.
(Target_x86_64::merge_gnu_properties): New method.
(add_property): New static inline function.
(Target_x86_64::do_finalize_gnu_properties): New method.
* testsuite/Makefile.am (gnu_property_test): Remove C source file;
link directly without compiler driver.
* testsuite/Makefile.in: Regenerate.
* testsuite/gnu_property_a.S: Add _start.
Diffstat (limited to 'gold/layout.cc')
-rw-r--r-- | gold/layout.cc | 186 |
1 files changed, 149 insertions, 37 deletions
diff --git a/gold/layout.cc b/gold/layout.cc index 9ce38c3..0df7ed3 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -2217,7 +2217,7 @@ read_sized_value(size_t size, const unsigned char* buf, bool is_big_endian, } else { - gold_warning(_("%s: in .note.gnu.properties section, " + gold_warning(_("%s: in .note.gnu.property section, " "pr_datasz must be 4 or 8"), object->name().c_str()); } @@ -2262,6 +2262,63 @@ Layout::layout_gnu_property(unsigned int note_type, // We currently support only the one note type. gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0); + if (pr_type >= elfcpp::GNU_PROPERTY_LOPROC + && pr_type < elfcpp::GNU_PROPERTY_HIPROC) + { + // Target-dependent property value; call the target to record. + const int size = parameters->target().get_size(); + const bool is_big_endian = parameters->target().is_big_endian(); + if (size == 32) + { + if (is_big_endian) + { +#ifdef HAVE_TARGET_32_BIG + parameters->sized_target<32, true>()-> + record_gnu_property(note_type, pr_type, pr_datasz, pr_data, + object); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_LITTLE + parameters->sized_target<32, false>()-> + record_gnu_property(note_type, pr_type, pr_datasz, pr_data, + object); +#else + gold_unreachable(); +#endif + } + } + else if (size == 64) + { + if (is_big_endian) + { +#ifdef HAVE_TARGET_64_BIG + parameters->sized_target<64, true>()-> + record_gnu_property(note_type, pr_type, pr_datasz, pr_data, + object); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_64_LITTLE + parameters->sized_target<64, false>()-> + record_gnu_property(note_type, pr_type, pr_datasz, pr_data, + object); +#else + gold_unreachable(); +#endif + } + } + else + gold_unreachable(); + return; + } + Gnu_properties::iterator pprop = this->gnu_properties_.find(pr_type); if (pprop == this->gnu_properties_.end()) { @@ -2273,46 +2330,99 @@ Layout::layout_gnu_property(unsigned int note_type, } else { - if (pr_type >= elfcpp::GNU_PROPERTY_LOPROC - && pr_type < elfcpp::GNU_PROPERTY_HIPROC) + const bool is_big_endian = parameters->target().is_big_endian(); + switch (pr_type) + { + case elfcpp::GNU_PROPERTY_STACK_SIZE: + // Record the maximum value seen. + { + uint64_t val1 = read_sized_value(pprop->second.pr_datasz, + pprop->second.pr_data, + is_big_endian, object); + uint64_t val2 = read_sized_value(pr_datasz, pr_data, + is_big_endian, object); + if (val2 > val1) + write_sized_value(val2, pprop->second.pr_datasz, + pprop->second.pr_data, is_big_endian); + } + break; + case elfcpp::GNU_PROPERTY_NO_COPY_ON_PROTECTED: + // No data to merge. + break; + default: + gold_warning(_("%s: unknown program property type %d " + "in .note.gnu.property section"), + object->name().c_str(), pr_type); + } + } +} + +// Merge per-object properties with program properties. +// This lets the target identify objects that are missing certain +// properties, in cases where properties must be ANDed together. + +void +Layout::merge_gnu_properties(const Object* object) +{ + const int size = parameters->target().get_size(); + const bool is_big_endian = parameters->target().is_big_endian(); + if (size == 32) + { + if (is_big_endian) + { +#ifdef HAVE_TARGET_32_BIG + parameters->sized_target<32, true>()->merge_gnu_properties(object); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_LITTLE + parameters->sized_target<32, false>()->merge_gnu_properties(object); +#else + gold_unreachable(); +#endif + } + } + else if (size == 64) + { + if (is_big_endian) { - // Target-dependent property value; call the target to merge. - parameters->target().merge_gnu_property(note_type, - pr_type, - pr_datasz, - pr_data, - pprop->second.pr_datasz, - pprop->second.pr_data, - object); +#ifdef HAVE_TARGET_64_BIG + parameters->sized_target<64, true>()->merge_gnu_properties(object); +#else + gold_unreachable(); +#endif } else { - const bool is_big_endian = parameters->target().is_big_endian(); - switch (pr_type) - { - case elfcpp::GNU_PROPERTY_STACK_SIZE: - // Record the maximum value seen. - { - uint64_t val1 = read_sized_value(pprop->second.pr_datasz, - pprop->second.pr_data, - is_big_endian, object); - uint64_t val2 = read_sized_value(pr_datasz, pr_data, - is_big_endian, object); - if (val2 > val1) - write_sized_value(val2, pprop->second.pr_datasz, - pprop->second.pr_data, is_big_endian); - } - break; - case elfcpp::GNU_PROPERTY_NO_COPY_ON_PROTECTED: - // No data to merge. - break; - default: - gold_warning(_("%s: unknown program property type %d " - "in .note.gnu.properties section"), - object->name().c_str(), pr_type); - } +#ifdef HAVE_TARGET_64_LITTLE + parameters->sized_target<64, false>()->merge_gnu_properties(object); +#else + gold_unreachable(); +#endif } } + else + gold_unreachable(); +} + +// Add a target-specific property for the output .note.gnu.property section. + +void +Layout::add_gnu_property(unsigned int note_type, + unsigned int pr_type, + size_t pr_datasz, + const unsigned char* pr_data) +{ + gold_assert(note_type == elfcpp::NT_GNU_PROPERTY_TYPE_0); + + Gnu_property prop; + prop.pr_datasz = pr_datasz; + prop.pr_data = new unsigned char[pr_datasz]; + memcpy(prop.pr_data, pr_data, pr_datasz); + this->gnu_properties_[pr_type] = prop; } // Create automatic note sections. @@ -3144,12 +3254,14 @@ Layout::create_note(const char* name, int note_type, return os; } -// Create a .note.gnu.properties section to record program properties +// Create a .note.gnu.property section to record program properties // accumulated from the input files. void Layout::create_gnu_properties_note() { + parameters->target().finalize_gnu_properties(this); + if (this->gnu_properties_.empty()) return; @@ -3168,7 +3280,7 @@ Layout::create_gnu_properties_note() // Create the note section. size_t trailing_padding; Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_PROPERTY_TYPE_0, - ".note.gnu.properties", descsz, + ".note.gnu.property", descsz, true, &trailing_padding); if (os == NULL) return; |