summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elfcpp/elfcpp_file.h45
-rw-r--r--gold/defstd.cc8
-rw-r--r--gold/dynobj.h10
-rw-r--r--gold/expression.cc80
-rw-r--r--gold/gold.cc9
-rw-r--r--gold/layout.cc388
-rw-r--r--gold/layout.h36
-rw-r--r--gold/object.h31
-rw-r--r--gold/output.cc269
-rw-r--r--gold/output.h243
-rw-r--r--gold/po/POTFILES.in2
-rw-r--r--gold/po/gold.pot350
-rw-r--r--gold/script-sections.cc1521
-rw-r--r--gold/script-sections.h55
-rw-r--r--gold/script.cc140
-rw-r--r--gold/script.h56
-rw-r--r--gold/symtab.cc35
-rw-r--r--gold/symtab.h16
-rw-r--r--gold/testsuite/Makefile.am5
-rw-r--r--gold/testsuite/script_test_2.cc69
-rw-r--r--gold/testsuite/script_test_2.t63
-rw-r--r--gold/testsuite/script_test_2a.cc24
-rw-r--r--gold/testsuite/script_test_2b.cc24
-rw-r--r--gold/yyscript.y3
24 files changed, 3064 insertions, 418 deletions
diff --git a/elfcpp/elfcpp_file.h b/elfcpp/elfcpp_file.h
index 3228332b83..f9f28efdb4 100644
--- a/elfcpp/elfcpp_file.h
+++ b/elfcpp/elfcpp_file.h
@@ -131,6 +131,10 @@ class Elf_file
typename File::Location
section_contents(unsigned int shndx);
+ // Return the size of section SHNDX.
+ typename Elf_types<size>::Elf_WXword
+ section_size(unsigned int shndx);
+
// Return the flags of section SHNDX.
typename Elf_types<size>::Elf_WXword
section_flags(unsigned int shndx);
@@ -147,6 +151,9 @@ class Elf_file
Elf_Word
section_info(unsigned int shndx);
+ // Return the addralign field of section SHNDX.
+ typename Elf_types<size>::Elf_WXword
+ section_addralign(unsigned int shndx);
private:
// Shared constructor code.
@@ -296,6 +303,25 @@ Elf_file<size, big_endian, File>::section_contents(unsigned int shndx)
return typename File::Location(shdr.get_sh_offset(), shdr.get_sh_size());
}
+// Get the size of section SHNDX.
+
+template<int size, bool big_endian, typename File>
+typename Elf_types<size>::Elf_WXword
+Elf_file<size, big_endian, File>::section_size(unsigned int shndx)
+{
+ File* const file = this->file_;
+
+ if (shndx >= this->shnum())
+ file->error(_("section_size: bad shndx %u >= %u"),
+ shndx, this->shnum());
+
+ typename File::View v(file->view(this->section_header_offset(shndx),
+ This::shdr_size));
+
+ Ef_shdr shdr(v.data());
+ return shdr.get_sh_size();
+}
+
// Return the section flags of section SHNDX.
template<int size, bool big_endian, typename File>
@@ -372,6 +398,25 @@ Elf_file<size, big_endian, File>::section_info(unsigned int shndx)
return shdr.get_sh_info();
}
+// Return the sh_addralign field of section SHNDX.
+
+template<int size, bool big_endian, typename File>
+typename Elf_types<size>::Elf_WXword
+Elf_file<size, big_endian, File>::section_addralign(unsigned int shndx)
+{
+ File* const file = this->file_;
+
+ if (shndx >= this->shnum())
+ file->error(_("section_addralign: bad shndx %u >= %u"),
+ shndx, this->shnum());
+
+ typename File::View v(file->view(this->section_header_offset(shndx),
+ This::shdr_size));
+
+ Ef_shdr shdr(v.data());
+ return shdr.get_sh_addralign();
+}
+
} // End namespace elfcpp.
#endif // !defined(ELFCPP_FILE_H)
diff --git a/gold/defstd.cc b/gold/defstd.cc
index 944af3e086..984f3e1b04 100644
--- a/gold/defstd.cc
+++ b/gold/defstd.cc
@@ -23,6 +23,7 @@
#include "gold.h"
#include "symtab.h"
+#include "layout.h"
#include "defstd.h"
// This is a simple file which defines the standard symbols like
@@ -251,8 +252,11 @@ namespace gold
void
define_standard_symbols(Symbol_table* symtab, const Layout* layout)
{
- symtab->define_symbols(layout, in_section_count, in_section);
- symtab->define_symbols(layout, in_segment_count, in_segment);
+ bool saw_sections_clause = layout->script_options()->saw_sections_clause();
+ symtab->define_symbols(layout, in_section_count, in_section,
+ saw_sections_clause);
+ symtab->define_symbols(layout, in_segment_count, in_segment,
+ saw_sections_clause);
}
} // End namespace gold.
diff --git a/gold/dynobj.h b/gold/dynobj.h
index 0b22362039..67b0f51d46 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -176,6 +176,11 @@ class Sized_dynobj : public Dynobj
void
do_add_symbols(Symbol_table*, Read_symbols_data*);
+ // Get the size of a section.
+ uint64_t
+ do_section_size(unsigned int shndx)
+ { return this->elf_file_.section_size(shndx); }
+
// Get the name of a section.
std::string
do_section_name(unsigned int shndx)
@@ -207,6 +212,11 @@ class Sized_dynobj : public Dynobj
do_section_info(unsigned int shndx)
{ return this->elf_file_.section_info(shndx); }
+ // Return the section alignment.
+ uint64_t
+ do_section_addralign(unsigned int shndx)
+ { return this->elf_file_.section_addralign(shndx); }
+
private:
// For convenience.
typedef Sized_dynobj<size, big_endian> This;
diff --git a/gold/expression.cc b/gold/expression.cc
index 533b0255fc..e8fd9fd895 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -36,14 +36,33 @@ namespace gold
// This file holds the code which handles linker expressions.
+// The dot symbol, which linker scripts refer to simply as ".",
+// requires special treatment. The dot symbol is set several times,
+// section addresses will refer to it, output sections will change it,
+// and it can be set based on the value of other symbols. We simplify
+// the handling by prohibiting setting the dot symbol to the value of
+// a non-absolute symbol.
+
// When evaluating the value of an expression, we pass in a pointer to
// this struct, so that the expression evaluation can find the
// information it needs.
struct Expression::Expression_eval_info
{
+ // The symbol table.
const Symbol_table* symtab;
+ // The layout--we use this to get section information.
const Layout* layout;
+ // Whether expressions can refer to the dot symbol. The dot symbol
+ // is only available within a SECTIONS clause.
+ bool is_dot_available;
+ // Whether the dot symbol currently has a value.
+ bool dot_has_value;
+ // The current value of the dot symbol.
+ uint64_t dot_value;
+ // Points to the IS_ABSOLUTE variable, which is set to false if the
+ // expression uses a value which is not absolute.
+ bool* is_absolute;
};
// Evaluate an expression.
@@ -51,9 +70,41 @@ struct Expression::Expression_eval_info
uint64_t
Expression::eval(const Symbol_table* symtab, const Layout* layout)
{
+ bool dummy;
+ return this->eval_maybe_dot(symtab, layout, false, false, 0, &dummy);
+}
+
+// Evaluate an expression which may refer to the dot symbol.
+
+uint64_t
+Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
+ bool dot_has_value, uint64_t dot_value,
+ bool* is_absolute)
+{
+ return this->eval_maybe_dot(symtab, layout, true, dot_has_value, dot_value,
+ is_absolute);
+}
+
+// Evaluate an expression which may or may not refer to the dot
+// symbol.
+
+uint64_t
+Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
+ bool is_dot_available, bool dot_has_value,
+ uint64_t dot_value, bool* is_absolute)
+{
Expression_eval_info eei;
eei.symtab = symtab;
eei.layout = layout;
+ eei.is_dot_available = is_dot_available;
+ eei.dot_has_value = dot_has_value;
+ eei.dot_value = dot_value;
+
+ // We assume the value is absolute, and only set this to false if we
+ // find a section relative reference.
+ *is_absolute = true;
+ eei.is_absolute = is_absolute;
+
return this->value(&eei);
}
@@ -115,6 +166,14 @@ Symbol_expression::value(const Expression_eval_info* eei)
return 0;
}
+ // If this symbol does not have an absolute value, then the whole
+ // expression does not have an absolute value. This is not strictly
+ // accurate: the subtraction of two symbols in the same section is
+ // absolute. This is unlikely to matter in practice, as this value
+ // is only used for error checking.
+ if (!sym->value_is_absolute())
+ *eei->is_absolute = false;
+
if (parameters->get_size() == 32)
return eei->symtab->get_sized_symbol<32>(sym)->value();
else if (parameters->get_size() == 64)
@@ -141,10 +200,21 @@ class Dot_expression : public Expression
};
uint64_t
-Dot_expression::value(const Expression_eval_info*)
+Dot_expression::value(const Expression_eval_info* eei)
{
- gold_error("dot symbol unimplemented");
- return 0;
+ if (!eei->is_dot_available)
+ {
+ gold_error(_("invalid reference to dot symbol outside of "
+ "SECTIONS clause"));
+ return 0;
+ }
+ else if (!eei->dot_has_value)
+ {
+ gold_error(_("invalid reference to dot symbol before "
+ "it has been given a value"));
+ return 0;
+ }
+ return eei->dot_value;
}
// A string. This is either the name of a symbol, or ".".
@@ -549,6 +619,10 @@ Addr_expression::value(const Expression_eval_info* eei)
section_name);
return 0;
}
+
+ // Note that the address of a section is an absolute address, and we
+ // should not clear *EEI->IS_ABSOLUTE here.
+
return os->address();
}
diff --git a/gold/gold.cc b/gold/gold.cc
index c738e31f74..aa6f32a87f 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -198,17 +198,16 @@ queue_middle_tasks(const General_options& options,
// handles some cases we want to see before we read the relocs.
layout->create_initial_dynamic_sections(symtab);
- // Predefine standard symbols. This should be fast, so we don't
- // bother to create a task for it.
+ // Define symbols from any linker scripts.
+ layout->define_script_symbols(symtab);
+
+ // Predefine standard symbols.
define_standard_symbols(symtab, layout);
// Define __start and __stop symbols for output sections where
// appropriate.
layout->define_section_symbols(symtab);
- // Define symbols from any linker scripts.
- layout->define_script_symbols(symtab);
-
// Read the relocations of the input files. We do this to find
// which symbols are used by relocations which require a GOT and/or
// a PLT entry, or a COPY reloc. When we implement garbage
diff --git a/gold/layout.cc b/gold/layout.cc
index 3969283f3e..a0fcc49d6a 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -29,6 +29,8 @@
#include "parameters.h"
#include "options.h"
+#include "script.h"
+#include "script-sections.h"
#include "output.h"
#include "symtab.h"
#include "dynobj.h"
@@ -185,11 +187,11 @@ Layout::include_section(Sized_relobj<size, big_endian>*, const char* name,
Output_section*
Layout::find_output_section(const char* name) const
{
- for (Section_name_map::const_iterator p = this->section_name_map_.begin();
- p != this->section_name_map_.end();
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
++p)
- if (strcmp(p->second->name(), name) == 0)
- return p->second;
+ if (strcmp((*p)->name(), name) == 0)
+ return *p;
return NULL;
}
@@ -211,19 +213,13 @@ Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
}
// Return the output section to use for section NAME with type TYPE
-// and section flags FLAGS.
+// and section flags FLAGS. NAME must be canonicalized in the string
+// pool, and NAME_KEY is the key.
Output_section*
Layout::get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags)
{
- // We should ignore some flags.
- flags &= ~ (elfcpp::SHF_INFO_LINK
- | elfcpp::SHF_LINK_ORDER
- | elfcpp::SHF_GROUP
- | elfcpp::SHF_MERGE
- | elfcpp::SHF_STRINGS);
-
const Key key(name_key, std::make_pair(type, flags));
const std::pair<Key, Output_section*> v(key, NULL);
std::pair<Section_name_map::iterator, bool> ins(
@@ -241,6 +237,80 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key,
}
}
+// Pick the output section to use for section NAME, in input file
+// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a
+// linker created section. ADJUST_NAME is true if we should apply the
+// standard name mappings in Layout::output_section_name. This will
+// return NULL if the input section should be discarded.
+
+Output_section*
+Layout::choose_output_section(const Relobj* relobj, const char* name,
+ elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
+ bool adjust_name)
+{
+ // We should ignore some flags. FIXME: This will need some
+ // adjustment for ld -r.
+ flags &= ~ (elfcpp::SHF_INFO_LINK
+ | elfcpp::SHF_LINK_ORDER
+ | elfcpp::SHF_GROUP
+ | elfcpp::SHF_MERGE
+ | elfcpp::SHF_STRINGS);
+
+ if (this->script_options_->saw_sections_clause())
+ {
+ // We are using a SECTIONS clause, so the output section is
+ // chosen based only on the name.
+
+ 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);
+ if (name == NULL)
+ {
+ // The SECTIONS clause says to discard this input section.
+ return NULL;
+ }
+
+ // 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.
+
+ if (output_section_slot != NULL)
+ {
+ if (*output_section_slot != NULL)
+ return *output_section_slot;
+
+ // We don't put sections found in the linker script into
+ // SECTION_NAME_MAP_. That keeps us from getting confused
+ // if an orphan section is mapped to a section with the same
+ // name as one in the linker script.
+
+ name = this->namepool_.add(name, false, NULL);
+
+ Output_section* os = this->make_output_section(name, type, flags);
+ os->set_found_in_sections_clause();
+ *output_section_slot = os;
+ return os;
+ }
+ }
+
+ // FIXME: Handle SHF_OS_NONCONFORMING somewhere.
+
+ // Turn NAME from the name of the input section into the name of the
+ // output section.
+
+ size_t len = strlen(name);
+ if (adjust_name && !parameters->output_is_object())
+ name = Layout::output_section_name(name, &len);
+
+ Stringpool::Key name_key;
+ name = this->namepool_.add_with_length(name, len, true, &name_key);
+
+ // Find or make the output section. The output section is selected
+ // based on the section name, type, and flags.
+ return this->get_output_section(name, name_key, type, flags);
+}
+
// Return the output section to use for input section SHNDX, with name
// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the
// index of a relocation section which applies to this section, or 0
@@ -260,27 +330,18 @@ Layout::layout(Sized_relobj<size, big_endian>* object, unsigned int shndx,
if (!this->include_section(object, name, shdr))
return NULL;
- // If we are not doing a relocateable link, choose the name to use
- // for the output section.
- size_t len = strlen(name);
- if (!parameters->output_is_object())
- name = Layout::output_section_name(name, &len);
-
- // FIXME: Handle SHF_OS_NONCONFORMING here.
-
- // Canonicalize the section name.
- Stringpool::Key name_key;
- name = this->namepool_.add_with_length(name, len, true, &name_key);
-
- // Find the output section. The output section is selected based on
- // the section name, type, and flags.
- Output_section* os = this->get_output_section(name, name_key,
- shdr.get_sh_type(),
- shdr.get_sh_flags());
+ Output_section* os = this->choose_output_section(object,
+ name,
+ shdr.get_sh_type(),
+ shdr.get_sh_flags(),
+ true);
+ if (os == NULL)
+ return NULL;
// FIXME: Handle SHF_LINK_ORDER somewhere.
- *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
+ *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
+ this->script_options_->saw_sections_clause());
return os;
}
@@ -304,12 +365,14 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS);
gold_assert(shdr.get_sh_flags() == elfcpp::SHF_ALLOC);
- Stringpool::Key name_key;
- const char* name = this->namepool_.add(".eh_frame", false, &name_key);
-
- Output_section* os = this->get_output_section(name, name_key,
- elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC);
+ const char* const name = ".eh_frame";
+ Output_section* os = this->choose_output_section(object,
+ name,
+ elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC,
+ false);
+ if (os == NULL)
+ return NULL;
if (this->eh_frame_section_ == NULL)
{
@@ -319,26 +382,28 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
if (this->options_.create_eh_frame_hdr())
{
- Stringpool::Key hdr_name_key;
- const char* hdr_name = this->namepool_.add(".eh_frame_hdr",
- false,
- &hdr_name_key);
Output_section* hdr_os =
- this->get_output_section(hdr_name, hdr_name_key,
- elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC);
+ this->choose_output_section(NULL,
+ ".eh_frame_hdr",
+ elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC,
+ false);
- Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, this->eh_frame_data_);
- hdr_os->add_output_section_data(hdr_posd);
+ if (hdr_os != NULL)
+ {
+ Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os,
+ this->eh_frame_data_);
+ hdr_os->add_output_section_data(hdr_posd);
- hdr_os->set_after_input_sections();
+ hdr_os->set_after_input_sections();
- Output_segment* hdr_oseg =
- new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
- this->segment_list_.push_back(hdr_oseg);
- hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
+ Output_segment* hdr_oseg =
+ new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
+ this->segment_list_.push_back(hdr_oseg);
+ hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
- this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
+ this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
+ }
}
}
@@ -357,7 +422,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
{
// We couldn't handle this .eh_frame section for some reason.
// Add it as a normal section.
- *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx);
+ bool saw_sections_clause = this->script_options_->saw_sections_clause();
+ *off = os->add_input_section(object, shndx, name, shdr, reloc_shndx,
+ saw_sections_clause);
}
return os;
@@ -370,12 +437,10 @@ Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags,
Output_section_data* posd)
{
- // Canonicalize the name.
- Stringpool::Key name_key;
- name = this->namepool_.add(name, true, &name_key);
-
- Output_section* os = this->get_output_section(name, name_key, type, flags);
- os->add_output_section_data(posd);
+ Output_section* os = this->choose_output_section(NULL, name, type, flags,
+ false);
+ if (os != NULL)
+ os->add_output_section_data(posd);
}
// Map section flags to segment flags.
@@ -428,6 +493,11 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
this->unattached_section_list_.push_back(os);
else
{
+ // If we have a SECTIONS clause, we can't handle the attachment
+ // to segments until after we've seen all the sections.
+ if (this->script_options_->saw_sections_clause())
+ return os;
+
// This output section goes into a PT_LOAD segment.
elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
@@ -581,7 +651,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
elfcpp::STV_DEFAULT,
0, // nonvis
false, // offset_is_from_end
- false); // only_if_ref
+ true); // only_if_ref
symtab->define_in_output_data(stop_name.c_str(),
NULL, // version
@@ -593,7 +663,7 @@ Layout::define_section_symbols(Symbol_table* symtab)
elfcpp::STV_DEFAULT,
0, // nonvis
true, // offset_is_from_end
- false); // only_if_ref
+ true); // only_if_ref
}
}
}
@@ -664,17 +734,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
this->create_gold_note();
this->create_executable_stack_info(target);
- Output_segment* phdr_seg = NULL;
- if (!parameters->doing_static_link())
+ if (!parameters->output_is_object() && !parameters->doing_static_link())
{
// There was a dynamic object in the link. We need to create
// some information for the dynamic linker.
- // Create the PT_PHDR segment which will hold the program
- // headers.
- phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
- this->segment_list_.push_back(phdr_seg);
-
// Create the dynamic symbol table, including the hash table.
Output_section* dynstr;
std::vector<Symbol*> dynamic_symbols;
@@ -703,15 +767,30 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
dynamic_symbols, dynstr);
}
- // FIXME: Handle PT_GNU_STACK.
+ // If there is a SECTIONS clause, put all the input sections into
+ // the required order.
+ Output_segment* load_seg;
+ if (this->script_options_->saw_sections_clause())
+ load_seg = this->set_section_addresses_from_script(symtab);
+ else
+ load_seg = this->find_first_load_seg();
- Output_segment* load_seg = this->find_first_load_seg();
+ Output_segment* phdr_seg = NULL;
+ if (load_seg != NULL
+ && !parameters->output_is_object()
+ && !parameters->doing_static_link())
+ {
+ // Create the PT_PHDR segment which will hold the program
+ // headers.
+ phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
+ this->segment_list_.push_back(phdr_seg);
+ }
// Lay out the segment headers.
Output_segment_headers* segment_headers;
segment_headers = new Output_segment_headers(this->segment_list_);
- load_seg->add_initial_output_data(segment_headers);
- this->special_output_list_.push_back(segment_headers);
+ if (load_seg != NULL)
+ load_seg->add_initial_output_data(segment_headers);
if (phdr_seg != NULL)
phdr_seg->add_initial_output_data(segment_headers);
@@ -719,8 +798,11 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
Output_file_header* file_header;
file_header = new Output_file_header(target, symtab, segment_headers,
this->script_options_->entry());
- load_seg->add_initial_output_data(file_header);
+ if (load_seg != NULL)
+ load_seg->add_initial_output_data(file_header);
+
this->special_output_list_.push_back(file_header);
+ this->special_output_list_.push_back(segment_headers);
// We set the output section indexes in set_segment_offsets and
// set_section_indexes.
@@ -970,6 +1052,27 @@ Layout::segment_precedes(const Output_segment* seg1,
return flags1 < flags2;
}
+ // If the addresses are set already, sort by load address.
+ if (seg1->are_addresses_set())
+ {
+ if (!seg2->are_addresses_set())
+ return true;
+
+ unsigned int section_count1 = seg1->output_section_count();
+ unsigned int section_count2 = seg2->output_section_count();
+ if (section_count1 == 0 && section_count2 > 0)
+ return true;
+ if (section_count1 > 0 && section_count2 == 0)
+ return false;
+
+ uint64_t paddr1 = seg1->first_section_load_address();
+ uint64_t paddr2 = seg2->first_section_load_address();
+ if (paddr1 != paddr2)
+ return paddr1 < paddr2;
+ }
+ else if (seg2->are_addresses_set())
+ return false;
+
// We sort PT_LOAD segments based on the flags. Readonly segments
// come before writable segments. Then executable segments come
// before non-executable segments. Then the unlikely case of a
@@ -984,15 +1087,9 @@ Layout::segment_precedes(const Output_segment* seg1,
if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
return (flags1 & elfcpp::PF_R) == 0;
- uint64_t vaddr1 = seg1->vaddr();
- uint64_t vaddr2 = seg2->vaddr();
- if (vaddr1 != vaddr2)
- return vaddr1 < vaddr2;
-
- uint64_t paddr1 = seg1->paddr();
- uint64_t paddr2 = seg2->paddr();
- gold_assert(paddr1 != paddr2);
- return paddr1 < paddr2;
+ // We shouldn't get here--we shouldn't create segments which we
+ // can't distinguish.
+ gold_unreachable();
}
// Set the file offsets of all the segments, and all the sections they
@@ -1010,13 +1107,29 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
uint64_t addr;
- if (parameters->output_is_shared())
- addr = 0;
- else if (options_.user_set_text_segment_address())
+ if (this->options_.user_set_text_segment_address())
addr = options_.text_segment_address();
+ else if (parameters->output_is_shared())
+ addr = 0;
else
addr = target->default_text_segment_address();
off_t off = 0;
+
+ // If LOAD_SEG is NULL, then the file header and segment headers
+ // will not be loadable. But they still need to be at offset 0 in
+ // the file. Set their offsets now.
+ if (load_seg == NULL)
+ {
+ for (Data_list::iterator p = this->special_output_list_.begin();
+ p != this->special_output_list_.end();
+ ++p)
+ {
+ off = align_address(off, (*p)->addralign());
+ (*p)->set_address_and_file_offset(0, off);
+ off += (*p)->data_size();
+ }
+ }
+
bool was_readonly = false;
for (Segment_list::iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
@@ -1028,34 +1141,55 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
gold_unreachable();
load_seg = NULL;
- // If the last segment was readonly, and this one is not,
- // then skip the address forward one page, maintaining the
- // same position within the page. This lets us store both
- // segments overlapping on a single page in the file, but
- // the loader will put them on different pages in memory.
-
uint64_t orig_addr = addr;
uint64_t orig_off = off;
- uint64_t aligned_addr = addr;
+ uint64_t aligned_addr = 0;
uint64_t abi_pagesize = target->abi_pagesize();
- // FIXME: This should depend on the -n and -N options.
- (*p)->set_minimum_addralign(target->common_pagesize());
+ // FIXME: This should depend on the -n and -N options.
+ (*p)->set_minimum_p_align(target->common_pagesize());
- if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
+ bool are_addresses_set = (*p)->are_addresses_set();
+ if (are_addresses_set)
{
- uint64_t align = (*p)->addralign();
-
- addr = align_address(addr, align);
+ // When it comes to setting file offsets, we care about
+ // the physical address.
+ addr = (*p)->paddr();
+
+ // Adjust the file offset to the same address modulo the
+ // page size.
+ uint64_t unsigned_off = off;
+ uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1))
+ | (addr & (abi_pagesize - 1)));
+ if (aligned_off < unsigned_off)
+ aligned_off += abi_pagesize;
+ off = aligned_off;
+ }
+ else
+ {
+ // If the last segment was readonly, and this one is
+ // not, then skip the address forward one page,
+ // maintaining the same position within the page. This
+ // lets us store both segments overlapping on a single
+ // page in the file, but the loader will put them on
+ // different pages in memory.
+
+ addr = align_address(addr, (*p)->maximum_alignment());
aligned_addr = addr;
- if ((addr & (abi_pagesize - 1)) != 0)
- addr = addr + abi_pagesize;
+
+ if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
+ {
+ if ((addr & (abi_pagesize - 1)) != 0)
+ addr = addr + abi_pagesize;
+ }
+
+ off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
}
unsigned int shndx_hold = *pshndx;
- off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
- uint64_t new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
+ uint64_t new_addr = (*p)->set_section_addresses(false, addr, &off,
+ pshndx);
// Now that we know the size of this segment, we may be able
// to save a page in memory, at the cost of wasting some
@@ -1063,7 +1197,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
// page. Here we use the real machine page size rather than
// the ABI mandated page size.
- if (aligned_addr != addr)
+ if (!are_addresses_set && aligned_addr != addr)
{
uint64_t common_pagesize = target->common_pagesize();
uint64_t first_off = (common_pagesize
@@ -1078,8 +1212,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
{
*pshndx = shndx_hold;
addr = align_address(aligned_addr, common_pagesize);
+ addr = align_address(addr, (*p)->maximum_alignment());
off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
- new_addr = (*p)->set_section_addresses(addr, &off, pshndx);
+ new_addr = (*p)->set_section_addresses(true, addr, &off,
+ pshndx);
}
}
@@ -1172,6 +1308,30 @@ Layout::set_section_indexes(unsigned int shndx)
return shndx;
}
+// Set the section addresses according to the linker script. This is
+// only called when we see a SECTIONS clause. This returns the
+// program segment which should hold the file header and segment
+// headers, if any. It will return NULL if they should not be in a
+// segment.
+
+Output_segment*
+Layout::set_section_addresses_from_script(Symbol_table* symtab)
+{
+ Script_sections* ss = this->script_options_->script_sections();
+ gold_assert(ss->saw_sections_clause());
+
+ // Place each orphaned output section in the script.
+ for (Section_list::iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ {
+ if (!(*p)->found_in_sections_clause())
+ ss->place_orphan(*p);
+ }
+
+ return this->script_options_->set_section_addresses(symtab, this);
+}
+
// Count the local symbols in the regular symbol table and the dynamic
// symbol table, and build the respective string pools.
@@ -1963,6 +2123,28 @@ Layout::add_comdat(const char* signature, bool group)
}
}
+// Store the allocated sections into the section list.
+
+void
+Layout::get_allocated_sections(Section_list* section_list) const
+{
+ for (Section_list::const_iterator p = this->section_list_.begin();
+ p != this->section_list_.end();
+ ++p)
+ if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0)
+ section_list->push_back(*p);
+}
+
+// Create an output segment.
+
+Output_segment*
+Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
+{
+ Output_segment* oseg = new Output_segment(type, flags);
+ this->segment_list_.push_back(oseg);
+ return oseg;
+}
+
// Write out the Output_sections. Most won't have anything to write,
// since most of the data will come from input sections which are
// handled elsewhere. But some Output_sections do have Output_data.
diff --git a/gold/layout.h b/gold/layout.h
index f070039417..ceacf5dd41 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -260,11 +260,11 @@ class Layout
void
print_stats() const;
- // The list of segments.
+ // A list of segments.
typedef std::vector<Output_segment*> Segment_list;
- // The list of sections not attached to a segment.
+ // A list of sections.
typedef std::vector<Output_section*> Section_list;
@@ -272,6 +272,24 @@ class Layout
// either a section or a segment.
typedef std::vector<Output_data*> Data_list;
+ // Store the allocated sections into the section list. This is used
+ // by the linker script code.
+ void
+ get_allocated_sections(Section_list*) const;
+
+ // Make a segment. This is used by the linker script code.
+ Output_segment*
+ make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags);
+
+ // Return the number of segments.
+ size_t
+ segment_count() const
+ { return this->segment_list_.size(); }
+
+ // Map from section flags to segment flags.
+ static elfcpp::Elf_Word
+ section_flags_to_segment(elfcpp::Elf_Xword flags);
+
private:
Layout(const Layout&);
Layout& operator=(const Layout&);
@@ -376,6 +394,12 @@ class Layout
get_output_section(const char* name, Stringpool::Key name_key,
elfcpp::Elf_Word type, elfcpp::Elf_Xword flags);
+ // Choose the output section for NAME in RELOBJ.
+ Output_section*
+ choose_output_section(const Relobj* relobj, const char* name,
+ elfcpp::Elf_Word type, elfcpp::Elf_Xword flags,
+ bool adjust_name);
+
// Create a new Output_section.
Output_section*
make_output_section(const char* name, elfcpp::Elf_Word type,
@@ -405,14 +429,14 @@ class Layout
unsigned int
set_section_indexes(unsigned int pshndx);
+ // Set the section addresses when using a script.
+ Output_segment*
+ set_section_addresses_from_script(Symbol_table*);
+
// Return whether SEG1 comes before SEG2 in the output file.
static bool
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
- // Map from section flags to segment flags.
- static elfcpp::Elf_Word
- section_flags_to_segment(elfcpp::Elf_Xword flags);
-
// A mapping used for group signatures.
typedef Unordered_map<std::string, bool> Signatures;
diff --git a/gold/object.h b/gold/object.h
index e4140be8fc..5a62546670 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -206,8 +206,12 @@ class Object
const unsigned char*
section_contents(unsigned int shndx, section_size_type* plen, bool cache);
- // Return the name of a section given a section index. This is only
- // used for error messages.
+ // Return the size of a section given a section index.
+ uint64_t
+ section_size(unsigned int shndx)
+ { return this->do_section_size(shndx); }
+
+ // Return the name of a section given a section index.
std::string
section_name(unsigned int shndx)
{ return this->do_section_name(shndx); }
@@ -232,6 +236,11 @@ class Object
section_info(unsigned int shndx)
{ return this->do_section_info(shndx); }
+ // Return the required section alignment given a section index.
+ uint64_t
+ section_addralign(unsigned int shndx)
+ { return this->do_section_addralign(shndx); }
+
// Read the symbol information.
void
read_symbols(Read_symbols_data* sd)
@@ -344,6 +353,10 @@ class Object
virtual Location
do_section_contents(unsigned int shndx) = 0;
+ // Get the size of a section--implemented by child class.
+ virtual uint64_t
+ do_section_size(unsigned int shndx) = 0;
+
// Get the name of a section--implemented by child class.
virtual std::string
do_section_name(unsigned int shndx) = 0;
@@ -364,6 +377,10 @@ class Object
virtual unsigned int
do_section_info(unsigned int shndx) = 0;
+ // Get section alignment--implemented by child class.
+ virtual uint64_t
+ do_section_addralign(unsigned int shndx) = 0;
+
// Get the file. We pass on const-ness.
Input_file*
input_file()
@@ -1136,6 +1153,11 @@ class Sized_relobj : public Relobj
do_relocate(const General_options& options, const Symbol_table* symtab,
const Layout*, Output_file* of);
+ // Get the size of a section.
+ uint64_t
+ do_section_size(unsigned int shndx)
+ { return this->elf_file_.section_size(shndx); }
+
// Get the name of a section.
std::string
do_section_name(unsigned int shndx)
@@ -1166,6 +1188,11 @@ class Sized_relobj : public Relobj
do_section_info(unsigned int shndx)
{ return this->elf_file_.section_info(shndx); }
+ // Return the section alignment.
+ uint64_t
+ do_section_addralign(unsigned int shndx)
+ { return this->elf_file_.section_addralign(shndx); }
+
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;
diff --git a/gold/output.cc b/gold/output.cc
index 1060de6b7e..c0db1afdc2 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -275,6 +275,7 @@ Output_segment_headers::do_sized_write(Output_file* of)
{
const int phdr_size = elfcpp::Elf_sizes<size>::phdr_size;
off_t all_phdrs_size = this->segment_list_.size() * phdr_size;
+ gold_assert(all_phdrs_size == this->data_size());
unsigned char* view = of->get_output_view(this->offset(),
all_phdrs_size);
unsigned char* v = view;
@@ -287,6 +288,8 @@ Output_segment_headers::do_sized_write(Output_file* of)
v += phdr_size;
}
+ gold_assert(v - view == all_phdrs_size);
+
of->write_output_view(this->offset(), all_phdrs_size, view);
}
@@ -1371,6 +1374,15 @@ Output_section::Input_section::set_address_and_file_offset(
this->u2_.posd->set_address_and_file_offset(address, file_offset);
}
+// Reset the address and file offset.
+
+void
+Output_section::Input_section::reset_address_and_file_offset()
+{
+ if (!this->is_input_section())
+ this->u2_.posd->reset_address_and_file_offset();
+}
+
// Finalize the data size.
void
@@ -1444,6 +1456,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
: name_(name),
addralign_(0),
entsize_(0),
+ load_address_(0),
link_section_(NULL),
link_(0),
info_section_(NULL),
@@ -1463,6 +1476,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
should_link_to_dynsym_(false),
after_input_sections_(false),
requires_postprocessing_(false),
+ found_in_sections_clause_(false),
+ has_load_address_(false),
tls_offset_(0)
{
// An unallocated section has no address. Forcing this means that
@@ -1495,7 +1510,9 @@ Output_section::set_entsize(uint64_t v)
// receive special handling. In the normal case we don't always keep
// track of input sections for an Output_section. Instead, each
// Object keeps track of the Output_section for each of its input
-// sections.
+// sections. However, if HAVE_SECTIONS_SCRIPT is true, we do keep
+// track of input sections here; this is used when SECTIONS appears in
+// a linker script.
template<int size, bool big_endian>
off_t
@@ -1503,7 +1520,8 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<size, big_endian>& shdr,
- unsigned int reloc_shndx)
+ unsigned int reloc_shndx,
+ bool have_sections_script)
{
elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
if ((addralign & (addralign - 1)) != 0)
@@ -1517,6 +1535,11 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
this->addralign_ = addralign;
typename elfcpp::Elf_types<size>::Elf_WXword sh_flags = shdr.get_sh_flags();
+ this->flags_ |= (sh_flags
+ & (elfcpp::SHF_WRITE
+ | elfcpp::SHF_ALLOC
+ | elfcpp::SHF_EXECINSTR));
+
uint64_t entsize = shdr.get_sh_entsize();
// .debug_str is a mergeable string section, but is not always so
@@ -1547,6 +1570,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
addralign);
if (aligned_offset_in_section > offset_in_section
+ && !have_sections_script
&& (sh_flags & elfcpp::SHF_EXECINSTR) != 0
&& object->target()->has_code_fill())
{
@@ -1572,7 +1596,7 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
// We need to keep track of this section if we are already keeping
// track of sections, or if we are relaxing. FIXME: Add test for
// relaxing.
- if (!this->input_sections_.empty())
+ if (have_sections_script || !this->input_sections_.empty())
this->input_sections_.push_back(Input_section(object, shndx,
shdr.get_sh_size(),
addralign));
@@ -1587,6 +1611,15 @@ Output_section::add_output_section_data(Output_section_data* posd)
{
Input_section inp(posd);
this->add_output_section_data(&inp);
+
+ if (posd->is_data_size_valid())
+ {
+ off_t offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ posd->addralign());
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + posd->data_size());
+ }
}
// Add arbitrary data to an output section by Input_section.
@@ -1809,6 +1842,17 @@ Output_section::set_final_data_size()
this->set_data_size(off - startoff);
}
+// Reset the address and file offset.
+
+void
+Output_section::do_reset_address_and_file_offset()
+{
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ p->reset_address_and_file_offset();
+}
+
// Set the TLS offset. Called only for SHT_TLS sections.
void
@@ -1863,7 +1907,7 @@ Output_section::do_write(Output_file* of)
{
std::string fill_data(parameters->target()->code_fill(p->length()));
of->write(output_section_file_offset + p->section_offset(),
- fill_data.data(), fill_data.size());
+ fill_data.data(), fill_data.size());
}
for (Input_section_list::iterator p = this->input_sections_.begin();
@@ -1917,7 +1961,8 @@ Output_section::write_to_postprocessing_buffer()
++p)
{
std::string fill_data(target->code_fill(p->length()));
- memcpy(buffer + p->section_offset(), fill_data.data(), fill_data.size());
+ memcpy(buffer + p->section_offset(), fill_data.data(),
+ fill_data.size());
}
off_t off = this->first_input_offset_;
@@ -1931,6 +1976,89 @@ Output_section::write_to_postprocessing_buffer()
}
}
+// Get the input sections for linker script processing. We leave
+// behind the Output_section_data entries. Note that this may be
+// slightly incorrect for merge sections. We will leave them behind,
+// but it is possible that the script says that they should follow
+// some other input sections, as in:
+// .rodata { *(.rodata) *(.rodata.cst*) }
+// For that matter, we don't handle this correctly:
+// .rodata { foo.o(.rodata.cst*) *(.rodata.cst*) }
+// With luck this will never matter.
+
+uint64_t
+Output_section::get_input_sections(
+ uint64_t address,
+ const std::string& fill,
+ std::list<std::pair<Relobj*, unsigned int> >* input_sections)
+{
+ uint64_t orig_address = address;
+
+ address = align_address(address, this->addralign());
+
+ Input_section_list remaining;
+ for (Input_section_list::iterator p = this->input_sections_.begin();
+ p != this->input_sections_.end();
+ ++p)
+ {
+ if (p->is_input_section())
+ input_sections->push_back(std::make_pair(p->relobj(), p->shndx()));
+ else
+ {
+ uint64_t aligned_address = align_address(address, p->addralign());
+ if (aligned_address != address && !fill.empty())
+ {
+ section_size_type length =
+ convert_to_section_size_type(aligned_address - address);
+ std::string this_fill;
+ this_fill.reserve(length);
+ while (this_fill.length() + fill.length() <= length)
+ this_fill += fill;
+ if (this_fill.length() < length)
+ this_fill.append(fill, 0, length - this_fill.length());
+
+ Output_section_data* posd = new Output_data_const(this_fill, 0);
+ remaining.push_back(Input_section(posd));
+ }
+ address = aligned_address;
+
+ remaining.push_back(*p);
+
+ p->finalize_data_size();
+ address += p->data_size();
+ }
+ }
+
+ this->input_sections_.swap(remaining);
+ this->first_input_offset_ = 0;
+
+ uint64_t data_size = address - orig_address;
+ this->set_current_data_size_for_child(data_size);
+ return data_size;
+}
+
+// Add an input section from a script.
+
+void
+Output_section::add_input_section_for_script(Relobj* object,
+ unsigned int shndx,
+ off_t data_size,
+ uint64_t addralign)
+{
+ if (addralign > this->addralign_)
+ this->addralign_ = addralign;
+
+ off_t offset_in_section = this->current_data_size_for_child();
+ off_t aligned_offset_in_section = align_address(offset_in_section,
+ addralign);
+
+ this->set_current_data_size_for_child(aligned_offset_in_section
+ + data_size);
+
+ this->input_sections_.push_back(Input_section(object, shndx,
+ data_size, addralign));
+}
+
// Print stats for merge sections to stderr.
void
@@ -1951,12 +2079,14 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
vaddr_(0),
paddr_(0),
memsz_(0),
- align_(0),
+ max_align_(0),
+ min_p_align_(0),
offset_(0),
filesz_(0),
type_(type),
flags_(flags),
- is_align_known_(false)
+ is_max_align_known_(false),
+ are_addresses_set_(false)
{
}
@@ -1968,7 +2098,7 @@ Output_segment::add_output_section(Output_section* os,
bool front)
{
gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
- gold_assert(!this->is_align_known_);
+ gold_assert(!this->is_max_align_known_);
// Update the segment flags.
this->flags_ |= seg_flags;
@@ -2069,38 +2199,37 @@ Output_segment::add_output_section(Output_section* os,
void
Output_segment::add_initial_output_data(Output_data* od)
{
- gold_assert(!this->is_align_known_);
+ gold_assert(!this->is_max_align_known_);
this->output_data_.push_front(od);
}
// Return the maximum alignment of the Output_data in Output_segment.
-// Once we compute this, we prohibit new sections from being added.
uint64_t
-Output_segment::addralign()
+Output_segment::maximum_alignment()
{
- if (!this->is_align_known_)
+ if (!this->is_max_align_known_)
{
uint64_t addralign;
- addralign = Output_segment::maximum_alignment(&this->output_data_);
- if (addralign > this->align_)
- this->align_ = addralign;
+ addralign = Output_segment::maximum_alignment_list(&this->output_data_);
+ if (addralign > this->max_align_)
+ this->max_align_ = addralign;
- addralign = Output_segment::maximum_alignment(&this->output_bss_);
- if (addralign > this->align_)
- this->align_ = addralign;
+ addralign = Output_segment::maximum_alignment_list(&this->output_bss_);
+ if (addralign > this->max_align_)
+ this->max_align_ = addralign;
- this->is_align_known_ = true;
+ this->is_max_align_known_ = true;
}
- return this->align_;
+ return this->max_align_;
}
// Return the maximum alignment of a list of Output_data.
uint64_t
-Output_segment::maximum_alignment(const Output_data_list* pdl)
+Output_segment::maximum_alignment_list(const Output_data_list* pdl)
{
uint64_t ret = 0;
for (Output_data_list::const_iterator p = pdl->begin();
@@ -2136,33 +2265,41 @@ Output_segment::dynamic_reloc_count_list(const Output_data_list* pdl) const
return count;
}
-// Set the section addresses for an Output_segment. ADDR is the
-// address and *POFF is the file offset. Set the section indexes
-// starting with *PSHNDX. Return the address of the immediately
-// following segment. Update *POFF and *PSHNDX.
+// Set the section addresses for an Output_segment. If RESET is true,
+// reset the addresses first. ADDR is the address and *POFF is the
+// file offset. Set the section indexes starting with *PSHNDX.
+// Return the address of the immediately following segment. Update
+// *POFF and *PSHNDX.
uint64_t
-Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
+Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
gold_assert(this->type_ == elfcpp::PT_LOAD);
- this->vaddr_ = addr;
- this->paddr_ = addr;
+ if (!reset && this->are_addresses_set_)
+ {
+ gold_assert(this->paddr_ == addr);
+ addr = this->vaddr_;
+ }
+ else
+ {
+ this->vaddr_ = addr;
+ this->paddr_ = addr;
+ this->are_addresses_set_ = true;
+ }
off_t orig_off = *poff;
this->offset_ = orig_off;
- *poff = align_address(*poff, this->addralign());
-
- addr = this->set_section_list_addresses(&this->output_data_, addr, poff,
- pshndx);
+ addr = this->set_section_list_addresses(reset, &this->output_data_,
+ addr, poff, pshndx);
this->filesz_ = *poff - orig_off;
off_t off = *poff;
- uint64_t ret = this->set_section_list_addresses(&this->output_bss_, addr,
- poff, pshndx);
+ uint64_t ret = this->set_section_list_addresses(reset, &this->output_bss_,
+ addr, poff, pshndx);
this->memsz_ = *poff - orig_off;
// Ignore the file offset adjustments made by the BSS Output_data
@@ -2176,7 +2313,7 @@ Output_segment::set_section_addresses(uint64_t addr, off_t* poff,
// structures.
uint64_t
-Output_segment::set_section_list_addresses(Output_data_list* pdl,
+Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
@@ -2188,7 +2325,23 @@ Output_segment::set_section_list_addresses(Output_data_list* pdl,
++p)
{
off = align_address(off, (*p)->addralign());
- (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+
+ if (reset)
+ (*p)->reset_address_and_file_offset();
+
+ // When using a linker script the section will most likely
+ // already have an address.
+ if (!(*p)->is_address_valid())
+ (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+ else
+ {
+ // The script may have inserted a skip forward, but it
+ // better not have moved backward.
+ gold_assert((*p)->address() >= addr);
+ off = startoff + ((*p)->address() - addr);
+ (*p)->set_file_offset(off);
+ (*p)->finalize_data_size();
+ }
// Unless this is a PT_TLS segment, we want to ignore the size
// of a SHF_TLS/SHT_NOBITS section. Such a section does not
@@ -2217,12 +2370,15 @@ Output_segment::set_offset()
{
gold_assert(this->type_ != elfcpp::PT_LOAD);
+ gold_assert(!this->are_addresses_set_);
+
if (this->output_data_.empty() && this->output_bss_.empty())
{
this->vaddr_ = 0;
this->paddr_ = 0;
+ this->are_addresses_set_ = true;
this->memsz_ = 0;
- this->align_ = 0;
+ this->min_p_align_ = 0;
this->offset_ = 0;
this->filesz_ = 0;
return;
@@ -2234,7 +2390,10 @@ Output_segment::set_offset()
else
first = this->output_data_.front();
this->vaddr_ = first->address();
- this->paddr_ = this->vaddr_;
+ this->paddr_ = (first->has_load_address()
+ ? first->load_address()
+ : this->vaddr_);
+ this->are_addresses_set_ = true;
this->offset_ = first->offset();
if (this->output_data_.empty())
@@ -2275,6 +2434,26 @@ Output_segment::set_tls_offsets()
(*p)->set_tls_offset(this->vaddr_);
}
+// Return the address of the first section.
+
+uint64_t
+Output_segment::first_section_load_address() const
+{
+ for (Output_data_list::const_iterator p = this->output_data_.begin();
+ p != this->output_data_.end();
+ ++p)
+ if ((*p)->is_section())
+ return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
+
+ for (Output_data_list::const_iterator p = this->output_bss_.begin();
+ p != this->output_bss_.end();
+ ++p)
+ if ((*p)->is_section())
+ return (*p)->has_load_address() ? (*p)->load_address() : (*p)->address();
+
+ gold_unreachable();
+}
+
// Return the number of Output_sections in an Output_segment.
unsigned int
@@ -2313,7 +2492,7 @@ Output_segment::write_header(elfcpp::Phdr_write<size, big_endian>* ophdr)
ophdr->put_p_filesz(this->filesz_);
ophdr->put_p_memsz(this->memsz_);
ophdr->put_p_flags(this->flags_);
- ophdr->put_p_align(this->addralign());
+ ophdr->put_p_align(std::max(this->min_p_align_, this->maximum_alignment()));
}
// Write the section headers into V.
@@ -2534,7 +2713,8 @@ Output_section::add_input_section<32, false>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, false>& shdr,
- unsigned int reloc_shndx);
+ unsigned int reloc_shndx,
+ bool have_sections_script);
#endif
#ifdef HAVE_TARGET_32_BIG
@@ -2545,7 +2725,8 @@ Output_section::add_input_section<32, true>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<32, true>& shdr,
- unsigned int reloc_shndx);
+ unsigned int reloc_shndx,
+ bool have_sections_script);
#endif
#ifdef HAVE_TARGET_64_LITTLE
@@ -2556,7 +2737,8 @@ Output_section::add_input_section<64, false>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, false>& shdr,
- unsigned int reloc_shndx);
+ unsigned int reloc_shndx,
+ bool have_sections_script);
#endif
#ifdef HAVE_TARGET_64_BIG
@@ -2567,7 +2749,8 @@ Output_section::add_input_section<64, true>(
unsigned int shndx,
const char* secname,
const elfcpp::Shdr<64, true>& shdr,
- unsigned int reloc_shndx);
+ unsigned int reloc_shndx,
+ bool have_sections_script);
#endif
#ifdef HAVE_TARGET_32_LITTLE
diff --git a/gold/output.h b/gold/output.h
index 96c02477f1..1354551476 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -88,11 +88,32 @@ class Output_data
return this->offset_;
}
+ // Reset the address and file offset. This essentially disables the
+ // sanity testing about duplicate and unknown settings.
+ void
+ reset_address_and_file_offset()
+ {
+ this->is_address_valid_ = false;
+ this->is_offset_valid_ = false;
+ this->is_data_size_valid_ = false;
+ this->do_reset_address_and_file_offset();
+ }
+
// Return the required alignment.
uint64_t
addralign() const
{ return this->do_addralign(); }
+ // Return whether this has a load address.
+ bool
+ has_load_address() const
+ { return this->do_has_load_address(); }
+
+ // Return the load address.
+ uint64_t
+ load_address() const
+ { return this->do_load_address(); }
+
// Return whether this is an Output_section.
bool
is_section() const
@@ -224,6 +245,16 @@ class Output_data
virtual uint64_t
do_addralign() const = 0;
+ // Return whether this has a load address.
+ virtual bool
+ do_has_load_address() const
+ { return false; }
+
+ // Return the load address.
+ virtual uint64_t
+ do_load_address() const
+ { gold_unreachable(); }
+
// Return whether this is an Output_section.
virtual bool
do_is_section() const
@@ -258,6 +289,11 @@ class Output_data
set_final_data_size()
{ gold_unreachable(); }
+ // A hook for resetting the address and file offset.
+ virtual void
+ do_reset_address_and_file_offset()
+ { }
+
// Set the TLS offset. Called only for SHT_TLS sections.
virtual void
do_set_tls_offset(uint64_t)
@@ -1491,13 +1527,16 @@ class Output_section : public Output_data
// Add a new input section SHNDX, named NAME, with header SHDR, from
// object OBJECT. RELOC_SHNDX is the index of a relocation section
// which applies to this section, or 0 if none, or -1U if more than
- // one. Return the offset within the output section.
+ // one. HAVE_SECTIONS_SCRIPT is true if we have a SECTIONS clause
+ // in a linker script; in that case we need to keep track of input
+ // sections associated with an output section. Return the offset
+ // within the output section.
template<int size, bool big_endian>
off_t
add_input_section(Sized_relobj<size, big_endian>* object, unsigned int shndx,
const char *name,
const elfcpp::Shdr<size, big_endian>& shdr,
- unsigned int reloc_shndx);
+ unsigned int reloc_shndx, bool have_sections_script);
// Add generated data POSD to this output section.
void
@@ -1527,6 +1566,14 @@ class Output_section : public Output_data
void
set_entsize(uint64_t v);
+ // Set the load address.
+ void
+ set_load_address(uint64_t load_address)
+ {
+ this->load_address_ = load_address;
+ this->has_load_address_ = true;
+ }
+
// Set the link field to the output section index of a section.
void
set_link_section(const Output_data* od)
@@ -1709,12 +1756,53 @@ class Output_section : public Output_data
uint64_t
starting_output_address(const Relobj* object, unsigned int shndx) const;
+ // Record that this output section was found in the SECTIONS clause
+ // of a linker script.
+ void
+ set_found_in_sections_clause()
+ { this->found_in_sections_clause_ = true; }
+
+ // Return whether this output section was found in the SECTIONS
+ // clause of a linker script.
+ bool
+ found_in_sections_clause() const
+ { return this->found_in_sections_clause_; }
+
// Write the section header into *OPHDR.
template<int size, bool big_endian>
void
write_header(const Layout*, const Stringpool*,
elfcpp::Shdr_write<size, big_endian>*) const;
+ // The next few calls are for linker script support.
+
+ // Store the list of input sections for this Output_section into the
+ // list passed in. This removes the input sections, leaving only
+ // any Output_section_data elements. This returns the size of those
+ // Output_section_data elements. ADDRESS is the address of this
+ // output section. FILL is the fill value to use, in case there are
+ // any spaces between the remaining Output_section_data elements.
+ uint64_t
+ get_input_sections(uint64_t address, const std::string& fill,
+ std::list<std::pair<Relobj*, unsigned int > >*);
+
+ // Add an input section from a script.
+ void
+ add_input_section_for_script(Relobj* object, unsigned int shndx,
+ off_t data_size, uint64_t addralign);
+
+ // Set the current size of the output section.
+ void
+ set_current_data_size(off_t size)
+ { this->set_current_data_size_for_child(size); }
+
+ // Get the current size of the output section.
+ off_t
+ current_data_size() const
+ { return this->current_data_size_for_child(); }
+
+ // End of linker script support.
+
// Print merge statistics to stderr.
void
print_merge_stats();
@@ -1732,7 +1820,7 @@ class Output_section : public Output_data
void
do_set_out_shndx(unsigned int shndx)
{
- gold_assert(this->out_shndx_ == -1U);
+ gold_assert(this->out_shndx_ == -1U || this->out_shndx_ == shndx);
this->out_shndx_ = shndx;
}
@@ -1743,6 +1831,10 @@ class Output_section : public Output_data
virtual void
set_final_data_size();
+ // Reset the address and file offset.
+ void
+ do_reset_address_and_file_offset();
+
// Write the data to the file. For a typical Output_section, this
// does nothing: the data is written out by calling Object::Relocate
// on each input object. But if there are any Output_section_data
@@ -1755,6 +1847,19 @@ class Output_section : public Output_data
do_addralign() const
{ return this->addralign_; }
+ // Return whether there is a load address.
+ bool
+ do_has_load_address() const
+ { return this->has_load_address_; }
+
+ // Return the load address.
+ uint64_t
+ do_load_address() const
+ {
+ gold_assert(this->has_load_address_);
+ return this->load_address_;
+ }
+
// Return whether this is an Output_section.
bool
do_is_section() const
@@ -1877,6 +1982,15 @@ class Output_section : public Output_data
off_t
data_size() const;
+ // Whether this is an input section.
+ bool
+ is_input_section() const
+ {
+ return (this->shndx_ != OUTPUT_SECTION_CODE
+ && this->shndx_ != MERGE_DATA_SECTION_CODE
+ && this->shndx_ != MERGE_STRING_SECTION_CODE);
+ }
+
// Return whether this is a merge section which matches the
// parameters.
bool
@@ -1890,6 +2004,22 @@ class Output_section : public Output_data
&& this->addralign() == addralign);
}
+ // Return the object for an input section.
+ Relobj*
+ relobj() const
+ {
+ gold_assert(this->is_input_section());
+ return this->u2_.object;
+ }
+
+ // Return the input section index for an input section.
+ unsigned int
+ shndx() const
+ {
+ gold_assert(this->is_input_section());
+ return this->shndx_;
+ }
+
// Set the output section.
void
set_output_section(Output_section* os)
@@ -1905,6 +2035,10 @@ class Output_section : public Output_data
set_address_and_file_offset(uint64_t address, off_t file_offset,
off_t section_file_offset);
+ // Reset the address and file offset.
+ void
+ reset_address_and_file_offset();
+
// Finalize the data size.
void
finalize_data_size();
@@ -1968,15 +2102,6 @@ class Output_section : public Output_data
MERGE_STRING_SECTION_CODE = -3U
};
- // Whether this is an input section.
- bool
- is_input_section() const
- {
- return (this->shndx_ != OUTPUT_SECTION_CODE
- && this->shndx_ != MERGE_DATA_SECTION_CODE
- && this->shndx_ != MERGE_STRING_SECTION_CODE);
- }
-
// For an ordinary input section, this is the section index in the
// input file. For an Output_section_data, this is
// OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
@@ -2007,15 +2132,16 @@ class Output_section : public Output_data
typedef std::vector<Input_section> Input_section_list;
// Fill data. This is used to fill in data between input sections.
- // When we have to keep track of the input sections, we can use an
- // Output_data_const, but we don't want to have to keep track of
- // input sections just to implement fills. For a fill we record the
- // offset, and the actual data to be written out.
+ // It is also used for data statements (BYTE, WORD, etc.) in linker
+ // scripts. When we have to keep track of the input sections, we
+ // can use an Output_data_const, but we don't want to have to keep
+ // track of input sections just to implement fills.
class Fill
{
public:
Fill(off_t section_offset, off_t length)
- : section_offset_(section_offset), length_(length)
+ : section_offset_(section_offset),
+ length_(convert_to_section_size_type(length))
{ }
// Return section offset.
@@ -2024,7 +2150,7 @@ class Output_section : public Output_data
{ return this->section_offset_; }
// Return fill length.
- off_t
+ section_size_type
length() const
{ return this->length_; }
@@ -2032,7 +2158,7 @@ class Output_section : public Output_data
// The offset within the output section.
off_t section_offset_;
// The length of the space to fill.
- off_t length_;
+ section_size_type length_;
};
typedef std::vector<Fill> Fill_list;
@@ -2064,6 +2190,10 @@ class Output_section : public Output_data
uint64_t addralign_;
// The section entry size.
uint64_t entsize_;
+ // The load address. This is only used when using a linker script
+ // with a SECTIONS clause. The has_load_address_ field indicates
+ // whether this field is valid.
+ uint64_t load_address_;
// The file offset is in the parent class.
// Set the section link field to the index of this section.
const Output_data* link_section_;
@@ -2076,7 +2206,7 @@ class Output_section : public Output_data
// The section type.
const elfcpp::Elf_Word type_;
// The section flags.
- const elfcpp::Elf_Xword flags_;
+ elfcpp::Elf_Xword flags_;
// The section index.
unsigned int out_shndx_;
// If there is a STT_SECTION for this output section in the normal
@@ -2121,6 +2251,11 @@ class Output_section : public Output_data
// Whether this section requires post processing after all
// relocations have been applied.
bool requires_postprocessing_ : 1;
+ // Whether an input section was mapped to this output section
+ // because of a SECTIONS clause in a linker script.
+ bool found_in_sections_clause_ : 1;
+ // Whether this section has an explicitly specified load address.
+ bool has_load_address_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;
@@ -2168,7 +2303,7 @@ class Output_segment
// Return the maximum alignment of the Output_data.
uint64_t
- addralign();
+ maximum_alignment();
// Add an Output_section to this segment.
void
@@ -2189,23 +2324,40 @@ class Output_segment
unsigned int
dynamic_reloc_count() const;
+ // Return the address of the first section.
+ uint64_t
+ first_section_load_address() const;
+
+ // Return whether the addresses have been set already.
+ bool
+ are_addresses_set() const
+ { return this->are_addresses_set_; }
+
+ // Set the addresses.
+ void
+ set_addresses(uint64_t vaddr, uint64_t paddr)
+ {
+ this->vaddr_ = vaddr;
+ this->paddr_ = paddr;
+ this->are_addresses_set_ = true;
+ }
+
// Set the address of the segment to ADDR and the offset to *POFF
- // (aligned if necessary), and set the addresses and offsets of all
- // contained output sections accordingly. Set the section indexes
- // of all contained output sections starting with *PSHNDX. Return
- // the address of the immediately following segment. Update *POFF
- // and *PSHNDX. This should only be called for a PT_LOAD segment.
+ // and set the addresses and offsets of all contained output
+ // sections accordingly. Set the section indexes of all contained
+ // output sections starting with *PSHNDX. If RESET is true, first
+ // reset the addresses of the contained sections. Return the
+ // address of the immediately following segment. Update *POFF and
+ // *PSHNDX. This should only be called for a PT_LOAD segment.
uint64_t
- set_section_addresses(uint64_t addr, off_t* poff, unsigned int* pshndx);
+ set_section_addresses(bool reset, uint64_t addr, off_t* poff,
+ unsigned int* pshndx);
// Set the minimum alignment of this segment. This may be adjusted
// upward based on the section alignments.
void
- set_minimum_addralign(uint64_t align)
- {
- gold_assert(!this->is_align_known_);
- this->align_ = align;
- }
+ set_minimum_p_align(uint64_t align)
+ { this->min_p_align_ = align; }
// Set the offset of this segment based on the section. This should
// only be called for a non-PT_LOAD segment.
@@ -2244,12 +2396,12 @@ class Output_segment
// Find the maximum alignment in an Output_data_list.
static uint64_t
- maximum_alignment(const Output_data_list*);
+ maximum_alignment_list(const Output_data_list*);
// Set the section addresses in an Output_data_list.
uint64_t
- set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff,
- unsigned int* pshndx);
+ set_section_list_addresses(bool reset, Output_data_list*, uint64_t addr,
+ off_t* poff, unsigned int* pshndx);
// Return the number of Output_sections in an Output_data_list.
unsigned int
@@ -2276,10 +2428,17 @@ class Output_segment
uint64_t paddr_;
// The size of the segment in memory.
uint64_t memsz_;
- // The segment alignment. The is_align_known_ field indicates
- // whether this has been finalized. It can be set to a minimum
- // value before it is finalized.
- uint64_t align_;
+ // The maximum section alignment. The is_max_align_known_ field
+ // indicates whether this has been finalized.
+ uint64_t max_align_;
+ // The required minimum value for the p_align field. This is used
+ // for PT_LOAD segments. Note that this does not mean that
+ // addresses should be aligned to this value; it means the p_paddr
+ // and p_vaddr fields must be congruent modulo this value. For
+ // non-PT_LOAD segments, the dynamic linker works more efficiently
+ // if the p_align field has the more conventional value, although it
+ // can align as needed.
+ uint64_t min_p_align_;
// The offset of the segment data within the file.
off_t offset_;
// The size of the segment data in the file.
@@ -2288,8 +2447,10 @@ class Output_segment
elfcpp::Elf_Word type_;
// The segment flags.
elfcpp::Elf_Word flags_;
- // Whether we have finalized align_.
- bool is_align_known_;
+ // Whether we have finalized max_align_.
+ bool is_max_align_known_ : 1;
+ // Whether vaddr and paddr were set by a linker script.
+ bool are_addresses_set_ : 1;
};
// This class represents the output file.
diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in
index b1cfa5a057..e4411e2a06 100644
--- a/gold/po/POTFILES.in
+++ b/gold/po/POTFILES.in
@@ -45,6 +45,8 @@ resolve.cc
script.cc
script-c.h
script.h
+script-sections.cc
+script-sections.h
stringpool.cc
stringpool.h
symtab.cc
diff --git a/gold/po/gold.pot b/gold/po/gold.pot
index 8efe501f2b..392b1c0b79 100644
--- a/gold/po/gold.pot
+++ b/gold/po/gold.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-01-09 11:37-0800\n"
+"POT-Creation-Date: 2008-02-01 22:48-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -61,7 +61,7 @@ msgstr ""
msgid "%s: member at %zu is not an ELF object"
msgstr ""
-#: compressed_output.cc:126
+#: compressed_output.cc:127
msgid "not compressing section data: zlib error"
msgstr ""
@@ -70,115 +70,115 @@ msgstr ""
msgid "%s: can not read directory: %s"
msgstr ""
-#: dynobj.cc:145
+#: dynobj.cc:147
#, c-format
msgid "unexpected duplicate type %u section: %u, %u"
msgstr ""
-#: dynobj.cc:181
+#: dynobj.cc:183
#, c-format
msgid "unexpected link in section %u header: %u != %u"
msgstr ""
-#: dynobj.cc:217
+#: dynobj.cc:219
#, c-format
msgid "DYNAMIC section %u link out of range: %u"
msgstr ""
-#: dynobj.cc:225
+#: dynobj.cc:227
#, c-format
msgid "DYNAMIC section %u link %u is not a strtab"
msgstr ""
-#: dynobj.cc:253
+#: dynobj.cc:255
#, c-format
msgid "DT_SONAME value out of range: %lld >= %lld"
msgstr ""
-#: dynobj.cc:265
+#: dynobj.cc:267
#, c-format
msgid "DT_NEEDED value out of range: %lld >= %lld"
msgstr ""
-#: dynobj.cc:278
+#: dynobj.cc:280
msgid "missing DT_NULL in dynamic segment"
msgstr ""
-#: dynobj.cc:323
+#: dynobj.cc:325
#, c-format
msgid "invalid dynamic symbol table name index: %u"
msgstr ""
-#: dynobj.cc:330
+#: dynobj.cc:332
#, c-format
msgid "dynamic symbol table name section has wrong type: %u"
msgstr ""
-#: dynobj.cc:404 object.cc:251 object.cc:589
+#: dynobj.cc:406 object.cc:251 object.cc:589
#, c-format
msgid "bad section name offset for section %u: %lu"
msgstr ""
-#: dynobj.cc:433
+#: dynobj.cc:435
#, c-format
msgid "duplicate definition for version %u"
msgstr ""
-#: dynobj.cc:462
+#: dynobj.cc:464
#, c-format
msgid "unexpected verdef version %u"
msgstr ""
-#: dynobj.cc:478
+#: dynobj.cc:480
#, c-format
msgid "verdef vd_cnt field too small: %u"
msgstr ""
-#: dynobj.cc:486
+#: dynobj.cc:488
#, c-format
msgid "verdef vd_aux field out of range: %u"
msgstr ""
-#: dynobj.cc:497
+#: dynobj.cc:499
#, c-format
msgid "verdaux vda_name field out of range: %u"
msgstr ""
-#: dynobj.cc:507
+#: dynobj.cc:509
#, c-format
msgid "verdef vd_next field out of range: %u"
msgstr ""
-#: dynobj.cc:541
+#: dynobj.cc:543
#, c-format
msgid "unexpected verneed version %u"
msgstr ""
-#: dynobj.cc:550
+#: dynobj.cc:552
#, c-format
msgid "verneed vn_aux field out of range: %u"
msgstr ""
-#: dynobj.cc:564
+#: dynobj.cc:566
#, c-format
msgid "vernaux vna_name field out of range: %u"
msgstr ""
-#: dynobj.cc:575
+#: dynobj.cc:577
#, c-format
msgid "verneed vna_next field out of range: %u"
msgstr ""
-#: dynobj.cc:586
+#: dynobj.cc:588
#, c-format
msgid "verneed vn_next field out of range: %u"
msgstr ""
-#: dynobj.cc:634
+#: dynobj.cc:636
msgid "size of dynamic symbols is not multiple of symbol size"
msgstr ""
-#: dynobj.cc:1316
+#: dynobj.cc:1355
#, c-format
msgid "symbol %s has undefined version %s"
msgstr ""
@@ -203,64 +203,60 @@ msgstr ""
msgid "%s: "
msgstr ""
-#: expression.cc:104
+#: expression.cc:113
#, c-format
msgid "undefined symbol '%s' referenced in expression"
msgstr ""
-#: expression.cc:427
+#: expression.cc:566
msgid "DEFINED not implemented"
msgstr ""
-#: expression.cc:433
+#: expression.cc:572
msgid "SIZEOF_HEADERS not implemented"
msgstr ""
-#: expression.cc:439
+#: expression.cc:578
msgid "ALIGNOF not implemented"
msgstr ""
-#: expression.cc:445
+#: expression.cc:584
msgid "SIZEOF not implemented"
msgstr ""
-#: expression.cc:451
-msgid "ADDR not implemented"
-msgstr ""
-
-#: expression.cc:457
+#: expression.cc:590
msgid "LOADADDR not implemented"
msgstr ""
-#: expression.cc:463
+#: expression.cc:596
msgid "ORIGIN not implemented"
msgstr ""
-#: expression.cc:469
+#: expression.cc:602
msgid "LENGTH not implemented"
msgstr ""
-#: expression.cc:475
+#: expression.cc:608
msgid "CONSTANT not implemented"
msgstr ""
-#: expression.cc:481
+#: expression.cc:614
msgid "ABSOLUTE not implemented"
msgstr ""
-#: expression.cc:487
+#: expression.cc:620
msgid "DATA_SEGMENT_ALIGN not implemented"
msgstr ""
-#: expression.cc:493
+#: expression.cc:626
msgid "DATA_SEGMENT_RELRO_END not implemented"
msgstr ""
-#: expression.cc:499
+#: expression.cc:632
msgid "DATA_SEGMENT_END not implemented"
msgstr ""
-#: expression.cc:505
+#: expression.cc:638
msgid "SEGMENT_START not implemented"
msgstr ""
@@ -319,34 +315,34 @@ msgstr ""
msgid "%s: maximum bytes mapped for read at one time: %llu\n"
msgstr ""
-#: fileread.cc:628
+#: fileread.cc:642
#, c-format
msgid "cannot find -l%s"
msgstr ""
-#: fileread.cc:655
+#: fileread.cc:669
#, c-format
msgid "cannot find %s"
msgstr ""
-#: fileread.cc:666
+#: fileread.cc:680
#, c-format
msgid "cannot open %s: %s"
msgstr ""
-#: gold.cc:72
+#: gold.cc:73
#, c-format
msgid "%s: internal error in %s, at %s:%d\n"
msgstr ""
#. We had some input files, but we weren't able to open any of
#. them.
-#: gold.cc:118 gold.cc:166
+#: gold.cc:119 gold.cc:167
msgid "no input files"
msgstr ""
#. We print out just the first .so we see; there may be others.
-#: gold.cc:181
+#: gold.cc:182
#, c-format
msgid "cannot mix -static with dynamic object %s"
msgstr ""
@@ -412,42 +408,42 @@ msgid "pthread_cond_broadcast failed: %s"
msgstr ""
#. FIXME: This needs to specify the location somehow.
-#: i386.cc:160 i386.cc:1484 x86_64.cc:172 x86_64.cc:1373
+#: i386.cc:160 i386.cc:1490 x86_64.cc:172 x86_64.cc:1375
msgid "missing expected TLS relocation"
msgstr ""
-#: i386.cc:810 x86_64.cc:764 x86_64.cc:978
+#: i386.cc:809 x86_64.cc:764 x86_64.cc:978
#, c-format
msgid "%s: unsupported reloc %u against local symbol"
msgstr ""
-#: i386.cc:917 i386.cc:1213 x86_64.cc:889 x86_64.cc:1160
+#: i386.cc:916 i386.cc:1214 x86_64.cc:889 x86_64.cc:1162
#, c-format
msgid "%s: unexpected reloc %u in object file"
msgstr ""
-#: i386.cc:1056 x86_64.cc:992 x86_64.cc:1256
+#: i386.cc:1055 x86_64.cc:992 x86_64.cc:1258
#, c-format
msgid "%s: unsupported reloc %u against global symbol %s"
msgstr ""
-#: i386.cc:1367
+#: i386.cc:1368
#, c-format
msgid "%s: unsupported RELA reloc section"
msgstr ""
-#: i386.cc:1627 x86_64.cc:1575
+#: i386.cc:1640 x86_64.cc:1577
#, c-format
msgid "unexpected reloc %u in object file"
msgstr ""
-#: i386.cc:1659 i386.cc:1734 i386.cc:1741 i386.cc:1772 i386.cc:1825
-#: x86_64.cc:1596 x86_64.cc:1676 x86_64.cc:1700
+#: i386.cc:1672 i386.cc:1747 i386.cc:1754 i386.cc:1785 i386.cc:1838
+#: x86_64.cc:1598 x86_64.cc:1678 x86_64.cc:1702
#, c-format
msgid "unsupported reloc %u"
msgstr ""
-#: i386.cc:1749
+#: i386.cc:1762
msgid "both SUN and GNU model TLS relocations"
msgstr ""
@@ -604,365 +600,378 @@ msgstr ""
msgid "unable to parse script file %s"
msgstr ""
-#: options.cc:185
+#: options.cc:174
+#, c-format
+msgid "unable to parse version script file %s"
+msgstr ""
+
+#: options.cc:201
#, c-format
msgid ""
"Usage: %s [options] file...\n"
"Options:\n"
msgstr ""
-#: options.cc:356
+#: options.cc:372
msgid "Allow unresolved references in shared libraries"
msgstr ""
-#: options.cc:360
+#: options.cc:376
msgid "Do not allow unresolved references in shared libraries"
msgstr ""
-#: options.cc:364
+#: options.cc:380
msgid "Only set DT_NEEDED for dynamic libs if used"
msgstr ""
-#: options.cc:367
+#: options.cc:383
msgid "Always DT_NEEDED for dynamic libs (default)"
msgstr ""
-#: options.cc:370
+#: options.cc:386
msgid "-l searches for shared libraries"
msgstr ""
-#: options.cc:374
+#: options.cc:390
msgid "-l does not search for shared libraries"
msgstr ""
-#: options.cc:377
+#: options.cc:393
msgid "Bind defined symbols locally"
msgstr ""
-#: options.cc:385
+#: options.cc:401
msgid "Compress .debug_* sections in the output file (default is none)"
msgstr ""
-#: options.cc:387
+#: options.cc:403
msgid "--compress-debug-sections=[none"
msgstr ""
-#: options.cc:387
+#: options.cc:403
msgid "]"
msgstr ""
-#: options.cc:390
+#: options.cc:406
msgid "Define a symbol"
msgstr ""
-#: options.cc:391
+#: options.cc:407
msgid "--defsym SYMBOL=EXPRESSION"
msgstr ""
-#: options.cc:393
+#: options.cc:409
msgid "Demangle C++ symbols in log messages"
msgstr ""
-#: options.cc:396
+#: options.cc:412
msgid "Do not demangle C++ symbols in log messages"
msgstr ""
-#: options.cc:399
+#: options.cc:415
msgid "Try to detect violations of the One Definition Rule"
msgstr ""
-#: options.cc:401
+#: options.cc:417
msgid "Set program start address"
msgstr ""
-#: options.cc:402
+#: options.cc:418
msgid "-e ADDRESS, --entry ADDRESS"
msgstr ""
-#: options.cc:404
+#: options.cc:420
msgid "Export all dynamic symbols"
msgstr ""
-#: options.cc:406
+#: options.cc:422
msgid "Create exception frame header"
msgstr ""
-#: options.cc:408
+#: options.cc:424
msgid "Set shared library name"
msgstr ""
-#: options.cc:409
+#: options.cc:425
msgid "-h FILENAME, -soname FILENAME"
msgstr ""
-#: options.cc:411
+#: options.cc:427
msgid "Set dynamic linker path"
msgstr ""
-#: options.cc:412
+#: options.cc:428
msgid "-I PROGRAM, --dynamic-linker PROGRAM"
msgstr ""
-#: options.cc:414
+#: options.cc:430
msgid "Search for library LIBNAME"
msgstr ""
-#: options.cc:415
+#: options.cc:431
msgid "-lLIBNAME, --library LIBNAME"
msgstr ""
-#: options.cc:417
+#: options.cc:433
msgid "Add directory to search path"
msgstr ""
-#: options.cc:418
+#: options.cc:434
msgid "-L DIR, --library-path DIR"
msgstr ""
-#: options.cc:420
+#: options.cc:436
msgid "Ignored for compatibility"
msgstr ""
-#: options.cc:422
+#: options.cc:438
msgid "Set output file name"
msgstr ""
-#: options.cc:423
+#: options.cc:439
msgid "-o FILE, --output FILE"
msgstr ""
-#: options.cc:425
+#: options.cc:441
msgid "Optimize output file size"
msgstr ""
-#: options.cc:426
+#: options.cc:442
msgid "-O level"
msgstr ""
-#: options.cc:428
+#: options.cc:444
msgid "Generate relocatable output"
msgstr ""
-#: options.cc:430
+#: options.cc:446
msgid "Add DIR to runtime search path"
msgstr ""
-#: options.cc:431
+#: options.cc:447
msgid "-R DIR, -rpath DIR"
msgstr ""
-#: options.cc:434
+#: options.cc:450
msgid "Add DIR to link time shared library search path"
msgstr ""
-#: options.cc:435
+#: options.cc:451
msgid "--rpath-link DIR"
msgstr ""
-#: options.cc:437
+#: options.cc:453
msgid "Strip all symbols"
msgstr ""
-#: options.cc:440
+#: options.cc:456
msgid "Strip debug symbols that are unused by gdb (at least versions <= 6.7)"
msgstr ""
#. This must come after -Sdebug since it's a prefix of it.
-#: options.cc:444
+#: options.cc:460
msgid "Strip debugging information"
msgstr ""
-#: options.cc:446
+#: options.cc:462
msgid "Generate shared library"
msgstr ""
-#: options.cc:448
+#: options.cc:464
msgid "Do not link against shared libraries"
msgstr ""
-#: options.cc:450
+#: options.cc:466
msgid "Print resource usage statistics"
msgstr ""
-#: options.cc:452
+#: options.cc:468
msgid "Set target system root directory"
msgstr ""
-#: options.cc:453
+#: options.cc:469
msgid "--sysroot DIR"
msgstr ""
-#: options.cc:454
+#: options.cc:470
msgid "Set the address of the .text section"
msgstr ""
-#: options.cc:455
+#: options.cc:471
msgid "-Ttext ADDRESS"
msgstr ""
#. This must come after -Ttext since it's a prefix of it.
-#: options.cc:458
+#: options.cc:474
msgid "Read linker script"
msgstr ""
-#: options.cc:459
+#: options.cc:475
msgid "-T FILE, --script FILE"
msgstr ""
-#: options.cc:461
+#: options.cc:477
+msgid "Read version script"
+msgstr ""
+
+#: options.cc:478
+msgid "--version-script FILE"
+msgstr ""
+
+#: options.cc:480
msgid "Run the linker multi-threaded"
msgstr ""
-#: options.cc:463
+#: options.cc:482
msgid "Do not run the linker multi-threaded"
msgstr ""
-#: options.cc:465
+#: options.cc:484
msgid "Number of threads to use"
msgstr ""
-#: options.cc:466
+#: options.cc:485
msgid "--thread-count COUNT"
msgstr ""
-#: options.cc:469
+#: options.cc:488
msgid "Number of threads to use in initial pass"
msgstr ""
-#: options.cc:470
+#: options.cc:489
msgid "--thread-count-initial COUNT"
msgstr ""
-#: options.cc:473
+#: options.cc:492
msgid "Number of threads to use in middle pass"
msgstr ""
-#: options.cc:474
+#: options.cc:493
msgid "--thread-count-middle COUNT"
msgstr ""
-#: options.cc:477
+#: options.cc:496
msgid "Number of threads to use in final pass"
msgstr ""
-#: options.cc:478
+#: options.cc:497
msgid "--thread-count-final COUNT"
msgstr ""
-#: options.cc:481
+#: options.cc:500
msgid "Include all archive contents"
msgstr ""
-#: options.cc:485
+#: options.cc:504
msgid "Include only needed archive contents"
msgstr ""
-#: options.cc:490
+#: options.cc:509
msgid ""
"Subcommands as follows:\n"
" -z execstack Mark output as requiring executable stack\n"
" -z noexecstack Mark output as not requiring executable stack"
msgstr ""
-#: options.cc:493
+#: options.cc:512
msgid "-z SUBCOMMAND"
msgstr ""
-#: options.cc:496
+#: options.cc:515
msgid "Start a library search group"
msgstr ""
-#: options.cc:498
+#: options.cc:517
msgid "End a library search group"
msgstr ""
-#: options.cc:500
+#: options.cc:519
msgid "Report usage information"
msgstr ""
-#: options.cc:502
+#: options.cc:521
msgid "Report version information"
msgstr ""
-#: options.cc:504
-msgid "Turn on debugging (all,task)"
+#: options.cc:523
+msgid "Turn on debugging (all,task,script)"
msgstr ""
-#: options.cc:505
+#: options.cc:524
msgid "--debug=TYPE"
msgstr ""
-#: options.cc:600
+#: options.cc:620
#, c-format
msgid "%s: unrecognized -z subcommand: %s\n"
msgstr ""
-#: options.cc:623
+#: options.cc:643
#, c-format
msgid "%s: unrecognized --debug subcommand: %s\n"
msgstr ""
-#: options.cc:812
+#: options.cc:832
msgid "unexpected argument"
msgstr ""
-#: options.cc:819 options.cc:871 options.cc:952
+#: options.cc:839 options.cc:891 options.cc:972
msgid "missing argument"
msgstr ""
-#: options.cc:832 options.cc:880
+#: options.cc:852 options.cc:900
msgid "unknown option"
msgstr ""
-#: options.cc:898
+#: options.cc:918
#, c-format
msgid "%s: missing group end\n"
msgstr ""
-#: options.cc:1026
+#: options.cc:1046
msgid "may not nest groups"
msgstr ""
-#: options.cc:1036
+#: options.cc:1056
msgid "group end without group start"
msgstr ""
-#: options.cc:1046
+#: options.cc:1066
#, c-format
msgid "%s: use the --help option for usage information\n"
msgstr ""
-#: options.cc:1055
+#: options.cc:1075
#, c-format
msgid "%s: %s: %s\n"
msgstr ""
-#: options.cc:1064
+#: options.cc:1084
#, c-format
msgid "%s: -%c: %s\n"
msgstr ""
-#: options.h:358
+#: options.h:363
#, c-format
msgid "invalid optimization level: %s"
msgstr ""
-#: options.h:404
+#: options.h:409
#, c-format
msgid "unsupported argument to --compress-debug-sections: %s"
msgstr ""
-#: options.h:458
+#: options.h:463
#, c-format
msgid "invalid argument to -Ttext: %s"
msgstr ""
-#: options.h:467
+#: options.h:472
#, c-format
msgid "invalid thread count: %s"
msgstr ""
-#: options.h:475
+#: options.h:480
msgid "--threads not supported"
msgstr ""
@@ -971,42 +980,42 @@ msgstr ""
msgid "invalid alignment %lu for section \"%s\""
msgstr ""
-#: output.cc:2418
+#: output.cc:2416
#, c-format
msgid "%s: open: %s"
msgstr ""
-#: output.cc:2438
+#: output.cc:2436
#, c-format
msgid "%s: mremap: %s"
msgstr ""
-#: output.cc:2474
+#: output.cc:2472
#, c-format
msgid "%s: lseek: %s"
msgstr ""
-#: output.cc:2477 output.cc:2514
+#: output.cc:2475 output.cc:2512
#, c-format
msgid "%s: write: %s"
msgstr ""
-#: output.cc:2485
+#: output.cc:2483
#, c-format
msgid "%s: mmap: %s"
msgstr ""
-#: output.cc:2495
+#: output.cc:2493
#, c-format
msgid "%s: munmap: %s"
msgstr ""
-#: output.cc:2512
+#: output.cc:2510
#, c-format
msgid "%s: write: unexpected 0 return-value"
msgstr ""
-#: output.cc:2524
+#: output.cc:2522
#, c-format
msgid "%s: close: %s"
msgstr ""
@@ -1016,13 +1025,8 @@ msgstr ""
msgid "%s: file is empty"
msgstr ""
-#: readsyms.cc:185
-#, c-format
-msgid "%s: ordinary object found in input group"
-msgstr ""
-
#. Here we have to handle any other input file types we need.
-#: readsyms.cc:242
+#: readsyms.cc:231
#, c-format
msgid "%s: not an object or archive"
msgstr ""
@@ -1075,14 +1079,14 @@ msgstr ""
msgid "%s: previous definition here"
msgstr ""
-#: script.cc:1413
+#: script.cc:1890
#, c-format
msgid "%s:%d:%d: %s"
msgstr ""
#. There are some options that we could handle here--e.g.,
#. -lLIBRARY. Should we bother?
-#: script.cc:1539
+#: script.cc:2026
#, c-format
msgid ""
"%s:%d:%d: ignoring command OPTION; OPTION is only valid for scripts "
@@ -1104,51 +1108,51 @@ msgstr ""
msgid "%s: %s Stringdata structures: %zu\n"
msgstr ""
-#: symtab.cc:603
+#: symtab.cc:627
#, c-format
msgid "bad global symbol name offset %u at %zu"
msgstr ""
-#: symtab.cc:682
+#: symtab.cc:730
msgid "too few symbol versions"
msgstr ""
-#: symtab.cc:711
+#: symtab.cc:762
#, c-format
msgid "bad symbol name offset %u at %zu"
msgstr ""
-#: symtab.cc:765
+#: symtab.cc:816
#, c-format
msgid "versym for symbol %zu out of range: %u"
msgstr ""
-#: symtab.cc:773
+#: symtab.cc:824
#, c-format
msgid "versym for symbol %zu has no name: %u"
msgstr ""
-#: symtab.cc:1499 symtab.cc:1715
+#: symtab.cc:1625 symtab.cc:1824
#, c-format
msgid "%s: unsupported symbol section 0x%x"
msgstr ""
-#: symtab.cc:1839
+#: symtab.cc:1952
#, c-format
msgid "%s: undefined reference to '%s'"
msgstr ""
-#: symtab.cc:1924
+#: symtab.cc:2037
#, c-format
msgid "%s: symbol table entries: %zu; buckets: %zu\n"
msgstr ""
-#: symtab.cc:1927
+#: symtab.cc:2040
#, c-format
msgid "%s: symbol table entries: %zu\n"
msgstr ""
-#: symtab.cc:1996
+#: symtab.cc:2109
#, c-format
msgid ""
"while linking %s: symbol '%s' defined in multiple places (possible ODR "
@@ -1188,12 +1192,12 @@ msgstr ""
msgid "%s failed: %s"
msgstr ""
-#: x86_64.cc:1281
+#: x86_64.cc:1283
#, c-format
msgid "%s: unsupported REL reloc section"
msgstr ""
-#: x86_64.cc:1748
+#: x86_64.cc:1750
#, c-format
msgid "unsupported reloc type %u"
msgstr ""
diff --git a/gold/script-sections.cc b/gold/script-sections.cc
index de6da3059d..2505170fb7 100644
--- a/gold/script-sections.cc
+++ b/gold/script-sections.cc
@@ -22,9 +22,17 @@
#include "gold.h"
+#include <cstring>
+#include <algorithm>
+#include <list>
#include <string>
#include <vector>
+#include <fnmatch.h>
+#include "parameters.h"
+#include "object.h"
+#include "layout.h"
+#include "output.h"
#include "script-c.h"
#include "script.h"
#include "script-sections.h"
@@ -45,6 +53,36 @@ class Sections_element
virtual ~Sections_element()
{ }
+ // Add any symbol being defined to the symbol table.
+ virtual void
+ add_symbols_to_table(Symbol_table*)
+ { }
+
+ // Finalize symbols and check assertions.
+ virtual void
+ finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*)
+ { }
+
+ // Return the output section name to use for an input file name and
+ // section name. This only real implementation is in
+ // Output_section_definition.
+ virtual const char*
+ output_section_name(const char*, const char*, Output_section***)
+ { return NULL; }
+
+ // Return whether to place an orphan output section after this
+ // element.
+ virtual bool
+ place_orphan_here(const Output_section *, bool*) const
+ { return false; }
+
+ // Set section addresses. This includes applying assignments if the
+ // the expression is an absolute value.
+ virtual void
+ set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*)
+ { }
+
+ // Print the element for debugging purposes.
virtual void
print(FILE* f) const = 0;
};
@@ -59,6 +97,32 @@ class Sections_element_assignment : public Sections_element
: assignment_(name, namelen, val, provide, hidden)
{ }
+ // Add the symbol to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab)
+ { this->assignment_.add_to_table(symtab); }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value,
+ *dot_value);
+ }
+
+ // Set the section address. There is no section here, but if the
+ // value is absolute, we set the symbol. This permits us to use
+ // absolute symbols when setting dot.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ this->assignment_.set_if_absolute(symtab, layout, true, *dot_has_value,
+ *dot_value);
+ }
+
+ // Print for debugging.
void
print(FILE* f) const
{
@@ -70,6 +134,53 @@ class Sections_element_assignment : public Sections_element
Symbol_assignment assignment_;
};
+// An assignment to the dot symbol in a SECTIONS clause outside of an
+// output section.
+
+class Sections_element_dot_assignment : public Sections_element
+{
+ public:
+ Sections_element_dot_assignment(Expression* val)
+ : val_(val)
+ { }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ bool dummy;
+ *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &dummy);
+ *dot_has_value = true;
+ }
+
+ // Update the dot symbol while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ bool is_absolute;
+ *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("dot set to non-absolute value"));
+ *dot_has_value = true;
+ }
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " . = ");
+ this->val_->print(f);
+ fprintf(f, "\n");
+ }
+
+ private:
+ Expression* val_;
+};
+
// An assertion in a SECTIONS clause outside of an output section.
class Sections_element_assertion : public Sections_element
@@ -80,6 +191,13 @@ class Sections_element_assertion : public Sections_element
: assertion_(check, message, messagelen)
{ }
+ // Check the assertion.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout, bool*,
+ uint64_t*)
+ { this->assertion_.check(symtab, layout); }
+
+ // Print for debugging.
void
print(FILE* f) const
{
@@ -96,16 +214,62 @@ class Sections_element_assertion : public Sections_element
class Output_section_element
{
public:
+ // A list of input sections.
+ typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+
Output_section_element()
{ }
virtual ~Output_section_element()
{ }
+ // Add any symbol being defined to the symbol table.
+ virtual void
+ add_symbols_to_table(Symbol_table*)
+ { }
+
+ // Finalize symbols and check assertions.
+ virtual void
+ finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*)
+ { }
+
+ // Return whether this element matches FILE_NAME and SECTION_NAME.
+ // The only real implementation is in Output_section_element_input.
+ virtual bool
+ match_name(const char*, const char*) const
+ { return false; }
+
+ // Set section addresses. This includes applying assignments if the
+ // the expression is an absolute value.
+ virtual void
+ set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t,
+ uint64_t*, std::string*, Input_section_list*)
+ { }
+
+ // Print the element for debugging purposes.
virtual void
print(FILE* f) const = 0;
+
+ protected:
+ // Return a fill string that is LENGTH bytes long, filling it with
+ // FILL.
+ std::string
+ get_fill_string(const std::string* fill, section_size_type length) const;
};
+std::string
+Output_section_element::get_fill_string(const std::string* fill,
+ section_size_type length) const
+{
+ std::string this_fill;
+ this_fill.reserve(length);
+ while (this_fill.length() + fill->length() <= length)
+ this_fill += *fill;
+ if (this_fill.length() < length)
+ this_fill.append(*fill, 0, length - this_fill.length());
+ return this_fill;
+}
+
// A symbol assignment in an output section.
class Output_section_element_assignment : public Output_section_element
@@ -117,6 +281,32 @@ class Output_section_element_assignment : public Output_section_element
: assignment_(name, namelen, val, provide, hidden)
{ }
+ // Add the symbol to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab)
+ { this->assignment_.add_to_table(symtab); }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ this->assignment_.finalize_with_dot(symtab, layout, *dot_has_value,
+ *dot_value);
+ }
+
+ // Set the section address. There is no section here, but if the
+ // value is absolute, we set the symbol. This permits us to use
+ // absolute symbols when setting dot.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, std::string*,
+ Input_section_list*)
+ {
+ this->assignment_.set_if_absolute(symtab, layout, true, true, *dot_value);
+ }
+
+ // Print for debugging.
void
print(FILE* f) const
{
@@ -128,6 +318,81 @@ class Output_section_element_assignment : public Output_section_element
Symbol_assignment assignment_;
};
+// An assignment to the dot symbol in an output section.
+
+class Output_section_element_dot_assignment : public Output_section_element
+{
+ public:
+ Output_section_element_dot_assignment(Expression* val)
+ : val_(val)
+ { }
+
+ // Finalize the symbol.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value)
+ {
+ bool dummy;
+ *dot_value = this->val_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &dummy);
+ *dot_has_value = true;
+ }
+
+ // Update the dot symbol while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, std::string*,
+ Input_section_list*);
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " . = ");
+ this->val_->print(f);
+ fprintf(f, "\n");
+ }
+
+ private:
+ Expression* val_;
+};
+
+// Update the dot symbol while setting section addresses.
+
+void
+Output_section_element_dot_assignment::set_section_addresses(
+ Symbol_table* symtab,
+ Layout* layout,
+ Output_section* output_section,
+ uint64_t,
+ uint64_t* dot_value,
+ std::string* fill,
+ Input_section_list*)
+{
+ bool is_absolute;
+ uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, true,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("dot set to non-absolute value"));
+ if (next_dot < *dot_value)
+ gold_error(_("dot may not move backward"));
+ if (next_dot > *dot_value && output_section != NULL)
+ {
+ section_size_type length = convert_to_section_size_type(next_dot
+ - *dot_value);
+ Output_section_data* posd;
+ if (fill->empty())
+ posd = new Output_data_fixed_space(length, 0);
+ else
+ {
+ std::string this_fill = this->get_fill_string(fill, length);
+ posd = new Output_data_const(this_fill, 0);
+ }
+ output_section->add_output_section_data(posd);
+ }
+ *dot_value = next_dot;
+}
+
// An assertion in an output section.
class Output_section_element_assertion : public Output_section_element
@@ -158,10 +423,26 @@ class Output_section_element_data : public Output_section_element
: size_(size), is_signed_(is_signed), val_(val)
{ }
+ // Finalize symbols--we just need to update dot.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t* dot_value)
+ { *dot_value += this->size_; }
+
+ // Store the value in the section.
+ void
+ set_section_addresses(Symbol_table*, Layout*, Output_section*, uint64_t,
+ uint64_t* dot_value, std::string*,
+ Input_section_list*);
+
+ // Print for debugging.
void
print(FILE*) const;
private:
+ template<bool big_endian>
+ std::string
+ set_fill_string(uint64_t);
+
// The size in bytes.
int size_;
// Whether the value is signed.
@@ -170,6 +451,74 @@ class Output_section_element_data : public Output_section_element
Expression* val_;
};
+// Store the value in the section.
+
+void
+Output_section_element_data::set_section_addresses(Symbol_table* symtab,
+ Layout* layout,
+ Output_section* os,
+ uint64_t,
+ uint64_t* dot_value,
+ std::string*,
+ Input_section_list*)
+{
+ gold_assert(os != NULL);
+
+ bool is_absolute;
+ uint64_t val = this->val_->eval_with_dot(symtab, layout, true, *dot_value,
+ &is_absolute);
+ if (!is_absolute)
+ gold_error(_("data directive with non-absolute value"));
+
+ std::string fill;
+ if (parameters->is_big_endian())
+ fill = this->set_fill_string<true>(val);
+ else
+ fill = this->set_fill_string<false>(val);
+
+ os->add_output_section_data(new Output_data_const(fill, 0));
+
+ *dot_value += this->size_;
+}
+
+// Get the value to store in a std::string.
+
+template<bool big_endian>
+std::string
+ Output_section_element_data::set_fill_string(uint64_t val)
+{
+ std::string ret;
+ unsigned char buf[8];
+ switch (this->size_)
+ {
+ case 1:
+ elfcpp::Swap_unaligned<8, big_endian>::writeval(buf, val);
+ ret.assign(reinterpret_cast<char*>(buf), 1);
+ break;
+ case 2:
+ elfcpp::Swap_unaligned<16, big_endian>::writeval(buf, val);
+ ret.assign(reinterpret_cast<char*>(buf), 2);
+ break;
+ case 4:
+ elfcpp::Swap_unaligned<32, big_endian>::writeval(buf, val);
+ ret.assign(reinterpret_cast<char*>(buf), 4);
+ break;
+ case 8:
+ if (parameters->get_size() == 32)
+ {
+ val &= 0xffffffff;
+ if (this->is_signed_ && (val & 0x80000000) != 0)
+ val |= 0xffffffff00000000LL;
+ }
+ elfcpp::Swap_unaligned<64, big_endian>::writeval(buf, val);
+ ret.assign(reinterpret_cast<char*>(buf), 8);
+ break;
+ default:
+ gold_unreachable();
+ }
+ return ret;
+}
+
// Print for debugging.
void
@@ -210,6 +559,25 @@ class Output_section_element_fill : public Output_section_element
: val_(val)
{ }
+ // Update the fill value while setting section addresses.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t, uint64_t* dot_value, std::string* fill,
+ Input_section_list*)
+ {
+ bool is_absolute;
+ uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, true,
+ *dot_value,
+ &is_absolute);
+ if (!is_absolute)
+ gold_error(_("fill set to non-absolute value"));
+ // FIXME: The GNU linker supports fill values of arbitrary length.
+ unsigned char fill_buff[4];
+ elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val);
+ fill->assign(reinterpret_cast<char*>(fill_buff), 4);
+ }
+
+ // Print for debugging.
void
print(FILE* f) const
{
@@ -223,16 +591,43 @@ class Output_section_element_fill : public Output_section_element
Expression* val_;
};
+// Return whether STRING contains a wildcard character. This is used
+// to speed up matching.
+
+static inline bool
+is_wildcard_string(const std::string& s)
+{
+ return strpbrk(s.c_str(), "?*[") != NULL;
+}
+
// An input section specification in an output section
class Output_section_element_input : public Output_section_element
{
public:
- // Note that an Input_section_spec holds some pointers to vectors.
- // This constructor takes ownership of them. The parser is
- // implemented such that this works.
Output_section_element_input(const Input_section_spec* spec, bool keep);
+ // Finalize symbols--just update the value of the dot symbol.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, bool* dot_has_value,
+ uint64_t* dot_value)
+ {
+ *dot_value = this->final_dot_value_;
+ *dot_has_value = true;
+ }
+
+ // See whether we match FILE_NAME and SECTION_NAME as an input
+ // section.
+ bool
+ match_name(const char* file_name, const char* section_name) const;
+
+ // Set the section address.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
+ uint64_t subalign, uint64_t* dot_value,
+ std::string* fill, Input_section_list*);
+
+ // Print for debugging.
void
print(FILE* f) const;
@@ -241,20 +636,42 @@ class Output_section_element_input : public Output_section_element
struct Input_section_pattern
{
std::string pattern;
+ bool pattern_is_wildcard;
Sort_wildcard sort;
Input_section_pattern(const char* patterna, size_t patternlena,
Sort_wildcard sorta)
- : pattern(patterna, patternlena), sort(sorta)
+ : pattern(patterna, patternlena),
+ pattern_is_wildcard(is_wildcard_string(this->pattern)),
+ sort(sorta)
{ }
};
typedef std::vector<Input_section_pattern> Input_section_patterns;
- typedef std::vector<std::string> Filename_exclusions;
+ // Filename_exclusions is a pair of filename pattern and a bool
+ // indicating whether the filename is a wildcard.
+ typedef std::vector<std::pair<std::string, bool> > Filename_exclusions;
+
+ // Return whether STRING matches PATTERN, where IS_WILDCARD_PATTERN
+ // indicates whether this is a wildcard pattern.
+ static inline bool
+ match(const char* string, const char* pattern, bool is_wildcard_pattern)
+ {
+ return (is_wildcard_pattern
+ ? fnmatch(pattern, string, 0) == 0
+ : strcmp(string, pattern) == 0);
+ }
+
+ // See if we match a file name.
+ bool
+ match_file_name(const char* file_name) const;
- // The file name pattern.
+ // The file name pattern. If this is the empty string, we match all
+ // files.
std::string filename_pattern_;
+ // Whether the file name pattern is a wildcard.
+ bool filename_is_wildcard_;
// How the file names should be sorted. This may only be
// SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME.
Sort_wildcard filename_sort_;
@@ -264,6 +681,8 @@ class Output_section_element_input : public Output_section_element
Input_section_patterns input_section_patterns_;
// Whether to keep this section when garbage collecting.
bool keep_;
+ // The value of dot after including all matching sections.
+ uint64_t final_dot_value_;
};
// Construct Output_section_element_input. The parser records strings
@@ -273,19 +692,32 @@ class Output_section_element_input : public Output_section_element
Output_section_element_input::Output_section_element_input(
const Input_section_spec* spec,
bool keep)
- : filename_pattern_(spec->file.name.value, spec->file.name.length),
+ : filename_pattern_(),
+ filename_is_wildcard_(false),
filename_sort_(spec->file.sort),
filename_exclusions_(),
input_section_patterns_(),
- keep_(keep)
+ keep_(keep),
+ final_dot_value_(0)
{
+ // The filename pattern "*" is common, and matches all files. Turn
+ // it into the empty string.
+ if (spec->file.name.length != 1 || spec->file.name.value[0] != '*')
+ this->filename_pattern_.assign(spec->file.name.value,
+ spec->file.name.length);
+ this->filename_is_wildcard_ = is_wildcard_string(this->filename_pattern_);
+
if (spec->input_sections.exclude != NULL)
{
for (String_list::const_iterator p =
spec->input_sections.exclude->begin();
p != spec->input_sections.exclude->end();
++p)
- this->filename_exclusions_.push_back(*p);
+ {
+ bool is_wildcard = is_wildcard_string(*p);
+ this->filename_exclusions_.push_back(std::make_pair(*p,
+ is_wildcard));
+ }
}
if (spec->input_sections.sections != NULL)
@@ -300,6 +732,253 @@ Output_section_element_input::Output_section_element_input(
}
}
+// See whether we match FILE_NAME.
+
+bool
+Output_section_element_input::match_file_name(const char* file_name) const
+{
+ if (!this->filename_pattern_.empty())
+ {
+ // If we were called with no filename, we refuse to match a
+ // pattern which requires a file name.
+ if (file_name == NULL)
+ return false;
+
+ if (!match(file_name, this->filename_pattern_.c_str(),
+ this->filename_is_wildcard_))
+ return false;
+ }
+
+ if (file_name != NULL)
+ {
+ // Now we have to see whether FILE_NAME matches one of the
+ // exclusion patterns, if any.
+ for (Filename_exclusions::const_iterator p =
+ this->filename_exclusions_.begin();
+ p != this->filename_exclusions_.end();
+ ++p)
+ {
+ if (match(file_name, p->first.c_str(), p->second))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// See whether we match FILE_NAME and SECTION_NAME.
+
+bool
+Output_section_element_input::match_name(const char* file_name,
+ const char* section_name) const
+{
+ if (!this->match_file_name(file_name))
+ return false;
+
+ // If there are no section name patterns, then we match.
+ if (this->input_section_patterns_.empty())
+ return true;
+
+ // See whether we match the section name patterns.
+ for (Input_section_patterns::const_iterator p =
+ this->input_section_patterns_.begin();
+ p != this->input_section_patterns_.end();
+ ++p)
+ {
+ if (match(section_name, p->pattern.c_str(), p->pattern_is_wildcard))
+ return true;
+ }
+
+ // We didn't match any section names, so we didn't match.
+ return false;
+}
+
+// Information we use to sort the input sections.
+
+struct Input_section_info
+{
+ Relobj* relobj;
+ unsigned int shndx;
+ std::string section_name;
+ uint64_t size;
+ uint64_t addralign;
+};
+
+// A class to sort the input sections.
+
+class Input_section_sorter
+{
+ public:
+ Input_section_sorter(Sort_wildcard filename_sort, Sort_wildcard section_sort)
+ : filename_sort_(filename_sort), section_sort_(section_sort)
+ { }
+
+ bool
+ operator()(const Input_section_info&, const Input_section_info&) const;
+
+ private:
+ Sort_wildcard filename_sort_;
+ Sort_wildcard section_sort_;
+};
+
+bool
+Input_section_sorter::operator()(const Input_section_info& isi1,
+ const Input_section_info& isi2) const
+{
+ if (this->section_sort_ == SORT_WILDCARD_BY_NAME
+ || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
+ || (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME
+ && isi1.addralign == isi2.addralign))
+ {
+ if (isi1.section_name != isi2.section_name)
+ return isi1.section_name < isi2.section_name;
+ }
+ if (this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT
+ || this->section_sort_ == SORT_WILDCARD_BY_NAME_BY_ALIGNMENT
+ || this->section_sort_ == SORT_WILDCARD_BY_ALIGNMENT_BY_NAME)
+ {
+ if (isi1.addralign != isi2.addralign)
+ return isi1.addralign < isi2.addralign;
+ }
+ if (this->filename_sort_ == SORT_WILDCARD_BY_NAME)
+ {
+ if (isi1.relobj->name() != isi2.relobj->name())
+ return isi1.relobj->name() < isi2.relobj->name();
+ }
+
+ // Otherwise we leave them in the same order.
+ return false;
+}
+
+// Set the section address. Look in INPUT_SECTIONS for sections which
+// match this spec, sort them as specified, and add them to the output
+// section.
+
+void
+Output_section_element_input::set_section_addresses(
+ Symbol_table*,
+ Layout*,
+ Output_section* output_section,
+ uint64_t subalign,
+ uint64_t* dot_value,
+ std::string* fill,
+ Input_section_list* input_sections)
+{
+ // We build a list of sections which match each
+ // Input_section_pattern.
+
+ typedef std::vector<std::vector<Input_section_info> > Matching_sections;
+ size_t input_pattern_count = this->input_section_patterns_.size();
+ if (input_pattern_count == 0)
+ input_pattern_count = 1;
+ Matching_sections matching_sections(input_pattern_count);
+
+ // Look through the list of sections for this output section. Add
+ // each one which matches to one of the elements of
+ // MATCHING_SECTIONS.
+
+ Input_section_list::iterator p = input_sections->begin();
+ while (p != input_sections->end())
+ {
+ // Calling section_name and section_addralign is not very
+ // efficient.
+ Input_section_info isi;
+ isi.relobj = p->first;
+ isi.shndx = p->second;
+
+ // Lock the object so that we can get information about the
+ // section. This is OK since we know we are single-threaded
+ // here.
+ {
+ const Task* task = reinterpret_cast<const Task*>(-1);
+ Task_lock_obj<Object> tl(task, p->first);
+
+ isi.section_name = p->first->section_name(p->second);
+ isi.size = p->first->section_size(p->second);
+ isi.addralign = p->first->section_addralign(p->second);
+ }
+
+ if (!this->match_file_name(isi.relobj->name().c_str()))
+ ++p;
+ else if (this->input_section_patterns_.empty())
+ {
+ matching_sections[0].push_back(isi);
+ p = input_sections->erase(p);
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < input_pattern_count; ++i)
+ {
+ const Input_section_pattern&
+ isp(this->input_section_patterns_[i]);
+ if (match(isi.section_name.c_str(), isp.pattern.c_str(),
+ isp.pattern_is_wildcard))
+ break;
+ }
+
+ if (i >= this->input_section_patterns_.size())
+ ++p;
+ else
+ {
+ matching_sections[i].push_back(isi);
+ p = input_sections->erase(p);
+ }
+ }
+ }
+
+ // Look through MATCHING_SECTIONS. Sort each one as specified,
+ // using a stable sort so that we get the default order when
+ // sections are otherwise equal. Add each input section to the
+ // output section.
+
+ for (size_t i = 0; i < input_pattern_count; ++i)
+ {
+ if (matching_sections[i].empty())
+ continue;
+
+ gold_assert(output_section != NULL);
+
+ const Input_section_pattern& isp(this->input_section_patterns_[i]);
+ if (isp.sort != SORT_WILDCARD_NONE
+ || this->filename_sort_ != SORT_WILDCARD_NONE)
+ std::stable_sort(matching_sections[i].begin(),
+ matching_sections[i].end(),
+ Input_section_sorter(this->filename_sort_,
+ isp.sort));
+
+ for (std::vector<Input_section_info>::const_iterator p =
+ matching_sections[i].begin();
+ p != matching_sections[i].end();
+ ++p)
+ {
+ uint64_t this_subalign = p->addralign;
+ if (this_subalign < subalign)
+ this_subalign = subalign;
+
+ uint64_t address = align_address(*dot_value, this_subalign);
+
+ if (address > *dot_value && !fill->empty())
+ {
+ section_size_type length =
+ convert_to_section_size_type(address - *dot_value);
+ std::string this_fill = this->get_fill_string(fill, length);
+ Output_section_data* posd = new Output_data_const(this_fill, 0);
+ output_section->add_output_section_data(posd);
+ }
+
+ output_section->add_input_section_for_script(p->relobj,
+ p->shndx,
+ p->size,
+ this_subalign);
+
+ *dot_value = address + p->size;
+ }
+ }
+
+ this->final_dot_value_ = *dot_value;
+}
+
// Print for debugging.
void
@@ -348,7 +1027,7 @@ Output_section_element_input::print(FILE* f) const
{
if (need_comma)
fprintf(f, ", ");
- fprintf(f, "%s", p->c_str());
+ fprintf(f, "%s", p->first.c_str());
need_comma = true;
}
fprintf(f, ")");
@@ -410,6 +1089,8 @@ Output_section_element_input::print(FILE* f) const
class Output_section_definition : public Sections_element
{
public:
+ typedef Output_section_element::Input_section_list Input_section_list;
+
Output_section_definition(const char* name, size_t namelen,
const Parser_output_section_header* header);
@@ -421,6 +1102,11 @@ class Output_section_definition : public Sections_element
void
add_symbol_assignment(const char* name, size_t length, Expression* value,
bool provide, bool hidden);
+
+ // Add an assignment to the special dot symbol.
+ void
+ add_dot_assignment(Expression* value);
+
// Add an assertion.
void
add_assertion(Expression* check, const char* message, size_t messagelen);
@@ -437,6 +1123,29 @@ class Output_section_definition : public Sections_element
void
add_input_section(const Input_section_spec* spec, bool keep);
+ // Add any symbols being defined to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table* symtab);
+
+ // Finalize symbols and check assertions.
+ void
+ finalize_symbols(Symbol_table*, const Layout*, bool*, uint64_t*);
+
+ // Return the output section name to use for an input file name and
+ // section name.
+ const char*
+ output_section_name(const char* file_name, const char* section_name,
+ Output_section***);
+
+ // Return whether to place an orphan section after this one.
+ bool
+ place_orphan_here(const Output_section *os, bool* exact) const;
+
+ // Set the section address.
+ void
+ set_section_addresses(Symbol_table* symtab, Layout* layout,
+ bool* dot_has_value, uint64_t* dot_value);
+
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
@@ -458,6 +1167,9 @@ class Output_section_definition : public Sections_element
Expression* fill_;
// The list of elements defining the section.
Output_section_elements elements_;
+ // The Output_section created for this definition. This will be
+ // NULL if none was created.
+ Output_section* output_section_;
};
// Constructor.
@@ -472,7 +1184,8 @@ Output_section_definition::Output_section_definition(
align_(header->align),
subalign_(header->subalign),
fill_(NULL),
- elements_()
+ elements_(),
+ output_section_(NULL)
{
}
@@ -501,6 +1214,15 @@ Output_section_definition::add_symbol_assignment(const char* name,
this->elements_.push_back(p);
}
+// Add an assignment to the special dot symbol.
+
+void
+Output_section_definition::add_dot_assignment(Expression* value)
+{
+ Output_section_element* p = new Output_section_element_dot_assignment(value);
+ this->elements_.push_back(p);
+}
+
// Add an assertion.
void
@@ -543,6 +1265,281 @@ Output_section_definition::add_input_section(const Input_section_spec* spec,
this->elements_.push_back(p);
}
+// Add any symbols being defined to the symbol table.
+
+void
+Output_section_definition::add_symbols_to_table(Symbol_table* symtab)
+{
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->add_symbols_to_table(symtab);
+}
+
+// Finalize symbols and check assertions.
+
+void
+Output_section_definition::finalize_symbols(Symbol_table* symtab,
+ const Layout* layout,
+ bool* dot_has_value,
+ uint64_t* dot_value)
+{
+ if (this->output_section_ != NULL)
+ *dot_value = this->output_section_->address();
+ else
+ {
+ uint64_t address = *dot_value;
+ if (this->address_ != NULL)
+ {
+ bool dummy;
+ address = this->address_->eval_with_dot(symtab, layout,
+ *dot_has_value, *dot_value,
+ &dummy);
+ }
+ if (this->align_ != NULL)
+ {
+ bool dummy;
+ uint64_t align = this->align_->eval_with_dot(symtab, layout,
+ *dot_has_value,
+ *dot_value,
+ &dummy);
+ address = align_address(address, align);
+ }
+ *dot_value = address;
+ }
+ *dot_has_value = true;
+
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->finalize_symbols(symtab, layout, dot_has_value, dot_value);
+}
+
+// Return the output section name to use for an input section name.
+
+const char*
+Output_section_definition::output_section_name(const char* file_name,
+ const char* section_name,
+ Output_section*** slot)
+{
+ // Ask each element whether it matches NAME.
+ for (Output_section_elements::const_iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ {
+ if ((*p)->match_name(file_name, section_name))
+ {
+ // We found a match for NAME, which means that it should go
+ // into this output section.
+ *slot = &this->output_section_;
+ return this->name_.c_str();
+ }
+ }
+
+ // We don't know about this section name.
+ return NULL;
+}
+
+// Return whether to place an orphan output section after this
+// section.
+
+bool
+Output_section_definition::place_orphan_here(const Output_section *os,
+ bool* exact) const
+{
+ // Check for the simple case first.
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == os->type()
+ && this->output_section_->flags() == os->flags())
+ {
+ *exact = true;
+ return true;
+ }
+
+ // Otherwise use some heuristics.
+
+ if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
+ return false;
+
+ if (os->type() == elfcpp::SHT_NOBITS)
+ {
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == elfcpp::SHT_NOBITS)
+ return true;
+ if (this->name_ == ".bss")
+ return true;
+ }
+ else if (os->type() == elfcpp::SHT_NOTE)
+ {
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == elfcpp::SHT_NOTE)
+ return true;
+ if (this->name_ == ".interp"
+ || this->name_.compare(0, 5, ".note") == 0)
+ return true;
+ }
+ else if (os->type() == elfcpp::SHT_REL || os->type() == elfcpp::SHT_RELA)
+ {
+ if (this->output_section_ != NULL
+ && (this->output_section_->type() == elfcpp::SHT_REL
+ || this->output_section_->type() == elfcpp::SHT_RELA))
+ return true;
+ if (this->name_.compare(0, 4, ".rel") == 0)
+ return true;
+ }
+ else if (os->type() == elfcpp::SHT_PROGBITS
+ && (os->flags() & elfcpp::SHF_WRITE) != 0)
+ {
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == elfcpp::SHT_PROGBITS
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
+ return true;
+ if (this->name_ == ".data")
+ return true;
+ }
+ else if (os->type() == elfcpp::SHT_PROGBITS
+ && (os->flags() & elfcpp::SHF_EXECINSTR) != 0)
+ {
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == elfcpp::SHT_PROGBITS
+ && (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) != 0)
+ return true;
+ if (this->name_ == ".text")
+ return true;
+ }
+ else if (os->type() == elfcpp::SHT_PROGBITS)
+ {
+ if (this->output_section_ != NULL
+ && this->output_section_->type() == elfcpp::SHT_PROGBITS
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0
+ && (this->output_section_->flags() & elfcpp::SHF_EXECINSTR) == 0)
+ return true;
+ if (this->name_ == ".rodata")
+ return true;
+ }
+
+ return false;
+}
+
+// Set the section address. Note that the OUTPUT_SECTION_ field will
+// be NULL if no input sections were mapped to this output section.
+// We still have to adjust dot and process symbol assignments.
+
+void
+Output_section_definition::set_section_addresses(Symbol_table* symtab,
+ Layout* layout,
+ bool* dot_has_value,
+ uint64_t* dot_value)
+{
+ bool is_absolute;
+ uint64_t address;
+ if (this->address_ != NULL)
+ {
+ address = this->address_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("address of section %s is not absolute"),
+ this->name_.c_str());
+ }
+ else
+ {
+ if (!*dot_has_value)
+ gold_error(_("no address given for section %s"),
+ this->name_.c_str());
+ address = *dot_value;
+ }
+
+ uint64_t align;
+ if (this->align_ == NULL)
+ {
+ if (this->output_section_ == NULL)
+ align = 0;
+ else
+ align = this->output_section_->addralign();
+ }
+ else
+ {
+ align = this->align_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("alignment of section %s is not absolute"),
+ this->name_.c_str());
+ if (this->output_section_ != NULL)
+ this->output_section_->set_addralign(align);
+ }
+
+ address = align_address(address, align);
+
+ *dot_value = address;
+ *dot_has_value = true;
+
+ // The address of non-SHF_ALLOC sections is forced to zero,
+ // regardless of what the linker script wants.
+ if (this->output_section_ != NULL
+ && (this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0)
+ this->output_section_->set_address(address);
+
+ if (this->load_address_ != NULL && this->output_section_ != NULL)
+ {
+ uint64_t load_address =
+ this->load_address_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("load address of section %s is not absolute"),
+ this->name_.c_str());
+ this->output_section_->set_load_address(load_address);
+ }
+
+ uint64_t subalign;
+ if (this->subalign_ == NULL)
+ subalign = 0;
+ else
+ {
+ subalign = this->subalign_->eval_with_dot(symtab, layout, *dot_has_value,
+ *dot_value, &is_absolute);
+ if (!is_absolute)
+ gold_error(_("subalign of section %s is not absolute"),
+ this->name_.c_str());
+ }
+
+ std::string fill;
+ if (this->fill_ != NULL)
+ {
+ // FIXME: The GNU linker supports fill values of arbitrary
+ // length.
+ uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout,
+ *dot_has_value,
+ *dot_value,
+ &is_absolute);
+ if (!is_absolute)
+ gold_error(_("fill of section %s is not absolute"),
+ this->name_.c_str());
+ unsigned char fill_buff[4];
+ elfcpp::Swap_unaligned<32, true>::writeval(fill_buff, fill_val);
+ fill.assign(reinterpret_cast<char*>(fill_buff), 4);
+ }
+
+ Input_section_list input_sections;
+ if (this->output_section_ != NULL)
+ {
+ // Get the list of input sections attached to this output
+ // section. This will leave the output section with only
+ // Output_section_data entries.
+ address += this->output_section_->get_input_sections(address,
+ fill,
+ &input_sections);
+ *dot_value = address;
+ }
+
+ for (Output_section_elements::iterator p = this->elements_.begin();
+ p != this->elements_.end();
+ ++p)
+ (*p)->set_section_addresses(symtab, layout, this->output_section_,
+ subalign, dot_value, &fill, &input_sections);
+
+ gold_assert(input_sections.empty());
+}
+
// Print for debugging.
void
@@ -597,6 +1594,98 @@ Output_section_definition::print(FILE* f) const
fprintf(f, "\n");
}
+// An output section created to hold orphaned input sections. These
+// do not actually appear in linker scripts. However, for convenience
+// when setting the output section addresses, we put a marker to these
+// sections in the appropriate place in the list of SECTIONS elements.
+
+class Orphan_output_section : public Sections_element
+{
+ public:
+ Orphan_output_section(Output_section* os)
+ : os_(os)
+ { }
+
+ // Return whether to place an orphan section after this one.
+ bool
+ place_orphan_here(const Output_section *os, bool* exact) const;
+
+ // Set section addresses.
+ void
+ set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*);
+
+ // Print for debugging.
+ void
+ print(FILE* f) const
+ {
+ fprintf(f, " marker for orphaned output section %s\n",
+ this->os_->name());
+ }
+
+ private:
+ Output_section* os_;
+};
+
+// Whether to place another orphan section after this one.
+
+bool
+Orphan_output_section::place_orphan_here(const Output_section* os,
+ bool* exact) const
+{
+ if (this->os_->type() == os->type()
+ && this->os_->flags() == os->flags())
+ {
+ *exact = true;
+ return true;
+ }
+ return false;
+}
+
+// Set section addresses.
+
+void
+Orphan_output_section::set_section_addresses(Symbol_table*, Layout*,
+ bool* dot_has_value,
+ uint64_t* dot_value)
+{
+ typedef std::list<std::pair<Relobj*, unsigned int> > Input_section_list;
+
+ if (!*dot_has_value)
+ gold_error(_("no address for orphan section %s"), this->os_->name());
+
+ uint64_t address = *dot_value;
+ address = align_address(address, this->os_->addralign());
+
+ if ((this->os_->flags() & elfcpp::SHF_ALLOC) != 0)
+ this->os_->set_address(address);
+
+ Input_section_list input_sections;
+ address += this->os_->get_input_sections(address, "", &input_sections);
+
+ for (Input_section_list::iterator p = input_sections.begin();
+ p != input_sections.end();
+ ++p)
+ {
+ uint64_t addralign;
+ uint64_t size;
+
+ // We know what are single-threaded, so it is OK to lock the
+ // object.
+ {
+ const Task* task = reinterpret_cast<const Task*>(-1);
+ Task_lock_obj<Object> tl(task, p->first);
+ addralign = p->first->section_addralign(p->second);
+ size = p->first->section_size(p->second);
+ }
+
+ address = align_address(address, addralign);
+ this->os_->add_input_section_for_script(p->first, p->second, size, 0);
+ address += size;
+ }
+
+ *dot_value = address;
+}
+
// Class Script_sections.
Script_sections::Script_sections()
@@ -647,6 +1736,20 @@ Script_sections::add_symbol_assignment(const char* name, size_t length,
}
}
+// Add an assignment to the special dot symbol.
+
+void
+Script_sections::add_dot_assignment(Expression* val)
+{
+ if (this->output_section_ != NULL)
+ this->output_section_->add_dot_assignment(val);
+ else
+ {
+ Sections_element* p = new Sections_element_dot_assignment(val);
+ this->sections_elements_->push_back(p);
+ }
+}
+
// Add an assertion.
void
@@ -717,6 +1820,402 @@ Script_sections::add_input_section(const Input_section_spec* spec, bool keep)
this->output_section_->add_input_section(spec, keep);
}
+// Add any symbols we are defining to the symbol table.
+
+void
+Script_sections::add_symbols_to_table(Symbol_table* symtab)
+{
+ if (!this->saw_sections_clause_)
+ return;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->add_symbols_to_table(symtab);
+}
+
+// Finalize symbols and check assertions.
+
+void
+Script_sections::finalize_symbols(Symbol_table* symtab, const Layout* layout)
+{
+ if (!this->saw_sections_clause_)
+ return;
+ bool dot_has_value = false;
+ uint64_t dot_value = 0;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->finalize_symbols(symtab, layout, &dot_has_value, &dot_value);
+}
+
+// Return the name of the output section to use for an input file name
+// and section name.
+
+const char*
+Script_sections::output_section_name(const char* file_name,
+ const char* section_name,
+ Output_section*** output_section_slot)
+{
+ for (Sections_elements::const_iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ const char* ret = (*p)->output_section_name(file_name, section_name,
+ output_section_slot);
+
+ if (ret != NULL)
+ {
+ // The special name /DISCARD/ means that the input section
+ // should be discarded.
+ if (strcmp(ret, "/DISCARD/") == 0)
+ {
+ *output_section_slot = NULL;
+ return NULL;
+ }
+ return ret;
+ }
+ }
+
+ // If we couldn't find a mapping for the name, the output section
+ // gets the name of the input section.
+
+ *output_section_slot = NULL;
+
+ return section_name;
+}
+
+// Place a marker for an orphan output section into the SECTIONS
+// clause.
+
+void
+Script_sections::place_orphan(Output_section* os)
+{
+ // Look for an output section definition which matches the output
+ // section. Put a marker after that section.
+ Sections_elements::iterator place = this->sections_elements_->end();
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ bool exact;
+ if ((*p)->place_orphan_here(os, &exact))
+ {
+ place = p;
+ if (exact)
+ break;
+ }
+ }
+
+ // The insert function puts the new element before the iterator.
+ if (place != this->sections_elements_->end())
+ ++place;
+
+ this->sections_elements_->insert(place, new Orphan_output_section(os));
+}
+
+// Set the addresses of all the output sections. Walk through all the
+// elements, tracking the dot symbol. Apply assignments which set
+// absolute symbol values, in case they are used when setting dot.
+// Fill in data statement values. As we find output sections, set the
+// address, set the address of all associated input sections, and
+// update dot. Return the segment which should hold the file header
+// and segment headers, if any.
+
+Output_segment*
+Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
+{
+ gold_assert(this->saw_sections_clause_);
+
+ bool dot_has_value = false;
+ uint64_t dot_value = 0;
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ (*p)->set_section_addresses(symtab, layout, &dot_has_value, &dot_value);
+
+ return this->create_segments(layout);
+}
+
+// Sort the sections in order to put them into segments.
+
+class Sort_output_sections
+{
+ public:
+ bool
+ operator()(const Output_section* os1, const Output_section* os2) const;
+};
+
+bool
+Sort_output_sections::operator()(const Output_section* os1,
+ const Output_section* os2) const
+{
+ // Sort first by the load address.
+ uint64_t lma1 = (os1->has_load_address()
+ ? os1->load_address()
+ : os1->address());
+ uint64_t lma2 = (os2->has_load_address()
+ ? os2->load_address()
+ : os2->address());
+ if (lma1 != lma2)
+ return lma1 < lma2;
+
+ // Then sort by the virtual address.
+ if (os1->address() != os2->address())
+ return os1->address() < os2->address();
+
+ // Sort TLS sections to the end.
+ bool tls1 = (os1->flags() & elfcpp::SHF_TLS) != 0;
+ bool tls2 = (os2->flags() & elfcpp::SHF_TLS) != 0;
+ if (tls1 != tls2)
+ return tls2;
+
+ // Sort PROGBITS before NOBITS.
+ if (os1->type() == elfcpp::SHT_PROGBITS && os2->type() == elfcpp::SHT_NOBITS)
+ return true;
+ if (os1->type() == elfcpp::SHT_NOBITS && os2->type() == elfcpp::SHT_PROGBITS)
+ return false;
+
+ // Otherwise we don't care.
+ return false;
+}
+
+// Return whether OS is a BSS section. This is a SHT_NOBITS section.
+// We treat a section with the SHF_TLS flag set as taking up space
+// even if it is SHT_NOBITS (this is true of .tbss), as we allocate
+// space for them in the file.
+
+bool
+Script_sections::is_bss_section(const Output_section* os)
+{
+ return (os->type() == elfcpp::SHT_NOBITS
+ && (os->flags() & elfcpp::SHF_TLS) == 0);
+}
+
+// Create the PT_LOAD segments when using a SECTIONS clause. Returns
+// the segment which should hold the file header and segment headers,
+// if any.
+
+Output_segment*
+Script_sections::create_segments(Layout* layout)
+{
+ gold_assert(this->saw_sections_clause_);
+
+ if (parameters->output_is_object())
+ return NULL;
+
+ Layout::Section_list sections;
+ layout->get_allocated_sections(&sections);
+
+ // Sort the sections by address.
+ std::stable_sort(sections.begin(), sections.end(), Sort_output_sections());
+
+ this->create_note_and_tls_segments(layout, &sections);
+
+ // Walk through the sections adding them to PT_LOAD segments.
+ const uint64_t abi_pagesize = parameters->target()->abi_pagesize();
+ Output_segment* first_seg = NULL;
+ Output_segment* current_seg = NULL;
+ bool is_current_seg_readonly = true;
+ Layout::Section_list::iterator plast = sections.end();
+ uint64_t last_vma = 0;
+ uint64_t last_lma = 0;
+ uint64_t last_size = 0;
+ for (Layout::Section_list::iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ {
+ const uint64_t vma = (*p)->address();
+ const uint64_t lma = ((*p)->has_load_address()
+ ? (*p)->load_address()
+ : vma);
+ const uint64_t size = (*p)->current_data_size();
+
+ bool need_new_segment;
+ if (current_seg == NULL)
+ need_new_segment = true;
+ else if (lma - vma != last_lma - last_vma)
+ {
+ // This section has a different LMA relationship than the
+ // last one; we need a new segment.
+ need_new_segment = true;
+ }
+ else if (align_address(last_lma + last_size, abi_pagesize)
+ < align_address(lma, abi_pagesize))
+ {
+ // Putting this section in the segment would require
+ // skipping a page.
+ need_new_segment = true;
+ }
+ else if (is_bss_section(*plast) && !is_bss_section(*p))
+ {
+ // A non-BSS section can not follow a BSS section in the
+ // same segment.
+ need_new_segment = true;
+ }
+ else if (is_current_seg_readonly
+ && ((*p)->flags() & elfcpp::SHF_WRITE) != 0)
+ {
+ // Don't put a writable section in the same segment as a
+ // non-writable section.
+ need_new_segment = true;
+ }
+ else
+ {
+ // Otherwise, reuse the existing segment.
+ need_new_segment = false;
+ }
+
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+
+ if (need_new_segment)
+ {
+ current_seg = layout->make_output_segment(elfcpp::PT_LOAD,
+ seg_flags);
+ current_seg->set_addresses(vma, lma);
+ if (first_seg == NULL)
+ first_seg = current_seg;
+ is_current_seg_readonly = true;
+ }
+
+ current_seg->add_output_section(*p, seg_flags);
+
+ if (((*p)->flags() & elfcpp::SHF_WRITE) != 0)
+ is_current_seg_readonly = false;
+
+ plast = p;
+ last_vma = vma;
+ last_lma = lma;
+ last_size = size;
+ }
+
+ // An ELF program should work even if the program headers are not in
+ // a PT_LOAD segment. However, it appears that the Linux kernel
+ // does not set the AT_PHDR auxiliary entry in that case. It sets
+ // the load address to p_vaddr - p_offset of the first PT_LOAD
+ // segment. It then sets AT_PHDR to the load address plus the
+ // offset to the program headers, e_phoff in the file header. This
+ // fails when the program headers appear in the file before the
+ // first PT_LOAD segment. Therefore, we always create a PT_LOAD
+ // segment to hold the file header and the program headers. This is
+ // effectively what the GNU linker does, and it is slightly more
+ // efficient in any case. We try to use the first PT_LOAD segment
+ // if we can, otherwise we make a new one.
+
+ size_t segment_count = layout->segment_count();
+ size_t file_header_size;
+ size_t segment_headers_size;
+ if (parameters->get_size() == 32)
+ {
+ file_header_size = elfcpp::Elf_sizes<32>::ehdr_size;
+ segment_headers_size = segment_count * elfcpp::Elf_sizes<32>::phdr_size;
+ }
+ else if (parameters->get_size() == 64)
+ {
+ file_header_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ segment_headers_size = segment_count * elfcpp::Elf_sizes<64>::phdr_size;
+ }
+ else
+ gold_unreachable();
+
+ if (first_seg != NULL
+ && ((first_seg->paddr() & (abi_pagesize - 1))
+ >= file_header_size + segment_headers_size))
+ return first_seg;
+
+ Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD,
+ elfcpp::PF_R);
+ if (first_seg == NULL)
+ load_seg->set_addresses(0, 0);
+ else
+ {
+ uint64_t vma = first_seg->vaddr();
+ uint64_t lma = first_seg->paddr();
+
+ if (lma >= file_header_size + segment_headers_size
+ && lma >= abi_pagesize)
+ {
+ // We want a segment with the same relationship between VMA
+ // and LMA, but with enough room for the headers.
+ uint64_t size_for_page = align_address((file_header_size
+ + segment_headers_size),
+ abi_pagesize);
+ load_seg->set_addresses(vma - size_for_page, lma - size_for_page);
+ }
+ else
+ {
+ // We could handle this case by create the file header
+ // outside of any PT_LOAD segment, and creating a new
+ // PT_LOAD segment after the others to hold the segment
+ // headers.
+ gold_error(_("sections loaded on first page without room for "
+ "file and program headers are not supported"));
+ }
+ }
+
+ return load_seg;
+}
+
+// Create a PT_NOTE segment for each SHT_NOTE section and a PT_TLS
+// segment if there are any SHT_TLS sections.
+
+void
+Script_sections::create_note_and_tls_segments(
+ Layout* layout,
+ const Layout::Section_list* sections)
+{
+ bool saw_tls = false;
+ for (Layout::Section_list::const_iterator p = sections->begin();
+ p != sections->end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::SHT_NOTE)
+ {
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+ Output_segment* oseg = layout->make_output_segment(elfcpp::PT_NOTE,
+ seg_flags);
+ oseg->add_output_section(*p, seg_flags);
+
+ // Incorporate any subsequent SHT_NOTE sections, in the
+ // hopes that the script is sensible.
+ Layout::Section_list::const_iterator pnext = p + 1;
+ while (pnext != sections->end()
+ && (*pnext)->type() == elfcpp::SHT_NOTE)
+ {
+ seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
+ oseg->add_output_section(*pnext, seg_flags);
+ p = pnext;
+ ++pnext;
+ }
+ }
+
+ if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ if (saw_tls)
+ gold_error(_("TLS sections are not adjacent"));
+
+ elfcpp::Elf_Word seg_flags =
+ Layout::section_flags_to_segment((*p)->flags());
+ Output_segment* oseg = layout->make_output_segment(elfcpp::PT_TLS,
+ seg_flags);
+ oseg->add_output_section(*p, seg_flags);
+
+ Layout::Section_list::const_iterator pnext = p + 1;
+ while (pnext != sections->end()
+ && ((*pnext)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ seg_flags = Layout::section_flags_to_segment((*pnext)->flags());
+ oseg->add_output_section(*pnext, seg_flags);
+ p = pnext;
+ ++pnext;
+ }
+
+ saw_tls = true;
+ }
+ }
+}
+
// Print the SECTIONS clause to F for debugging.
void
diff --git a/gold/script-sections.h b/gold/script-sections.h
index 434432508d..6ac4303a49 100644
--- a/gold/script-sections.h
+++ b/gold/script-sections.h
@@ -37,6 +37,8 @@ struct Input_section_spec;
class Expression;
class Sections_element;
class Output_section_definition;
+class Output_section;
+class Output_segment;
class Script_sections
{
@@ -79,6 +81,11 @@ class Script_sections
void
add_symbol_assignment(const char* name, size_t length, Expression* value,
bool provide, bool hidden);
+
+ // Add an assignment to the special dot symbol.
+ void
+ add_dot_assignment(Expression* value);
+
// Add an assertion.
void
add_assertion(Expression* check, const char* message, size_t messagelen);
@@ -91,6 +98,42 @@ class Script_sections
void
add_input_section(const Input_section_spec* spec, bool keep);
+ // Add any symbols we are defining to the symbol table.
+ void
+ add_symbols_to_table(Symbol_table*);
+
+ // Finalize symbol values and check assertions.
+ void
+ finalize_symbols(Symbol_table* symtab, const Layout* layout);
+
+ // Find the name of the output section to use for an input file name
+ // and section name. This returns a name, and sets
+ // *OUTPUT_SECTION_SLOT to point to the address where the actual
+ // output section may be stored.
+ // 1) If the input section should be discarded, this returns NULL
+ // and sets *OUTPUT_SECTION_SLOT to NULL.
+ // 2) If the input section is mapped by the SECTIONS clause, this
+ // returns the name to use for the output section (in permanent
+ // storage), and sets *OUTPUT_SECTION_SLOT to point to where the
+ // output section should be stored. **OUTPUT_SECTION_SLOT will be
+ // non-NULL if we have seen this output section already.
+ // 3) If the input section is not mapped by the SECTIONS clause,
+ // this returns SECTION_NAME, and sets *OUTPUT_SECTION_SLOT to
+ // NULL.
+ const char*
+ output_section_name(const char* file_name, const char* section_name,
+ Output_section*** output_section_slot);
+
+ // Place a marker for an orphan output section into the SECTIONS
+ // clause.
+ void
+ place_orphan(Output_section* os);
+
+ // Set the addresses of all the output sections. Return the segment
+ // which holds the file header and segment headers, if any.
+ Output_segment*
+ set_section_addresses(Symbol_table*, Layout*);
+
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
@@ -98,6 +141,18 @@ class Script_sections
private:
typedef std::vector<Sections_element*> Sections_elements;
+ // Create segments.
+ Output_segment*
+ create_segments(Layout*);
+
+ // Create PT_NOTE and PT_TLS segments.
+ void
+ create_note_and_tls_segments(Layout*, const std::vector<Output_section*>*);
+
+ // Return whether the section is a BSS section.
+ static bool
+ is_bss_section(const Output_section*);
+
// True if we ever saw a SECTIONS clause.
bool saw_sections_clause_;
// True if we are currently processing a SECTIONS clause.
diff --git a/gold/script.cc b/gold/script.cc
index 5b49a90d5b..734349b891 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -913,6 +913,29 @@ Symbol_assignment::add_to_table(Symbol_table* symtab)
void
Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
{
+ this->finalize_maybe_dot(symtab, layout, false, false, 0);
+}
+
+// Finalize a symbol value which can refer to the dot symbol.
+
+void
+Symbol_assignment::finalize_with_dot(Symbol_table* symtab,
+ const Layout* layout,
+ bool dot_has_value,
+ uint64_t dot_value)
+{
+ this->finalize_maybe_dot(symtab, layout, true, dot_has_value, dot_value);
+}
+
+// Finalize a symbol value, internal version.
+
+void
+Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab,
+ const Layout* layout,
+ bool is_dot_available,
+ bool dot_has_value,
+ uint64_t dot_value)
+{
// If we were only supposed to provide this symbol, the sym_ field
// will be NULL if the symbol was not referenced.
if (this->sym_ == NULL)
@@ -924,7 +947,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
if (parameters->get_size() == 32)
{
#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
- this->sized_finalize<32>(symtab, layout);
+ this->sized_finalize<32>(symtab, layout, is_dot_available, dot_has_value,
+ dot_value);
#else
gold_unreachable();
#endif
@@ -932,7 +956,8 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
else if (parameters->get_size() == 64)
{
#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
- this->sized_finalize<64>(symtab, layout);
+ this->sized_finalize<64>(symtab, layout, is_dot_available, dot_has_value,
+ dot_value);
#else
gold_unreachable();
#endif
@@ -943,10 +968,56 @@ Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
template<int size>
void
-Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout)
-{
+Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
+ bool is_dot_available, bool dot_has_value,
+ uint64_t dot_value)
+{
+ bool dummy;
+ uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout,
+ is_dot_available,
+ dot_has_value, dot_value,
+ &dummy);
Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
- ssym->set_value(this->val_->eval(symtab, layout));
+ ssym->set_value(final_val);
+}
+
+// Set the symbol value if the expression yields an absolute value.
+
+void
+Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
+ bool is_dot_available, bool dot_has_value,
+ uint64_t dot_value)
+{
+ if (this->sym_ == NULL)
+ return;
+
+ bool is_absolute;
+ uint64_t val = this->val_->eval_maybe_dot(symtab, layout, is_dot_available,
+ dot_has_value, dot_value,
+ &is_absolute);
+ if (!is_absolute)
+ return;
+
+ if (parameters->get_size() == 32)
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
+ Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(this->sym_);
+ ssym->set_value(val);
+#else
+ gold_unreachable();
+#endif
+ }
+ else if (parameters->get_size() == 64)
+ {
+#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
+ Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(this->sym_);
+ ssym->set_value(val);
+#else
+ gold_unreachable();
+#endif
+ }
+ else
+ gold_unreachable();
}
// Print for debugging.
@@ -1006,14 +1077,26 @@ Script_options::add_symbol_assignment(const char* name, size_t length,
Expression* value, bool provide,
bool hidden)
{
- if (this->script_sections_.in_sections_clause())
- this->script_sections_.add_symbol_assignment(name, length, value,
- provide, hidden);
+ if (length != 1 || name[0] != '.')
+ {
+ if (this->script_sections_.in_sections_clause())
+ this->script_sections_.add_symbol_assignment(name, length, value,
+ provide, hidden);
+ else
+ {
+ Symbol_assignment* p = new Symbol_assignment(name, length, value,
+ provide, hidden);
+ this->symbol_assignments_.push_back(p);
+ }
+ }
else
{
- Symbol_assignment* p = new Symbol_assignment(name, length, value,
- provide, hidden);
- this->symbol_assignments_.push_back(p);
+ if (provide || hidden)
+ gold_error(_("invalid use of PROVIDE for dot symbol"));
+ if (!this->script_sections_.in_sections_clause())
+ gold_error(_("invalid assignment to dot outside of SECTIONS"));
+ else
+ this->script_sections_.add_dot_assignment(value);
}
}
@@ -1041,9 +1124,10 @@ Script_options::add_symbols_to_table(Symbol_table* symtab)
p != this->symbol_assignments_.end();
++p)
(*p)->add_to_table(symtab);
+ this->script_sections_.add_symbols_to_table(symtab);
}
-// Finalize symbol values.
+// Finalize symbol values. Also check assertions.
void
Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
@@ -1052,6 +1136,29 @@ Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
p != this->symbol_assignments_.end();
++p)
(*p)->finalize(symtab, layout);
+
+ for (Assertions::iterator p = this->assertions_.begin();
+ p != this->assertions_.end();
+ ++p)
+ (*p)->check(symtab, layout);
+
+ this->script_sections_.finalize_symbols(symtab, layout);
+}
+
+// Set section addresses. We set all the symbols which have absolute
+// values. Then we let the SECTIONS clause do its thing. This
+// returns the segment which holds the file header and segment
+// headers, if any.
+
+Output_segment*
+Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout)
+{
+ for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ (*p)->set_if_absolute(symtab, layout, false, false, 0);
+
+ return this->script_sections_.set_section_addresses(symtab, layout);
}
// This class holds data passed through the parser to the lexer and to
@@ -2279,8 +2386,13 @@ extern "C" String_sort_list_ptr
script_string_sort_list_add(String_sort_list_ptr pv,
const struct Wildcard_section* string_sort)
{
- pv->push_back(*string_sort);
- return pv;
+ if (pv == NULL)
+ return script_new_string_sort_list(string_sort);
+ else
+ {
+ pv->push_back(*string_sort);
+ return pv;
+ }
}
// Create a new list of strings.
diff --git a/gold/script.h b/gold/script.h
index 24bd5138f0..257b479dcd 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -46,6 +46,7 @@ class Input_argument;
class Input_objects;
class Input_group;
class Input_file;
+class Output_segment;
class Task_token;
class Workqueue;
struct Version_dependency_list;
@@ -65,10 +66,27 @@ class Expression
virtual ~Expression()
{ }
- // Return the value of the expression.
+ // Return the value of the expression which is not permitted to
+ // refer to the dot symbol.
uint64_t
eval(const Symbol_table*, const Layout*);
+ // Return the value of an expression which is permitted to refer to
+ // the dot symbol. This sets *IS_ABSOLUTE to indicate whether this
+ // is an absolute value; it will be false if a non-absolute symbol
+ // was referenced in the expression; this is used to detect invalid
+ // uses when setting a section address.
+ uint64_t
+ eval_with_dot(const Symbol_table*, const Layout*, bool dot_has_value,
+ uint64_t dot_value, bool* is_absolute);
+
+ // Return the value of an expression which may or may not be
+ // permitted to refer to the dot symbol, depending on
+ // is_dot_available.
+ uint64_t
+ eval_maybe_dot(const Symbol_table*, const Layout*, bool is_dot_available,
+ bool dot_has_value, uint64_t dot_value, bool* is_absolute);
+
// Print the expression to the FILE. This is for debugging.
virtual void
print(FILE*) const = 0;
@@ -181,17 +199,35 @@ class Symbol_assignment
add_to_table(Symbol_table*);
// Finalize the symbol value.
- void finalize(Symbol_table*, const Layout*);
+ void
+ finalize(Symbol_table*, const Layout*);
+
+ // Finalize the symbol value when it can refer to the dot symbol.
+ void
+ finalize_with_dot(Symbol_table*, const Layout*, bool dot_has_value,
+ uint64_t dot_value);
+
+ // Set the symbol value, but only if the value is absolute. This is
+ // used while processing a SECTIONS clause.
+ void
+ set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available,
+ bool dot_has_value, uint64_t dot_value);
// Print the assignment to the FILE. This is for debugging.
void
print(FILE*) const;
private:
+ // Shared by finalize and finalize_with_dot.
+ void
+ finalize_maybe_dot(Symbol_table*, const Layout*, bool is_dot_available,
+ bool dot_has_value, uint64_t dot_value);
+
// Sized version of finalize.
template<int size>
void
- sized_finalize(Symbol_table*, const Layout*);
+ sized_finalize(Symbol_table*, const Layout*, bool is_dot_available,
+ bool dot_has_value, uint64_t dot_value);
// Symbol name.
std::string name_;
@@ -274,7 +310,7 @@ class Script_options
void
add_symbols_to_table(Symbol_table*);
- // Finalize the symbol values.
+ // Finalize the symbol values. Also check assertions.
void
finalize_symbols(Symbol_table*, const Layout*);
@@ -290,6 +326,18 @@ class Script_options
script_sections()
{ return &this->script_sections_; }
+ // Whether we saw a SECTIONS clause.
+ bool
+ saw_sections_clause() const
+ { return this->script_sections_.saw_sections_clause(); }
+
+ // Set section addresses using a SECTIONS clause. Return the
+ // segment which should hold the file header and segment headers;
+ // this may return NULL, in which case the headers are not in a
+ // loadable segment.
+ Output_segment*
+ set_section_addresses(Symbol_table*, Layout*);
+
// Print the script to the FILE. This is for debugging.
void
print(FILE*) const;
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 78bfec5a61..288b966966 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -298,6 +298,25 @@ Symbol::final_value_is_known() const
return parameters->doing_static_link();
}
+// Return whether the symbol has an absolute value.
+
+bool
+Symbol::value_is_absolute() const
+{
+ switch (this->source_)
+ {
+ case FROM_OBJECT:
+ return this->u_.from_object.shndx == elfcpp::SHN_ABS;
+ case IN_OUTPUT_DATA:
+ case IN_OUTPUT_SEGMENT:
+ return false;
+ case CONSTANT:
+ return true;
+ default:
+ gold_unreachable();
+ }
+}
+
// Class Symbol_table.
Symbol_table::Symbol_table(unsigned int count,
@@ -1336,7 +1355,8 @@ Symbol_table::do_define_as_constant(
void
Symbol_table::define_symbols(const Layout* layout, int count,
- const Define_symbol_in_section* p)
+ const Define_symbol_in_section* p,
+ bool only_if_ref)
{
for (int i = 0; i < count; ++i, ++p)
{
@@ -1345,11 +1365,12 @@ Symbol_table::define_symbols(const Layout* layout, int count,
this->define_in_output_data(p->name, NULL, os, p->value,
p->size, p->type, p->binding,
p->visibility, p->nonvis,
- p->offset_is_from_end, p->only_if_ref);
+ p->offset_is_from_end,
+ only_if_ref || p->only_if_ref);
else
this->define_as_constant(p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
- p->only_if_ref);
+ only_if_ref || p->only_if_ref);
}
}
@@ -1357,7 +1378,8 @@ Symbol_table::define_symbols(const Layout* layout, int count,
void
Symbol_table::define_symbols(const Layout* layout, int count,
- const Define_symbol_in_segment* p)
+ const Define_symbol_in_segment* p,
+ bool only_if_ref)
{
for (int i = 0; i < count; ++i, ++p)
{
@@ -1368,11 +1390,12 @@ Symbol_table::define_symbols(const Layout* layout, int count,
this->define_in_output_segment(p->name, NULL, os, p->value,
p->size, p->type, p->binding,
p->visibility, p->nonvis,
- p->offset_base, p->only_if_ref);
+ p->offset_base,
+ only_if_ref || p->only_if_ref);
else
this->define_as_constant(p->name, NULL, 0, p->size, p->type,
p->binding, p->visibility, p->nonvis,
- p->only_if_ref);
+ only_if_ref || p->only_if_ref);
}
}
diff --git a/gold/symtab.h b/gold/symtab.h
index 73b0cb7ffb..b60256e90a 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -552,6 +552,10 @@ class Symbol
return true;
}
+ // Return whether this symbol currently has an absolute value.
+ bool
+ value_is_absolute() const;
+
// Return whether there should be a warning for references to this
// symbol.
bool
@@ -1053,13 +1057,17 @@ class Symbol_table
elfcpp::STB binding, elfcpp::STV visibility,
unsigned char nonvis, bool only_if_ref);
- // Define a set of symbols in output sections.
+ // Define a set of symbols in output sections. If ONLY_IF_REF is
+ // true, only define them if they are referenced.
void
- define_symbols(const Layout*, int count, const Define_symbol_in_section*);
+ define_symbols(const Layout*, int count, const Define_symbol_in_section*,
+ bool only_if_ref);
- // Define a set of symbols in output segments.
+ // Define a set of symbols in output segments. If ONLY_IF_REF is
+ // true, only defined them if they are referenced.
void
- define_symbols(const Layout*, int count, const Define_symbol_in_segment*);
+ define_symbols(const Layout*, int count, const Define_symbol_in_segment*,
+ bool only_if_ref);
// Define SYM using a COPY reloc. POSD is the Output_data where the
// symbol should be defined--typically a .dyn.bss section. VALUE is
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index e42b2b3897..43d2a66b82 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -527,6 +527,11 @@ script_test_1_SOURCES = script_test_1.cc
script_test_1_DEPENDENCIES = gcctestdir/ld script_test_1.t
script_test_1_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_1.t
+check_PROGRAMS += script_test_2
+script_test_2_SOURCES = script_test_2.cc script_test_2a.cc script_test_2b.cc
+script_test_2_DEPENDENCIES = gcctestdir/ld script_test_2.t
+script_test_2_LDFLAGS = -Bgcctestdir/ -Wl,-R,. -T $(srcdir)/script_test_2.t
+
if OBJDUMP_AND_CPPFILT
check_SCRIPTS += ver_matching_test.sh
check_DATA += ver_matching_test.stdout
diff --git a/gold/testsuite/script_test_2.cc b/gold/testsuite/script_test_2.cc
new file mode 100644
index 0000000000..24771aafcf
--- /dev/null
+++ b/gold/testsuite/script_test_2.cc
@@ -0,0 +1,69 @@
+// script_test_2.cc -- linker script test 2 for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+// A test of some uses of the SECTIONS clause. Look at
+// script_test_2.t to make sense of this test.
+
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <stdint.h>
+
+extern char start_test_area[];
+extern char start_test_area_1[];
+extern char start_data[];
+extern char end_data[];
+extern char start_fill[];
+extern char end_fill[];
+extern char end_test_area[];
+
+int
+main(int, char**)
+{
+ assert(reinterpret_cast<uintptr_t>(start_test_area) == 0x20000001);
+ assert(reinterpret_cast<uintptr_t>(start_test_area_1) == 0x20000010);
+
+ // We should see the string from script_test_2b.o next. The
+ // subalign should move it up to 0x20000020.
+ for (int i = 0; i < 16; ++i)
+ assert(start_test_area_1[i] == 0);
+ assert(strcmp(start_test_area_1 + 16, "test b") == 0);
+
+ // Next the string from script_test_2a.o, after the subalign.
+ for (int i = 16 + 7; i < 48; ++i)
+ assert(start_test_area_1[i] == 0);
+ assert(strcmp(start_test_area_1 + 48, "test a") == 0);
+
+ // Move four bytes forward to start_data.
+ assert(reinterpret_cast<uintptr_t>(start_test_area_1 + 48 + 7 + 4)
+ == reinterpret_cast<uintptr_t>(start_data));
+ assert(memcmp(start_data, "\1\2\0\4\0\0\0\010\0\0\0\0\0\0\0", 15) == 0
+ || memcmp(start_data, "\1\0\2\0\0\0\4\0\0\0\0\0\0\0\010", 15) == 0);
+ assert(end_data == start_data + 15);
+
+ // Check that FILL works as expected.
+ assert(start_fill == end_data);
+ assert(memcmp(start_fill, "\x12\x34\x56\x78\x12\x34\x56\0", 8) == 0);
+ assert(end_fill == start_fill + 8);
+
+ assert(end_test_area == end_fill);
+}
diff --git a/gold/testsuite/script_test_2.t b/gold/testsuite/script_test_2.t
new file mode 100644
index 0000000000..e02b7a9777
--- /dev/null
+++ b/gold/testsuite/script_test_2.t
@@ -0,0 +1,63 @@
+/* script_test_2.t -- linker script test 2 for gold
+
+ Copyright 2008 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <iant@google.com>.
+
+ This file is part of gold.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+SECTIONS
+{
+ /* With luck this will work everywhere. */
+ . = 0x10000000;
+
+ /* With luck this will be enough to get the program working. */
+ .text : { *(.text) }
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+
+ /* Now the real test. */
+ . = 0x20000001;
+ start_test_area = .;
+ .gold_test ALIGN(16) : SUBALIGN(32) {
+ start_test_area_1 = .;
+
+ /* No sections should wind up here, because of the EXCLUDE_FILE. */
+ *( EXCLUDE_FILE(script_test*) .gold_test)
+
+ /* This should match only script_test_2b.o. */
+ script_test_2b.o(.gold_test)
+
+ /* This should match the remaining sections. */
+ *(.gold_test)
+
+ . = . + 4;
+ start_data = .;
+ BYTE(1)
+ SHORT(2)
+ LONG(4)
+ QUAD(8)
+ end_data = .;
+
+ start_fill = .;
+ FILL(0x12345678);
+ . = . + 7;
+ BYTE(0)
+ end_fill = .;
+ }
+ end_test_area = .;
+}
diff --git a/gold/testsuite/script_test_2a.cc b/gold/testsuite/script_test_2a.cc
new file mode 100644
index 0000000000..f4a611cac7
--- /dev/null
+++ b/gold/testsuite/script_test_2a.cc
@@ -0,0 +1,24 @@
+// script_test_2a.cc -- linker script test 2, file 1 -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+char script_test_string_a[] __attribute__ ((section(".gold_test"))) =
+ "test a";
diff --git a/gold/testsuite/script_test_2b.cc b/gold/testsuite/script_test_2b.cc
new file mode 100644
index 0000000000..5b6100bfdd
--- /dev/null
+++ b/gold/testsuite/script_test_2b.cc
@@ -0,0 +1,24 @@
+// script_test_2a.cc -- linker script test 2, file 2 -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+char script_test_string_b[] __attribute__ ((section(".gold_test"))) =
+ "test b";
diff --git a/gold/yyscript.y b/gold/yyscript.y
index 33023dc52b..a0379063b5 100644
--- a/gold/yyscript.y
+++ b/gold/yyscript.y
@@ -371,7 +371,8 @@ opt_phdr:
| /* empty */
;
-/* The value to use to fill an output section. */
+/* The value to use to fill an output section. FIXME: This does not
+ handle a string of arbitrary length. */
opt_fill:
'=' exp
{ $$ = $2; }