aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-02-04 06:45:50 +0000
committerIan Lance Taylor <iant@google.com>2008-02-04 06:45:50 +0000
commit3802b2dd6b937e2904b6e2de087e224437eab493 (patch)
treeac185197a2a44c92c3785020c2ce1e389f2b0287
parentae7d22a6f2f59251b85ef5655b800f2dfe2dfbee (diff)
downloadgdb-3802b2dd6b937e2904b6e2de087e224437eab493.zip
gdb-3802b2dd6b937e2904b6e2de087e224437eab493.tar.gz
gdb-3802b2dd6b937e2904b6e2de087e224437eab493.tar.bz2
Implement SIZEOF_HEADERS, section constraints, other minor linker
script items.
-rw-r--r--gold/expression.cc170
-rw-r--r--gold/layout.cc143
-rw-r--r--gold/layout.h4
-rw-r--r--gold/output.cc11
-rw-r--r--gold/script-c.h22
-rw-r--r--gold/script-sections.cc208
-rw-r--r--gold/script-sections.h5
-rw-r--r--gold/script.cc23
-rw-r--r--gold/yyscript.y29
9 files changed, 501 insertions, 114 deletions
diff --git a/gold/expression.cc b/gold/expression.cc
index e8fd9fd..d57b45c 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -24,6 +24,7 @@
#include <string>
+#include "elfcpp.h"
#include "parameters.h"
#include "symtab.h"
#include "layout.h"
@@ -632,78 +633,197 @@ script_exp_function_addr(const char* section_name, size_t section_name_len)
return new Addr_expression(section_name, section_name_len);
}
-// Functions.
+// CONSTANT. It would be nice if we could simply evaluate this
+// immediately and return an Integer_expression, but unfortunately we
+// don't know the target.
+
+class Constant_expression : public Expression
+{
+ public:
+ Constant_expression(const char* name, size_t length);
+
+ uint64_t
+ value(const Expression_eval_info*);
+
+ void
+ print(FILE* f) const;
+
+ private:
+ enum Constant_function
+ {
+ CONSTANT_MAXPAGESIZE,
+ CONSTANT_COMMONPAGESIZE
+ };
+ Constant_function function_;
+};
+
+Constant_expression::Constant_expression(const char* name, size_t length)
+{
+ if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0)
+ this->function_ = CONSTANT_MAXPAGESIZE;
+ else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0)
+ this->function_ = CONSTANT_COMMONPAGESIZE;
+ else
+ {
+ std::string s(name, length);
+ gold_error(_("unknown constant %s"), s.c_str());
+ this->function_ = CONSTANT_MAXPAGESIZE;
+ }
+}
+
+uint64_t
+Constant_expression::value(const Expression_eval_info*)
+{
+ switch (this->function_)
+ {
+ case CONSTANT_MAXPAGESIZE:
+ return parameters->target()->abi_pagesize();
+ case CONSTANT_COMMONPAGESIZE:
+ return parameters->target()->common_pagesize();
+ default:
+ gold_unreachable();
+ }
+}
+
+void
+Constant_expression::print(FILE* f) const
+{
+ const char* name;
+ switch (this->function_)
+ {
+ case CONSTANT_MAXPAGESIZE:
+ name = "MAXPAGESIZE";
+ break;
+ case CONSTANT_COMMONPAGESIZE:
+ name = "COMMONPAGESIZE";
+ break;
+ default:
+ gold_unreachable();
+ }
+ fprintf(f, "CONSTANT(%s)", name);
+}
+
extern "C" Expression*
-script_exp_function_defined(const char*, size_t)
+script_exp_function_constant(const char* name, size_t length)
{
- gold_fatal(_("DEFINED not implemented"));
+ return new Constant_expression(name, length);
}
+// DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall
+// back to the general case.
+
extern "C" Expression*
-script_exp_function_sizeof_headers()
+script_exp_function_data_segment_align(Expression* left, Expression*)
{
- gold_fatal(_("SIZEOF_HEADERS not implemented"));
+ Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left);
+ Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1));
+ Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1),
+ e2);
+ return script_exp_binary_add(e1, e3);
}
+// DATA_SEGMENT_RELRO. FIXME: This is not implemented.
+
extern "C" Expression*
-script_exp_function_alignof(const char*, size_t)
+script_exp_function_data_segment_relro_end(Expression*, Expression* right)
{
- gold_fatal(_("ALIGNOF not implemented"));
+ return right;
}
+// DATA_SEGMENT_END. FIXME: This is not implemented.
+
extern "C" Expression*
-script_exp_function_sizeof(const char*, size_t)
+script_exp_function_data_segment_end(Expression* val)
{
- gold_fatal(_("SIZEOF not implemented"));
+ return val;
+}
+
+// SIZEOF_HEADERS.
+
+class Sizeof_headers_expression : public Expression
+{
+ public:
+ Sizeof_headers_expression()
+ { }
+
+ uint64_t
+ value(const Expression_eval_info*);
+
+ void
+ print(FILE* f) const
+ { fprintf(f, "SIZEOF_HEADERS"); }
+};
+
+uint64_t
+Sizeof_headers_expression::value(const Expression_eval_info* eei)
+{
+ unsigned int ehdr_size;
+ unsigned int phdr_size;
+ if (parameters->get_size() == 32)
+ {
+ ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
+ phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+ }
+ else if (parameters->get_size() == 64)
+ {
+ ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+ phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+ }
+ else
+ gold_unreachable();
+
+ return ehdr_size + phdr_size * eei->layout->expected_segment_count();
}
extern "C" Expression*
-script_exp_function_loadaddr(const char*, size_t)
+script_exp_function_sizeof_headers()
{
- gold_fatal(_("LOADADDR not implemented"));
+ return new Sizeof_headers_expression();
}
+// Functions.
+
extern "C" Expression*
-script_exp_function_origin(const char*, size_t)
+script_exp_function_defined(const char*, size_t)
{
- gold_fatal(_("ORIGIN not implemented"));
+ gold_fatal(_("DEFINED not implemented"));
}
extern "C" Expression*
-script_exp_function_length(const char*, size_t)
+script_exp_function_alignof(const char*, size_t)
{
- gold_fatal(_("LENGTH not implemented"));
+ gold_fatal(_("ALIGNOF not implemented"));
}
extern "C" Expression*
-script_exp_function_constant(const char*, size_t)
+script_exp_function_sizeof(const char*, size_t)
{
- gold_fatal(_("CONSTANT not implemented"));
+ gold_fatal(_("SIZEOF not implemented"));
}
extern "C" Expression*
-script_exp_function_absolute(Expression*)
+script_exp_function_loadaddr(const char*, size_t)
{
- gold_fatal(_("ABSOLUTE not implemented"));
+ gold_fatal(_("LOADADDR not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_align(Expression*, Expression*)
+script_exp_function_origin(const char*, size_t)
{
- gold_fatal(_("DATA_SEGMENT_ALIGN not implemented"));
+ gold_fatal(_("ORIGIN not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_relro_end(Expression*, Expression*)
+script_exp_function_length(const char*, size_t)
{
- gold_fatal(_("DATA_SEGMENT_RELRO_END not implemented"));
+ gold_fatal(_("LENGTH not implemented"));
}
extern "C" Expression*
-script_exp_function_data_segment_end(Expression*)
+script_exp_function_absolute(Expression*)
{
- gold_fatal(_("DATA_SEGMENT_END not implemented"));
+ gold_fatal(_("ABSOLUTE not implemented"));
}
extern "C" Expression*
diff --git a/gold/layout.cc b/gold/layout.cc
index a0fcc49..1e597ac 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -397,9 +397,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
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);
+ Output_segment* hdr_oseg;
+ hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
+ elfcpp::PF_R);
hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
@@ -523,9 +523,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
if (p == this->segment_list_.end())
{
- Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
- seg_flags);
- this->segment_list_.push_back(oseg);
+ Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
+ seg_flags);
oseg->add_output_section(os, seg_flags);
}
@@ -549,9 +548,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
if (p == this->segment_list_.end())
{
- Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
- seg_flags);
- this->segment_list_.push_back(oseg);
+ Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
+ seg_flags);
oseg->add_output_section(os, seg_flags);
}
}
@@ -561,11 +559,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
if ((flags & elfcpp::SHF_TLS) != 0)
{
if (this->tls_segment_ == NULL)
- {
- this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
- seg_flags);
- this->segment_list_.push_back(this->tls_segment_);
- }
+ this->tls_segment_ = this->make_output_segment(elfcpp::PT_TLS,
+ seg_flags);
this->tls_segment_->add_output_section(os, seg_flags);
}
}
@@ -573,6 +568,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
return os;
}
+// Return the number of segments we expect to see.
+
+size_t
+Layout::expected_segment_count() const
+{
+ size_t ret = this->segment_list_.size();
+
+ // If we didn't see a SECTIONS clause in a linker script, we should
+ // already have the complete list of segments. Otherwise we ask the
+ // SECTIONS clause how many segments it expects, and add in the ones
+ // we already have (PT_GNU_STACK, PT_GNU_EH_FRAME, etc.)
+
+ if (!this->script_options_->saw_sections_clause())
+ return ret;
+ else
+ {
+ const Script_sections* ss = this->script_options_->script_sections();
+ return ret + ss->expected_segment_count(this);
+ }
+}
+
// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK
// is whether we saw a .note.GNU-stack section in the object file.
// GNU_STACK_FLAGS is the section flags. The flags give the
@@ -603,11 +619,11 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
if (parameters->doing_static_link())
return;
- const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL);
- this->dynamic_section_ = this->make_output_section(dynamic_name,
- elfcpp::SHT_DYNAMIC,
- (elfcpp::SHF_ALLOC
- | elfcpp::SHF_WRITE));
+ this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic",
+ elfcpp::SHT_DYNAMIC,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ false);
symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
@@ -684,8 +700,8 @@ Layout::find_first_load_seg()
return *p;
}
- Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
- this->segment_list_.push_back(load_seg);
+ Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD,
+ elfcpp::PF_R);
return load_seg;
}
@@ -734,11 +750,16 @@ 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->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 = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
+
// Create the dynamic symbol table, including the hash table.
Output_section* dynstr;
std::vector<Symbol*> dynamic_symbols;
@@ -775,16 +796,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
else
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);
- }
+ gold_assert(phdr_seg == NULL || load_seg != NULL);
// Lay out the segment headers.
Output_segment_headers* segment_headers;
@@ -988,8 +1000,7 @@ Layout::create_executable_stack_info(const Target* target)
int flags = elfcpp::PF_R | elfcpp::PF_W;
if (is_stack_executable)
flags |= elfcpp::PF_X;
- Output_segment* oseg = new Output_segment(elfcpp::PT_GNU_STACK, flags);
- this->segment_list_.push_back(oseg);
+ this->make_output_segment(elfcpp::PT_GNU_STACK, flags);
}
}
@@ -1591,10 +1602,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
// Create the dynamic symbol table section.
- const char* dynsym_name = this->namepool_.add(".dynsym", false, NULL);
- Output_section* dynsym = this->make_output_section(dynsym_name,
- elfcpp::SHT_DYNSYM,
- elfcpp::SHF_ALLOC);
+ Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
+ elfcpp::SHT_DYNSYM,
+ elfcpp::SHF_ALLOC,
+ false);
Output_section_data* odata = new Output_data_fixed_space(index * symsize,
align);
@@ -1612,10 +1623,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
// Create the dynamic string table section.
- const char* dynstr_name = this->namepool_.add(".dynstr", false, NULL);
- Output_section* dynstr = this->make_output_section(dynstr_name,
- elfcpp::SHT_STRTAB,
- elfcpp::SHF_ALLOC);
+ Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
+ elfcpp::SHT_STRTAB,
+ elfcpp::SHF_ALLOC,
+ false);
Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
dynstr->add_output_section_data(strdata);
@@ -1637,10 +1648,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount,
&phash, &hashlen);
- const char* hash_name = this->namepool_.add(".hash", false, NULL);
- Output_section* hashsec = this->make_output_section(hash_name,
- elfcpp::SHT_HASH,
- elfcpp::SHF_ALLOC);
+ Output_section* hashsec = this->choose_output_section(NULL, ".hash",
+ elfcpp::SHT_HASH,
+ elfcpp::SHF_ALLOC,
+ false);
Output_section_data* hashdata = new Output_data_const_buffer(phash,
hashlen,
@@ -1753,10 +1764,10 @@ Layout::sized_create_version_sections(
const Output_section* dynstr
ACCEPT_SIZE_ENDIAN)
{
- const char* vname = this->namepool_.add(".gnu.version", false, NULL);
- Output_section* vsec = this->make_output_section(vname,
- elfcpp::SHT_GNU_versym,
- elfcpp::SHF_ALLOC);
+ Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
+ elfcpp::SHT_GNU_versym,
+ elfcpp::SHF_ALLOC,
+ false);
unsigned char* vbuf;
unsigned int vsize;
@@ -1775,10 +1786,11 @@ Layout::sized_create_version_sections(
if (versions->any_defs())
{
- const char* vdname = this->namepool_.add(".gnu.version_d", false, NULL);
- Output_section *vdsec;
- vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
- elfcpp::SHF_ALLOC);
+ Output_section* vdsec;
+ vdsec= this->choose_output_section(NULL, ".gnu.version_d",
+ elfcpp::SHT_GNU_verdef,
+ elfcpp::SHF_ALLOC,
+ false);
unsigned char* vdbuf;
unsigned int vdsize;
@@ -1801,10 +1813,11 @@ Layout::sized_create_version_sections(
if (versions->any_needs())
{
- const char* vnname = this->namepool_.add(".gnu.version_r", false, NULL);
Output_section* vnsec;
- vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
- elfcpp::SHF_ALLOC);
+ vnsec = this->choose_output_section(NULL, ".gnu.version_r",
+ elfcpp::SHT_GNU_verneed,
+ elfcpp::SHF_ALLOC,
+ false);
unsigned char* vnbuf;
unsigned int vnsize;
@@ -1842,14 +1855,14 @@ Layout::create_interp(const Target* target)
Output_section_data* odata = new Output_data_const(interp, len, 1);
- const char* interp_name = this->namepool_.add(".interp", false, NULL);
- Output_section* osec = this->make_output_section(interp_name,
- elfcpp::SHT_PROGBITS,
- elfcpp::SHF_ALLOC);
+ Output_section* osec = this->choose_output_section(NULL, ".interp",
+ elfcpp::SHT_PROGBITS,
+ elfcpp::SHF_ALLOC,
+ false);
osec->add_output_section_data(odata);
- Output_segment* oseg = new Output_segment(elfcpp::PT_INTERP, elfcpp::PF_R);
- this->segment_list_.push_back(oseg);
+ Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
+ elfcpp::PF_R);
oseg->add_initial_output_section(osec, elfcpp::PF_R);
}
@@ -1859,9 +1872,9 @@ void
Layout::finish_dynamic_section(const Input_objects* input_objects,
const Symbol_table* symtab)
{
- Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
- elfcpp::PF_R | elfcpp::PF_W);
- this->segment_list_.push_back(oseg);
+ Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
+ (elfcpp::PF_R
+ | elfcpp::PF_W));
oseg->add_initial_output_section(this->dynamic_section_,
elfcpp::PF_R | elfcpp::PF_W);
diff --git a/gold/layout.h b/gold/layout.h
index ceacf5d..d7f5965 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -237,6 +237,10 @@ class Layout
find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
elfcpp::Elf_Word clear) const;
+ // Return the number of segments we expect to produce.
+ size_t
+ expected_segment_count() const;
+
// Set a flag to indicate that an object file uses the static TLS model.
void
set_has_static_tls()
diff --git a/gold/output.cc b/gold/output.cc
index c0db1af..8eb79fa 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -2324,21 +2324,22 @@ Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
p != pdl->end();
++p)
{
- off = align_address(off, (*p)->addralign());
-
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);
+ {
+ off = align_address(off, (*p)->addralign());
+ (*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);
+ gold_assert((*p)->address() >= addr + (off - startoff));
+ off += (*p)->address() - (addr + (off - startoff));
(*p)->set_file_offset(off);
(*p)->finalize_data_size();
}
diff --git a/gold/script-c.h b/gold/script-c.h
index 496e18b..26dc556 100644
--- a/gold/script-c.h
+++ b/gold/script-c.h
@@ -61,6 +61,21 @@ typedef Expression* Expression_ptr;
typedef void* Expression_ptr;
#endif
+/* A constraint for whether to use a particular output section
+ definition. */
+
+enum Section_constraint
+{
+ /* No constraint. */
+ CONSTRAINT_NONE,
+ /* Only if all input sections are read-only. */
+ CONSTRAINT_ONLY_IF_RO,
+ /* Only if at least input section is writable. */
+ CONSTRAINT_ONLY_IF_RW,
+ /* Special constraint. */
+ CONSTRAINT_SPECIAL
+};
+
/* The information we store for an output section header in the bison
parser. */
@@ -75,6 +90,8 @@ struct Parser_output_section_header
/* The input section alignment, from the SUBALIGN specifier. This
may be NULL. */
Expression_ptr subalign;
+ /* A constraint on this output section. */
+ enum Section_constraint constraint;
};
/* The information we store for an output section trailer in the bison
@@ -204,6 +221,11 @@ script_set_entry(void* closure, const char*, size_t);
extern void
script_parse_option(void* closure, const char*, size_t);
+/* Called by the bison parser to handle SEARCH_DIR. */
+
+extern void
+script_add_search_dir(void* closure, const char*, size_t);
+
/* Called by the bison parser to push the lexer into expression
mode. */
diff --git a/gold/script-sections.cc b/gold/script-sections.cc
index 2505170..6c8a7f5 100644
--- a/gold/script-sections.cc
+++ b/gold/script-sections.cc
@@ -82,6 +82,20 @@ class Sections_element
set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*)
{ }
+ // Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+ // this section is constrained, and the input sections do not match,
+ // return the constraint, and set *POSD.
+ virtual Section_constraint
+ check_constraint(Output_section_definition**)
+ { return CONSTRAINT_NONE; }
+
+ // See if this is the alternate output section for a constrained
+ // output section. If it is, transfer the Output_section and return
+ // true. Otherwise return false.
+ virtual bool
+ alternate_constraint(Output_section_definition*, Section_constraint)
+ { return false; }
+
// Print the element for debugging purposes.
virtual void
print(FILE* f) const = 0;
@@ -1146,6 +1160,18 @@ class Output_section_definition : public Sections_element
set_section_addresses(Symbol_table* symtab, Layout* layout,
bool* dot_has_value, uint64_t* dot_value);
+ // Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+ // this section is constrained, and the input sections do not match,
+ // return the constraint, and set *POSD.
+ Section_constraint
+ check_constraint(Output_section_definition** posd);
+
+ // See if this is the alternate output section for a constrained
+ // output section. If it is, transfer the Output_section and return
+ // true. Otherwise return false.
+ bool
+ alternate_constraint(Output_section_definition*, Section_constraint);
+
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
@@ -1163,6 +1189,8 @@ class Output_section_definition : public Sections_element
Expression* align_;
// The input section alignment. This may be NULL.
Expression* subalign_;
+ // The constraint, if any.
+ Section_constraint constraint_;
// The fill value. This may be NULL.
Expression* fill_;
// The list of elements defining the section.
@@ -1183,6 +1211,7 @@ Output_section_definition::Output_section_definition(
load_address_(header->load_address),
align_(header->align),
subalign_(header->subalign),
+ constraint_(header->constraint),
fill_(NULL),
elements_(),
output_section_(NULL)
@@ -1540,6 +1569,88 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
gold_assert(input_sections.empty());
}
+// Check a constraint (ONLY_IF_RO, etc.) on an output section. If
+// this section is constrained, and the input sections do not match,
+// return the constraint, and set *POSD.
+
+Section_constraint
+Output_section_definition::check_constraint(Output_section_definition** posd)
+{
+ switch (this->constraint_)
+ {
+ case CONSTRAINT_NONE:
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_ONLY_IF_RO:
+ if (this->output_section_ != NULL
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
+ {
+ *posd = this;
+ return CONSTRAINT_ONLY_IF_RO;
+ }
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_ONLY_IF_RW:
+ if (this->output_section_ != NULL
+ && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
+ {
+ *posd = this;
+ return CONSTRAINT_ONLY_IF_RW;
+ }
+ return CONSTRAINT_NONE;
+
+ case CONSTRAINT_SPECIAL:
+ if (this->output_section_ != NULL)
+ gold_error(_("SPECIAL constraints are not implemented"));
+ return CONSTRAINT_NONE;
+
+ default:
+ gold_unreachable();
+ }
+}
+
+// See if this is the alternate output section for a constrained
+// output section. If it is, transfer the Output_section and return
+// true. Otherwise return false.
+
+bool
+Output_section_definition::alternate_constraint(
+ Output_section_definition* posd,
+ Section_constraint constraint)
+{
+ if (this->name_ != posd->name_)
+ return false;
+
+ switch (constraint)
+ {
+ case CONSTRAINT_ONLY_IF_RO:
+ if (this->constraint_ != CONSTRAINT_ONLY_IF_RW)
+ return false;
+ break;
+
+ case CONSTRAINT_ONLY_IF_RW:
+ if (this->constraint_ != CONSTRAINT_ONLY_IF_RO)
+ return false;
+ break;
+
+ default:
+ gold_unreachable();
+ }
+
+ // We have found the alternate constraint. We just need to move
+ // over the Output_section. When constraints are used properly,
+ // THIS should not have an output_section pointer, as all the input
+ // sections should have matched the other definition.
+
+ if (this->output_section_ != NULL)
+ gold_error(_("mismatched definition for constrained sections"));
+
+ this->output_section_ = posd->output_section_;
+ posd->output_section_ = NULL;
+
+ return true;
+}
+
// Print for debugging.
void
@@ -1926,6 +2037,33 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
{
gold_assert(this->saw_sections_clause_);
+ // Implement ONLY_IF_RO/ONLY_IF_RW constraints. These are a pain
+ // for our representation.
+ for (Sections_elements::iterator p = this->sections_elements_->begin();
+ p != this->sections_elements_->end();
+ ++p)
+ {
+ Output_section_definition* posd;
+ Section_constraint failed_constraint = (*p)->check_constraint(&posd);
+ if (failed_constraint != CONSTRAINT_NONE)
+ {
+ Sections_elements::iterator q;
+ for (q = this->sections_elements_->begin();
+ q != this->sections_elements_->end();
+ ++q)
+ {
+ if (q != p)
+ {
+ if ((*q)->alternate_constraint(posd, failed_constraint))
+ break;
+ }
+ }
+
+ if (q == this->sections_elements_->end())
+ gold_error(_("no matching section constraint"));
+ }
+ }
+
bool dot_has_value = false;
uint64_t dot_value = 0;
for (Sections_elements::iterator p = this->sections_elements_->begin();
@@ -2118,10 +2256,15 @@ Script_sections::create_segments(Layout* layout)
else
gold_unreachable();
+ size_t sizeof_headers = file_header_size + segment_headers_size;
+
if (first_seg != NULL
- && ((first_seg->paddr() & (abi_pagesize - 1))
- >= file_header_size + segment_headers_size))
- return first_seg;
+ && (first_seg->paddr() & (abi_pagesize - 1)) >= sizeof_headers)
+ {
+ first_seg->set_addresses(first_seg->vaddr() - sizeof_headers,
+ first_seg->paddr() - sizeof_headers);
+ return first_seg;
+ }
Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD,
elfcpp::PF_R);
@@ -2132,16 +2275,13 @@ Script_sections::create_segments(Layout* layout)
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);
- }
+ // We want a segment with the same relationship between VMA and
+ // LMA, but with enough room for the headers, and aligned to
+ // load at the start of a page.
+ uint64_t hdr_lma = lma - sizeof_headers;
+ hdr_lma &= ~(abi_pagesize - 1);
+ if (lma >= hdr_lma && vma >= (lma - hdr_lma))
+ load_seg->set_addresses(vma - (lma - hdr_lma), hdr_lma);
else
{
// We could handle this case by create the file header
@@ -2216,6 +2356,48 @@ Script_sections::create_note_and_tls_segments(
}
}
+// Return the number of segments we expect to create based on the
+// SECTIONS clause. This is used to implement SIZEOF_HEADERS.
+
+size_t
+Script_sections::expected_segment_count(const Layout* layout) const
+{
+ Layout::Section_list sections;
+ layout->get_allocated_sections(&sections);
+
+ // We assume that we will need two PT_LOAD segments.
+ size_t ret = 2;
+
+ bool saw_note = false;
+ bool saw_tls = false;
+ for (Layout::Section_list::const_iterator p = sections.begin();
+ p != sections.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::SHT_NOTE)
+ {
+ // Assume that all note sections will fit into a single
+ // PT_NOTE segment.
+ if (!saw_note)
+ {
+ ++ret;
+ saw_note = true;
+ }
+ }
+ else if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
+ {
+ // There can only be one PT_TLS segment.
+ if (!saw_tls)
+ {
+ ++ret;
+ saw_tls = true;
+ }
+ }
+ }
+
+ return ret;
+}
+
// Print the SECTIONS clause to F for debugging.
void
diff --git a/gold/script-sections.h b/gold/script-sections.h
index 6ac4303..ec708bd 100644
--- a/gold/script-sections.h
+++ b/gold/script-sections.h
@@ -134,6 +134,11 @@ class Script_sections
Output_segment*
set_section_addresses(Symbol_table*, Layout*);
+ // Return the number of segments we expect to create based on the
+ // SECTIONS clause.
+ size_t
+ expected_segment_count(const Layout*) const;
+
// Print the contents to the FILE. This is for debugging.
void
print(FILE*) const;
diff --git a/gold/script.cc b/gold/script.cc
index 734349b..973c05c 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -393,7 +393,9 @@ Lex::can_start_name(char c, char c2)
return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
case '*': case '[':
- return this->mode_ == VERSION_SCRIPT;
+ return (this->mode_ == VERSION_SCRIPT
+ || (this->mode_ == LINKER_SCRIPT
+ && can_continue_name(&c2)));
default:
return false;
@@ -1607,6 +1609,7 @@ script_keyword_parsecodes[] =
{ "SHORT", SHORT },
{ "SIZEOF", SIZEOF },
{ "SIZEOF_HEADERS", SIZEOF_HEADERS },
+ { "SORT", SORT_BY_NAME },
{ "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
{ "SORT_BY_NAME", SORT_BY_NAME },
{ "SPECIAL", SPECIAL },
@@ -2145,6 +2148,24 @@ script_parse_option(void* closurev, const char* option, size_t length)
}
}
+// Called by the bison parser to handle SEARCH_DIR. This is handled
+// exactly like a -L option.
+
+extern "C" void
+script_add_search_dir(void* closurev, const char* option, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ if (closure->command_line() == NULL)
+ gold_warning(_("%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid"
+ " for scripts specified via -T/--script"),
+ closure->filename(), closure->lineno(), closure->charpos());
+ else
+ {
+ std::string s = "-L" + std::string(option, length);
+ script_parse_option(closurev, s.c_str(), s.size());
+ }
+}
+
/* Called by the bison parser to push the lexer into expression
mode. */
diff --git a/gold/yyscript.y b/gold/yyscript.y
index a037906..ad76709 100644
--- a/gold/yyscript.y
+++ b/gold/yyscript.y
@@ -60,6 +60,8 @@
struct Parser_output_section_header output_section_header;
/* An output section trailer. */
struct Parser_output_section_trailer output_section_trailer;
+ /* A section constraint. */
+ enum Section_constraint constraint;
/* A complete input section specification. */
struct Input_section_spec input_section_spec;
/* A list of wildcard specifications, with exclusions. */
@@ -195,6 +197,7 @@
%type <expr> opt_at opt_align opt_subalign opt_fill
%type <output_section_header> section_header
%type <output_section_trailer> section_trailer
+%type <constraint> opt_constraint
%type <integer> data_length
%type <input_section_spec> input_section_no_keep
%type <wildcard_sections> wildcard_sections
@@ -229,6 +232,8 @@ file_cmd:
{ script_end_group(closure); }
| OPTION '(' string ')'
{ script_parse_option(closure, $3.value, $3.length); }
+ | SEARCH_DIR '(' string ')'
+ { script_add_search_dir(closure, $3.value, $3.length); }
| SECTIONS '{'
{ script_start_sections(closure); }
sections_block '}'
@@ -239,6 +244,7 @@ file_cmd:
{ script_pop_lex_mode(closure); }
| file_or_sections_cmd
| ignore_cmd
+ | ';'
;
/* Top level commands which we ignore. The GNU linker uses these to
@@ -287,12 +293,14 @@ section_block_cmd:
section_header:
{ script_push_lex_into_expression_mode(closure); }
opt_address_and_section_type opt_at opt_align opt_subalign
+ { script_pop_lex_mode(closure); }
+ opt_constraint
{
$$.address = $2;
$$.load_address = $3;
$$.align = $4;
$$.subalign = $5;
- script_pop_lex_mode(closure);
+ $$.constraint = $7;
}
;
@@ -340,13 +348,23 @@ opt_subalign:
{ $$ = $3; }
;
+/* A section constraint. */
+opt_constraint:
+ /* empty */
+ { $$ = CONSTRAINT_NONE; }
+ | ONLY_IF_RO
+ { $$ = CONSTRAINT_ONLY_IF_RO; }
+ | ONLY_IF_RW
+ { $$ = CONSTRAINT_ONLY_IF_RW; }
+ | SPECIAL
+ { $$ = CONSTRAINT_SPECIAL; }
+ ;
+
/* The trailer of an output section in a SECTIONS block. */
section_trailer:
- { script_push_lex_into_expression_mode(closure); }
opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
{
- $$.fill = $5;
- script_pop_lex_mode(closure);
+ $$.fill = $4;
}
;
@@ -374,7 +392,7 @@ opt_phdr:
/* The value to use to fill an output section. FIXME: This does not
handle a string of arbitrary length. */
opt_fill:
- '=' exp
+ '=' parse_exp
{ $$ = $2; }
| /* empty */
{ $$ = NULL; }
@@ -405,6 +423,7 @@ section_cmd:
some ELF linker scripts use it although it does
nothing, we accept it and ignore it. */
}
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
| ';'
;