if (is_prefix_of(".gnu.lto_", name))
return false;
}
+ // The GNU linker strips .gnu_debuglink sections, so we do too.
+ // This is a feature used to keep debugging information in
+ // separate files.
+ if (strcmp(name, ".gnu_debuglink") == 0)
+ return false;
return true;
default:
Script_sections* ss = this->script_options_->script_sections();
const char* file_name = relobj == NULL ? NULL : relobj->name().c_str();
Output_section** output_section_slot;
- name = ss->output_section_name(file_name, name, &output_section_slot);
+ Script_sections::Section_type script_section_type;
+ name = ss->output_section_name(file_name, name, &output_section_slot,
+ &script_section_type);
if (name == NULL)
{
// The SECTIONS clause says to discard this input section.
return NULL;
}
+ // We can only handle script section types ST_NONE and ST_NOLOAD.
+ switch (script_section_type)
+ {
+ case Script_sections::ST_NONE:
+ break;
+ case Script_sections::ST_NOLOAD:
+ flags &= elfcpp::SHF_ALLOC;
+ break;
+ default:
+ gold_unreachable();
+ }
+
// If this is an orphan section--one not mentioned in the linker
// script--then OUTPUT_SECTION_SLOT will be NULL, and we do the
// default processing below.
is_dynamic_linker_section, is_relro,
is_last_relro, is_first_non_relro);
os->set_found_in_sections_clause();
+
+ // Special handling for NOLOAD sections.
+ if (script_section_type == Script_sections::ST_NOLOAD)
+ {
+ os->set_is_noload();
+
+ // The constructor of Output_section sets addresses of non-ALLOC
+ // sections to 0 by default. We don't want that for NOLOAD
+ // sections even if they have no SHF_ALLOC flag.
+ if ((os->flags() & elfcpp::SHF_ALLOC) == 0
+ && os->is_address_valid())
+ {
+ gold_assert(os->address() == 0
+ && !os->is_offset_valid()
+ && !os->is_data_size_valid());
+ os->reset_address_and_file_offset();
+ }
+ }
+
*output_section_slot = os;
return os;
}
Output_section* os;
+ // Sometimes .init_array*, .preinit_array* and .fini_array* do not have
+ // correct section types. Force them here.
+ elfcpp::Elf_Word sh_type = shdr.get_sh_type();
+ if (sh_type == elfcpp::SHT_PROGBITS)
+ {
+ static const char init_array_prefix[] = ".init_array";
+ static const char preinit_array_prefix[] = ".preinit_array";
+ static const char fini_array_prefix[] = ".fini_array";
+ static size_t init_array_prefix_size = sizeof(init_array_prefix) - 1;
+ static size_t preinit_array_prefix_size =
+ sizeof(preinit_array_prefix) - 1;
+ static size_t fini_array_prefix_size = sizeof(fini_array_prefix) - 1;
+
+ if (strncmp(name, init_array_prefix, init_array_prefix_size) == 0)
+ sh_type = elfcpp::SHT_INIT_ARRAY;
+ else if (strncmp(name, preinit_array_prefix, preinit_array_prefix_size)
+ == 0)
+ sh_type = elfcpp::SHT_PREINIT_ARRAY;
+ else if (strncmp(name, fini_array_prefix, fini_array_prefix_size) == 0)
+ sh_type = elfcpp::SHT_FINI_ARRAY;
+ }
+
// In a relocatable link a grouped section must not be combined with
// any other sections.
if (parameters->options().relocatable()
&& (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0)
{
name = this->namepool_.add(name, true, NULL);
- os = this->make_output_section(name, shdr.get_sh_type(),
- shdr.get_sh_flags(), false, false,
- false, false, false);
+ os = this->make_output_section(name, sh_type, shdr.get_sh_flags(), false,
+ false, false, false, false);
}
else
{
- os = this->choose_output_section(object, name, shdr.get_sh_type(),
+ os = this->choose_output_section(object, name, sh_type,
shdr.get_sh_flags(), true, false,
false, false, false, false);
if (os == NULL)
// Make an output section for a script.
Output_section*
-Layout::make_output_section_for_script(const char* name)
+Layout::make_output_section_for_script(
+ const char* name,
+ Script_sections::Section_type section_type)
{
name = this->namepool_.add(name, false, NULL);
+ elfcpp::Elf_Xword sh_flags = elfcpp::SHF_ALLOC;
+ if (section_type == Script_sections::ST_NOLOAD)
+ sh_flags = 0;
Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC, false,
+ sh_flags, false,
false, false, false, false);
os->set_found_in_sections_clause();
+ if (section_type == Script_sections::ST_NOLOAD)
+ os->set_is_noload();
return os;
}
p != this->section_list_.end();
++p)
{
- (*p)->reset_address_and_file_offset();
(*p)->restore_states();
+
+ // If an input section changes size because of relaxation,
+ // we need to adjust the section offsets of all input sections.
+ // after such a section.
+ if ((*p)->section_offsets_need_adjustment())
+ (*p)->adjust_section_offsets();
+
+ (*p)->reset_address_and_file_offset();
}
// Reset special output object address and file offsets.
// If PLT_GOT is not NULL, then DT_PLTGOT points to it.
// If PLT_REL is not NULL, it is used for DT_PLTRELSZ, and DT_JMPREL,
-// and we also set DT_PLTREL.
+// and we also set DT_PLTREL. We use PLT_REL's output section, since
+// some targets have multiple reloc sections in PLT_REL.
// If DYN_REL is not NULL, it is used for DT_REL/DT_RELA,
// DT_RELSZ/DT_RELASZ, DT_RELENT/DT_RELAENT.
void
Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got,
const Output_data* plt_rel,
- const Output_data* dyn_rel, bool add_debug)
+ const Output_data_reloc_generic* dyn_rel,
+ bool add_debug, bool dynrel_includes_plt)
{
Output_data_dynamic* odyn = this->dynamic_data_;
if (odyn == NULL)
if (plt_rel != NULL && plt_rel->output_section() != NULL)
{
- odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel);
- odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel);
+ odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel->output_section());
+ odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel->output_section());
odyn->add_constant(elfcpp::DT_PLTREL,
use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA);
}
{
odyn->add_section_address(use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA,
dyn_rel);
- odyn->add_section_size(use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ,
- dyn_rel);
+ if (plt_rel != NULL && dynrel_includes_plt)
+ odyn->add_section_size(use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ,
+ dyn_rel, plt_rel);
+ else
+ odyn->add_section_size(use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ,
+ dyn_rel);
const int size = parameters->target().get_size();
elfcpp::DT rel_tag;
int rel_size;
gold_unreachable();
}
odyn->add_constant(rel_tag, rel_size);
+
+ if (parameters->options().combreloc())
+ {
+ size_t c = dyn_rel->relative_reloc_count();
+ if (c > 0)
+ odyn->add_constant((use_rel
+ ? elfcpp::DT_RELCOUNT
+ : elfcpp::DT_RELACOUNT),
+ c);
+ }
}
if (add_debug && !parameters->options().shared())
MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
- MAPPING_INIT(".ARM.extab.", ".ARM.extab"),
+ MAPPING_INIT(".ARM.extab", ".ARM.extab"),
MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
- MAPPING_INIT(".ARM.exidx.", ".ARM.exidx"),
+ MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
};
#undef MAPPING_INIT