+2018-06-22 Cary Coutant <ccoutant@gmail.com>
+
+ 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.
+
2018-06-22 Cary Coutant <ccoutant@gmail.com>
* incremental.cc (Sized_incremental_binary::setup_readers): Use
}
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());
}
// 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())
{
}
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.
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;
// 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;
const unsigned char* pr_data,
const Object* object);
+ // Merge per-object properties with program properties.
+ void
+ merge_gnu_properties(const Object* object);
+
+ // Add a target-specific property for the output .note.gnu.property section.
+ void
+ add_gnu_property(unsigned int note_type,
+ unsigned int pr_type,
+ size_t pr_datasz,
+ const unsigned char* pr_data);
+
// Add an Output_section_data to the layout. This is used for
// special sections like the GOT section. ORDER is where the
// section should wind up in the output segment. IS_RELRO is true
std::vector<Section_info> section_infos_;
};
- // Program properties from .note.gnu.properties sections.
+ // Program properties from .note.gnu.property sections.
struct Gnu_property
{
size_t pr_datasz;
}
if (!is_pass_two)
- layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
+ {
+ layout->merge_gnu_properties(this);
+ layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
+ }
// Handle the .eh_frame sections after the other sections.
gold_assert(!is_pass_one || eh_frame_sections.empty());
should_include_section(elfcpp::Elf_Word sh_type) const
{ return this->do_should_include_section(sh_type); }
- // Merge a target-specific program property in the .note.gnu.properties
- // section.
+ // Finalize the target-specific properties in the .note.gnu.property section.
void
- merge_gnu_property(int note_type,
- int pr_type,
- size_t new_pr_datasz,
- const unsigned char* new_pr_data,
- size_t old_pr_datasz,
- unsigned char* old_pr_data,
- const Object* object) const
- {
- return this->do_merge_gnu_property(note_type, pr_type,
- new_pr_datasz, new_pr_data,
- old_pr_datasz, old_pr_data,
- object);
- }
+ finalize_gnu_properties(Layout* layout) const
+ { this->do_finalize_gnu_properties(layout); }
protected:
// This struct holds the constant information for a child class. We
do_should_include_section(elfcpp::Elf_Word) const
{ return true; }
- // Merge a target-specific program property in the .note.gnu.properties
- // section.
+ // Finalize the target-specific properties in the .note.gnu.property section.
virtual void
- do_merge_gnu_property(int, int, size_t, const unsigned char*,
- size_t, unsigned char*, const Object*) const
+ do_finalize_gnu_properties(Layout*) const
{ }
private:
return elfcpp::elf_r_sym<size>(rel.get_r_info());
}
+ // Record a target-specific program property in the .note.gnu.property
+ // section.
+ virtual void
+ record_gnu_property(int, int, size_t, const unsigned char*, const Object*)
+ { }
+
+ // Merge the target-specific program properties from the current object.
+ virtual void
+ merge_gnu_properties(const Object*)
+ { }
+
protected:
Sized_target(const Target::Target_info* pti)
: Target(pti)
check_DATA += gnu_property_test.stdout
gnu_property_test.stdout: gnu_property_test
$(TEST_READELF) -n $< >$@
-gnu_property_test: gcctestdir/ld gnu_property_main.o gnu_property_a.o gnu_property_b.o gnu_property_c.o
- $(LINK) -Bgcctestdir/ -o $@ gnu_property_main.o gnu_property_a.o gnu_property_b.o gnu_property_c.o
+gnu_property_test: gcctestdir/ld gnu_property_a.o gnu_property_b.o gnu_property_c.o
+ gcctestdir/ld -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o
gnu_property_main.o: gnu_property_main.c
$(COMPILE) -c -o $@ $<
gnu_property_a.o: gnu_property_a.S
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -Bgcctestdir/ -Wa,-madd-bnd-prefix -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_test.stdout: gnu_property_test
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -n $< >$@
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_test: gcctestdir/ld gnu_property_main.o gnu_property_a.o gnu_property_b.o gnu_property_c.o
-@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -o $@ gnu_property_main.o gnu_property_a.o gnu_property_b.o gnu_property_c.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_test: gcctestdir/ld gnu_property_a.o gnu_property_b.o gnu_property_c.o
+@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir/ld -o $@ gnu_property_a.o gnu_property_b.o gnu_property_c.o
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_main.o: gnu_property_main.c
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $<
@DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@gnu_property_a.o: gnu_property_a.S
# define ALIGN 2
#endif
+ .text
+ .globl _start
+_start:
+ ret
+
.section ".note.gnu.property", "a"
.p2align ALIGN
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
got_mod_index_offset_(-1U), tlsdesc_reloc_info_(),
- tls_base_symbol_defined_(false)
+ tls_base_symbol_defined_(false), isa_1_used_(0), isa_1_needed_(0),
+ feature_1_(0), object_feature_1_(0), seen_first_object_(false)
{ }
// Hook for a new output section.
this->rela_dyn_section(layout));
}
- // Merge a target-specific program property in the .note.gnu.properties
+ // Record a target-specific program property in the .note.gnu.property
// section.
void
- do_merge_gnu_property(int, int, size_t, const unsigned char*,
- size_t, unsigned char*, const Object*) const;
+ record_gnu_property(int, int, size_t, const unsigned char*, const Object*);
+
+ // Merge the target-specific program properties from the current object.
+ void
+ merge_gnu_properties(const Object*);
+
+ // Finalize the target-specific program properties and add them back to
+ // the layout.
+ void
+ do_finalize_gnu_properties(Layout*) const;
// Information about this specific target which we pass to the
// general Target structure.
std::vector<Tlsdesc_info> tlsdesc_reloc_info_;
// True if the _TLS_MODULE_BASE_ symbol has been defined.
bool tls_base_symbol_defined_;
+ // Target-specific program properties, from .note.gnu.property section.
+ // Each bit represents a specific feature.
+ uint32_t isa_1_used_;
+ uint32_t isa_1_needed_;
+ uint32_t feature_1_;
+ // Target-specific properties from the current object.
+ // These bits get ANDed into FEATURE_1_ after all properties for the object
+ // have been processed.
+ uint32_t object_feature_1_;
+ // Whether we have seen our first object, for use in initializing FEATURE_1_.
+ bool seen_first_object_;
};
template<>
return this->rela_irelative_;
}
-// Merge a target-specific program property in the .note.gnu.properties
+// Record a target-specific program property from the .note.gnu.property
// section.
template<int size>
void
-Target_x86_64<size>::do_merge_gnu_property(
+Target_x86_64<size>::record_gnu_property(
int, int pr_type,
- size_t new_pr_datasz, const unsigned char* new_pr_data,
- size_t old_pr_datasz, unsigned char* old_pr_data,
- const Object*) const
+ size_t pr_datasz, const unsigned char* pr_data,
+ const Object* object)
{
- size_t min_datasz = (new_pr_datasz > old_pr_datasz
- ? old_pr_datasz
- : new_pr_datasz);
+ uint32_t val;
+
switch (pr_type)
{
case elfcpp::GNU_PROPERTY_X86_ISA_1_USED:
case elfcpp::GNU_PROPERTY_X86_ISA_1_NEEDED:
- {
- for (size_t i = 0; i < min_datasz; ++i)
- old_pr_data[i] |= new_pr_data[i];
- }
- break;
case elfcpp::GNU_PROPERTY_X86_FEATURE_1_AND:
- {
- for (size_t i = 0; i < min_datasz; ++i)
- old_pr_data[i] &= new_pr_data[i];
- }
+ if (pr_datasz != 4)
+ {
+ gold_warning(_("%s: corrupt .note.gnu.property section "
+ "(pr_datasz for property %d is not 4)"),
+ object->name().c_str(), pr_type);
+ return;
+ }
+ val = elfcpp::Swap<32, false>::readval(pr_data);
break;
default:
+ gold_warning(_("%s: unknown program property type 0x%x "
+ "in .note.gnu.property section"),
+ object->name().c_str(), pr_type);
break;
}
+
+ switch (pr_type)
+ {
+ case elfcpp::GNU_PROPERTY_X86_ISA_1_USED:
+ this->isa_1_used_ |= val;
+ break;
+ case elfcpp::GNU_PROPERTY_X86_ISA_1_NEEDED:
+ this->isa_1_needed_ |= val;
+ break;
+ case elfcpp::GNU_PROPERTY_X86_FEATURE_1_AND:
+ // If we see multiple feature props in one object, OR them together.
+ this->object_feature_1_ |= val;
+ break;
+ }
+}
+
+// Merge the target-specific program properties from the current object.
+template<int size>
+void
+Target_x86_64<size>::merge_gnu_properties(const Object*)
+{
+ if (this->seen_first_object_)
+ this->feature_1_ &= this->object_feature_1_;
+ else
+ {
+ this->feature_1_ = this->object_feature_1_;
+ this->seen_first_object_ = true;
+ }
+ this->object_feature_1_ = 0;
+}
+
+static inline void
+add_property(Layout* layout, unsigned int pr_type, uint32_t val)
+{
+ unsigned char buf[4];
+ elfcpp::Swap<32, false>::writeval(buf, val);
+ layout->add_gnu_property(elfcpp::NT_GNU_PROPERTY_TYPE_0, pr_type, 4, buf);
+}
+
+// Finalize the target-specific program properties and add them back to
+// the layout.
+template<int size>
+void
+Target_x86_64<size>::do_finalize_gnu_properties(Layout* layout) const
+{
+ if (this->isa_1_used_ != 0)
+ add_property(layout, elfcpp::GNU_PROPERTY_X86_ISA_1_USED,
+ this->isa_1_used_);
+ if (this->isa_1_needed_ != 0)
+ add_property(layout, elfcpp::GNU_PROPERTY_X86_ISA_1_NEEDED,
+ this->isa_1_needed_);
+ if (this->feature_1_ != 0)
+ add_property(layout, elfcpp::GNU_PROPERTY_X86_FEATURE_1_AND,
+ this->feature_1_);
}
// Write the first three reserved words of the .got.plt section.