special_output_list_(),
section_headers_(NULL),
tls_segment_(NULL),
+ relro_segment_(NULL),
symtab_section_(NULL),
symtab_xindex_(NULL),
dynsym_section_(NULL),
if (parameters->options().strip_debug()
&& (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
{
- // Debugging sections can only be recognized by name.
- if (is_prefix_of(".debug", name)
- || is_prefix_of(".gnu.linkonce.wi.", name)
- || is_prefix_of(".line", name)
- || is_prefix_of(".stab", name))
+ if (is_debug_info_section(name))
return false;
}
if (parameters->options().strip_debug_gdb()
const char* group_section_name,
const char* signature,
const elfcpp::Shdr<size, big_endian>& shdr,
- const elfcpp::Elf_Word* contents)
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* shndxes)
{
gold_assert(parameters->options().relocatable());
gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP);
section_size_type entry_count =
convert_to_section_size_type(shdr.get_sh_size() / 4);
Output_section_data* posd =
- new Output_data_group<size, big_endian>(object, entry_count, contents);
+ new Output_data_group<size, big_endian>(object, entry_count, flags,
+ shndxes);
os->add_output_section_data(posd);
}
return os;
}
-// Add POSD to an output section using NAME, TYPE, and FLAGS.
+// Add POSD to an output section using NAME, TYPE, and FLAGS. Return
+// the output section.
-void
+Output_section*
Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
Output_section_data* posd)
false);
if (os != NULL)
os->add_output_section_data(posd);
+ return os;
}
// Map section flags to segment flags.
|| strcmp(name, ".fini_array") == 0))
os->set_may_sort_attached_input_sections();
+ // With -z relro, we have to recognize the special sections by name.
+ // There is no other way.
+ if (!this->script_options_->saw_sections_clause()
+ && parameters->options().relro()
+ && type == elfcpp::SHT_PROGBITS
+ && (flags & elfcpp::SHF_ALLOC) != 0
+ && (flags & elfcpp::SHF_WRITE) != 0)
+ {
+ if (strcmp(name, ".data.rel.ro") == 0)
+ os->set_is_relro();
+ else if (strcmp(name, ".data.rel.ro.local") == 0)
+ {
+ os->set_is_relro();
+ os->set_is_relro_local();
+ }
+ }
+
// If we have already attached the sections to segments, then we
// need to attach this one now. This happens for sections created
// directly by the linker.
seg_flags);
this->tls_segment_->add_output_section(os, seg_flags);
}
+
+ // If -z relro is in effect, and we see a relro section, we create a
+ // PT_GNU_RELRO segment. There can only be one such segment.
+ if (os->is_relro() && parameters->options().relro())
+ {
+ gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W));
+ if (this->relro_segment_ == NULL)
+ this->relro_segment_ = this->make_output_segment(elfcpp::PT_GNU_RELRO,
+ seg_flags);
+ this->relro_segment_->add_output_section(os, seg_flags);
+ }
}
// Make an output section for a script.
(elfcpp::SHF_ALLOC
| elfcpp::SHF_WRITE),
false);
+ this->dynamic_section_->set_is_relro();
symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
return false;
- // We put the PT_TLS segment last, because that is where the dynamic
- // linker expects to find it (this is just for efficiency; other
- // positions would also work correctly).
- if (type1 == elfcpp::PT_TLS && type2 != elfcpp::PT_TLS)
+ // We put the PT_TLS segment last except for the PT_GNU_RELRO
+ // segment, because that is where the dynamic linker expects to find
+ // it (this is just for efficiency; other positions would also work
+ // correctly).
+ if (type1 == elfcpp::PT_TLS
+ && type2 != elfcpp::PT_TLS
+ && type2 != elfcpp::PT_GNU_RELRO)
+ return false;
+ if (type2 == elfcpp::PT_TLS
+ && type1 != elfcpp::PT_TLS
+ && type1 != elfcpp::PT_GNU_RELRO)
+ return true;
+
+ // We put the PT_GNU_RELRO segment last, because that is where the
+ // dynamic linker expects to find it (as with PT_TLS, this is just
+ // for efficiency).
+ if (type1 == elfcpp::PT_GNU_RELRO && type2 != elfcpp::PT_GNU_RELRO)
return false;
- if (type2 == elfcpp::PT_TLS && type1 != elfcpp::PT_TLS)
+ if (type2 == elfcpp::PT_GNU_RELRO && type1 != elfcpp::PT_GNU_RELRO)
return true;
const elfcpp::Elf_Word flags1 = seg1->flags();
{
Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
elfcpp::PF_R);
- oseg->add_initial_output_section(osec, elfcpp::PF_R);
+ oseg->add_output_section(osec, elfcpp::PF_R);
}
}
Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
(elfcpp::PF_R
| elfcpp::PF_W));
- oseg->add_initial_output_section(this->dynamic_section_,
- elfcpp::PF_R | elfcpp::PF_W);
+ oseg->add_output_section(this->dynamic_section_,
+ elfcpp::PF_R | elfcpp::PF_W);
}
Output_data_dynamic* const odyn = this->dynamic_data_;
#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
{
- MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Must be before "d".
+ MAPPING_INIT("d.rel.ro.local", ".data.rel.ro.local"), // Before "d.rel.ro".
+ MAPPING_INIT("d.rel.ro", ".data.rel.ro"), // Before "d".
MAPPING_INIT("t", ".text"),
MAPPING_INIT("r", ".rodata"),
MAPPING_INIT("d", ".data"),
// initial '.', we use the name unchanged (i.e., "mysection" and
// ".text" are unchanged).
+ // If the name starts with ".data.rel.ro.local" we use
+ // ".data.rel.ro.local".
+
// If the name starts with ".data.rel.ro" we use ".data.rel.ro".
// Otherwise, we drop the second '.' and everything that comes after
if (sdot == NULL)
return name;
+ const char* const data_rel_ro_local = ".data.rel.ro.local";
+ if (strncmp(name, data_rel_ro_local, strlen(data_rel_ro_local)) == 0)
+ {
+ *plen = strlen(data_rel_ro_local);
+ return data_rel_ro_local;
+ }
+
const char* const data_rel_ro = ".data.rel.ro";
if (strncmp(name, data_rel_ro, strlen(data_rel_ro)) == 0)
{
// want a linkonce signature to block another linkonce signature.
bool
-Layout::add_comdat(const char* signature, bool group)
+Layout::add_comdat(Relobj* object, unsigned int shndx,
+ const std::string& signature, bool group)
{
- std::string sig(signature);
+ Kept_section kept(object, shndx, group);
std::pair<Signatures::iterator, bool> ins(
- this->signatures_.insert(std::make_pair(sig, group)));
+ this->signatures_.insert(std::make_pair(signature, kept)));
if (ins.second)
{
return true;
}
- if (ins.first->second)
+ if (ins.first->second.group_)
{
// We've already seen a real section group with this signature.
return false;
// This is a real section group, and we've already seen a
// linkonce section with this signature. Record that we've seen
// a section group, and don't include this section group.
- ins.first->second = true;
+ ins.first->second.group_ = true;
return false;
}
else
}
}
+// Find the given comdat signature, and return the object and section
+// index of the kept group.
+Relobj*
+Layout::find_kept_object(const std::string& signature,
+ unsigned int* pshndx) const
+{
+ Signatures::const_iterator p = this->signatures_.find(signature);
+ if (p == this->signatures_.end())
+ return NULL;
+ if (pshndx != NULL)
+ *pshndx = p->second.shndx_;
+ return p->second.object_;
+}
+
// Store the allocated sections into the section list.
void
const char* group_section_name,
const char* signature,
const elfcpp::Shdr<32, false>& shdr,
- const elfcpp::Elf_Word* contents);
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* shndxes);
#endif
#ifdef HAVE_TARGET_32_BIG
const char* group_section_name,
const char* signature,
const elfcpp::Shdr<32, true>& shdr,
- const elfcpp::Elf_Word* contents);
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* shndxes);
#endif
#ifdef HAVE_TARGET_64_LITTLE
const char* group_section_name,
const char* signature,
const elfcpp::Shdr<64, false>& shdr,
- const elfcpp::Elf_Word* contents);
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* shndxes);
#endif
#ifdef HAVE_TARGET_64_BIG
const char* group_section_name,
const char* signature,
const elfcpp::Shdr<64, true>& shdr,
- const elfcpp::Elf_Word* contents);
+ elfcpp::Elf_Word flags,
+ std::vector<unsigned int>* shndxes);
#endif
#ifdef HAVE_TARGET_32_LITTLE