// layout.cc -- lay out output file sections for gold
-// Copyright (C) 2006-2018 Free Software Foundation, Inc.
+// Copyright (C) 2006-2020 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
unique_segment_for_sections_specified_(false),
incremental_inputs_(NULL),
record_output_section_data_from_script_(false),
+ lto_slim_object_(false),
script_output_section_data_list_(),
segment_states_(NULL),
relaxation_debug_check_(NULL),
".text.unlikely",
".text.exit",
".text.startup",
- ".text.hot"
+ ".text.hot",
+ ".text.sorted"
};
for (size_t i = 0;
// All ".text.unlikely.*" sections can be moved to a unique
// segment with --text-unlikely-segment option.
bool text_unlikely_segment
- = (parameters->options().text_unlikely_segment()
- && is_prefix_of(".text.unlikely",
- object->section_name(shndx).c_str()));
+ = (parameters->options().text_unlikely_segment()
+ && is_prefix_of(".text.unlikely",
+ object->section_name(shndx).c_str()));
if (text_unlikely_segment)
- {
+ {
elfcpp::Elf_Xword flags
= this->get_output_section_flags(shdr.get_sh_flags());
&name_key);
os = this->get_output_section(os_name, name_key, sh_type, 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"
- // that is likely executed.
+ // Map this output section to a unique segment. This is done to
+ // separate "text" that is not likely to be executed from "text"
+ // that is likely executed.
os->set_is_unique_segment();
- }
+ }
else
{
// Plugins can choose to place one or more subsets of sections in
// 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());
+ = this->get_output_section_flags(shdr.get_sh_flags());
const char* os_name = it->second->name;
Stringpool::Key name_key;
os = this->get_output_section(os_name, name_key, sh_type, flags,
ORDER_INVALID, false);
if (!os->is_unique_segment())
- {
- os->set_is_unique_segment();
- os->set_extra_segment_flags(it->second->flags);
- os->set_segment_alignment(it->second->align);
- }
+ {
+ os->set_is_unique_segment();
+ os->set_extra_segment_flags(it->second->flags);
+ os->set_segment_alignment(it->second->align);
+ }
}
}
if (os == NULL)
}
}
-// Remove .eh_frame information for a PLT. FDEs using the CIE must
-// be removed in reverse order to the order they were added.
+// Remove all post-map .eh_frame information for a PLT.
void
Layout::remove_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data,
- size_t cie_length, const unsigned char* fde_data,
- size_t fde_length)
+ size_t cie_length)
{
if (parameters->incremental())
{
// FIXME: Maybe this could work some day....
return;
}
- this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length,
- fde_data, fde_length);
+ this->eh_frame_data_->remove_ehframe_for_plt(plt, cie_data, cie_length);
}
// Scan a .debug_info or .debug_types section, and add summary
}
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)
{
- // 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);
+ 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
{
- 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_32_LITTLE
+ parameters->sized_target<32, false>()->merge_gnu_properties(object);
+#else
+ gold_unreachable();
+#endif
}
}
+ else if (size == 64)
+ {
+ if (is_big_endian)
+ {
+#ifdef HAVE_TARGET_64_BIG
+ parameters->sized_target<64, true>()->merge_gnu_properties(object);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ {
+#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.
void
Layout::define_section_symbols(Symbol_table* symtab)
{
+ const elfcpp::STV visibility = parameters->options().start_stop_visibility_enum();
for (Section_list::const_iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
0, // symsize
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
- elfcpp::STV_PROTECTED,
+ visibility,
0, // nonvis
false, // offset_is_from_end
true); // only_if_ref
0, // symsize
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
- elfcpp::STV_PROTECTED,
+ visibility,
0, // nonvis
true, // offset_is_from_end
true); // only_if_ref
gold_fatal(_("unable to open --section-ordering-file file %s: %s"),
filename, strerror(errno));
+ File_read::record_file_read(filename);
+
std::getline(in, line); // this chops off the trailing \n, if any
unsigned int position = 1;
this->set_section_ordering_specified();
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;
write_sized_value(datasz, 4, p + 4, is_big_endian);
memcpy(p + 8, prop->second.pr_data, datasz);
if (aligned_datasz > datasz)
- memset(p + 8 + datasz, 0, aligned_datasz - datasz);
+ memset(p + 8 + datasz, 0, aligned_datasz - datasz);
p += 8 + aligned_datasz;
}
Output_section_data* posd = new Output_data_const(desc, descsz, 4);
flags |= elfcpp::DF_1_NOW;
if (parameters->options().Bgroup())
flags |= elfcpp::DF_1_GROUP;
+ if (parameters->options().pie())
+ flags |= elfcpp::DF_1_PIE;
if (flags != 0)
odyn->add_constant(elfcpp::DT_FLAGS_1, flags);
}
MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
+ MAPPING_INIT(".gnu.build.attributes.", ".gnu.build.attributes"),
};
// Mapping for ".text" section prefixes with -z,keep-text-section-prefix.
if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF)
this->layout_->write_binary(this->of_);
+ if (this->options_->dependency_file())
+ File_read::write_dependency_file(this->options_->dependency_file(),
+ this->options_->output_file_name());
+
this->of_->close();
}