From 8f2eb564ddf8002e343bd917a1f1e62f6412e862 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 29 Feb 2008 00:04:06 +0000 Subject: [PATCH] Permit scripts to refer to the addresses of output sections which were not created. --- gold/expression.cc | 49 ++++++++++++++++++--- gold/script-sections.cc | 97 ++++++++++++++++++++++++++++++++++++++++- gold/script-sections.h | 10 +++++ gold/script.h | 4 ++ 4 files changed, 153 insertions(+), 7 deletions(-) diff --git a/gold/expression.cc b/gold/expression.cc index 28d385b88d6..25f3ac33936 100644 --- a/gold/expression.cc +++ b/gold/expression.cc @@ -645,6 +645,11 @@ class Section_expression : public Expression value_from_output_section(const Expression_eval_info*, Output_section*) = 0; + // The child class must implement this. + virtual uint64_t + value_from_script_output_section(uint64_t address, uint64_t load_address, + uint64_t addralign, uint64_t size) = 0; + // The child class must implement this. virtual const char* function_name() const = 0; @@ -658,14 +663,28 @@ Section_expression::value(const Expression_eval_info* eei) { const char* section_name = this->section_name_.c_str(); Output_section* os = eei->layout->find_output_section(section_name); - if (os == NULL) + if (os != NULL) + return this->value_from_output_section(eei, os); + + uint64_t address; + uint64_t load_address; + uint64_t addralign; + uint64_t size; + const Script_options* ss = eei->layout->script_options(); + if (ss->saw_sections_clause()) { - gold_error("%s called on nonexistent output section '%s'", - this->function_name(), section_name); - return 0; + if (ss->script_sections()->get_output_section_info(section_name, + &address, + &load_address, + &addralign, + &size)) + return this->value_from_script_output_section(address, load_address, + addralign, size); } - return this->value_from_output_section(eei, os); + gold_error("%s called on nonexistent output section '%s'", + this->function_name(), section_name); + return 0; } // ABSOLUTE function. @@ -792,6 +811,11 @@ class Addr_expression : public Section_expression return os->address(); } + uint64_t + value_from_script_output_section(uint64_t address, uint64_t, uint64_t, + uint64_t) + { return address; } + const char* function_name() const { return "ADDR"; } @@ -818,6 +842,11 @@ class Alignof_expression : public Section_expression Output_section* os) { return os->addralign(); } + uint64_t + value_from_script_output_section(uint64_t, uint64_t, uint64_t addralign, + uint64_t) + { return addralign; } + const char* function_name() const { return "ALIGNOF"; } @@ -988,6 +1017,11 @@ class Loadaddr_expression : public Section_expression } } + uint64_t + value_from_script_output_section(uint64_t, uint64_t load_address, uint64_t, + uint64_t) + { return load_address; } + const char* function_name() const { return "LOADADDR"; } @@ -1020,6 +1054,11 @@ class Sizeof_expression : public Section_expression return os->current_data_size(); } + uint64_t + value_from_script_output_section(uint64_t, uint64_t, uint64_t, + uint64_t size) + { return size; } + const char* function_name() const { return "SIZEOF"; } diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 39aa9bd03db..340bf8936fd 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -112,6 +112,17 @@ class Sections_element allocate_to_segment(String_list**) { return NULL; } + // Look for an output section by name and return the address, the + // load address, the alignment, and the size. This is used when an + // expression refers to an output section which was not actually + // created. This returns true if the section was found, false + // otherwise. The only real definition is for + // Output_section_definition. + virtual bool + get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*, + uint64_t*) const + { return false; } + // Print the element for debugging purposes. virtual void print(FILE* f) const = 0; @@ -1259,6 +1270,15 @@ class Output_section_definition : public Sections_element Output_section* allocate_to_segment(String_list** phdrs_list); + // Look for an output section by name and return the address, the + // load address, the alignment, and the size. This is used when an + // expression refers to an output section which was not actually + // created. This returns true if the section was found, false + // otherwise. + bool + get_output_section_info(const char*, uint64_t*, uint64_t*, uint64_t*, + uint64_t*) const; + // Print the contents to the FILE. This is for debugging. void print(FILE*) const; @@ -1288,6 +1308,12 @@ class Output_section_definition : public Sections_element // The Output_section created for this definition. This will be // NULL if none was created. Output_section* output_section_; + // The address after it has been evaluated. + uint64_t evaluated_address_; + // The load address after it has been evaluated. + uint64_t evaluated_load_address_; + // The alignment after it has been evaluated. + uint64_t evaluated_addralign_; }; // Constructor. @@ -1648,13 +1674,20 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, && (this->output_section_->flags() & elfcpp::SHF_ALLOC) != 0) this->output_section_->set_address(address); - if (this->load_address_ != NULL && this->output_section_ != NULL) + this->evaluated_address_ = address; + this->evaluated_addralign_ = align; + + if (this->load_address_ == NULL) + this->evaluated_load_address_ = address; + else { Output_section* dummy; uint64_t load_address = this->load_address_->eval_with_dot(symtab, layout, true, *dot_value, this->output_section_, &dummy); - this->output_section_->set_load_address(load_address); + if (this->output_section_ != NULL) + this->output_section_->set_load_address(load_address); + this->evaluated_load_address_ = load_address; } uint64_t subalign; @@ -1818,6 +1851,43 @@ Output_section_definition::allocate_to_segment(String_list** phdrs_list) return this->output_section_; } +// Look for an output section by name and return the address, the load +// address, the alignment, and the size. This is used when an +// expression refers to an output section which was not actually +// created. This returns true if the section was found, false +// otherwise. + +bool +Output_section_definition::get_output_section_info(const char* name, + uint64_t* address, + uint64_t* load_address, + uint64_t* addralign, + uint64_t* size) const +{ + if (this->name_ != name) + return false; + + if (this->output_section_ != NULL) + { + *address = this->output_section_->address(); + if (this->output_section_->has_load_address()) + *load_address = this->output_section_->load_address(); + else + *load_address = *address; + *addralign = this->output_section_->addralign(); + *size = this->output_section_->current_data_size(); + } + else + { + *address = this->evaluated_address_; + *load_address = this->evaluated_load_address_; + *addralign = this->evaluated_addralign_; + *size = 0; + } + + return true; +} + // Print for debugging. void @@ -2971,6 +3041,29 @@ Script_sections::put_headers_in_phdrs(Output_data* file_header, } } +// Look for an output section by name and return the address, the load +// address, the alignment, and the size. This is used when an +// expression refers to an output section which was not actually +// created. This returns true if the section was found, false +// otherwise. + +bool +Script_sections::get_output_section_info(const char* name, uint64_t* address, + uint64_t* load_address, + uint64_t* addralign, + uint64_t* size) const +{ + if (!this->saw_sections_clause_) + return false; + for (Sections_elements::const_iterator p = this->sections_elements_->begin(); + p != this->sections_elements_->end(); + ++p) + if ((*p)->get_output_section_info(name, address, load_address, addralign, + size)) + return true; + return false; +} + // Print the SECTIONS clause to F for debugging. void diff --git a/gold/script-sections.h b/gold/script-sections.h index 9043dfdda56..73bf33f42bb 100644 --- a/gold/script-sections.h +++ b/gold/script-sections.h @@ -162,6 +162,16 @@ class Script_sections void put_headers_in_phdrs(Output_data* file_header, Output_data* segment_headers); + // Look for an output section by name and return the address, the + // load address, the alignment, and the size. This is used when an + // expression refers to an output section which was not actually + // created. This returns true if the section was found, false + // otherwise. + bool + get_output_section_info(const char* name, uint64_t* address, + uint64_t* load_address, uint64_t* addralign, + uint64_t* size) const; + // Print the contents to the FILE. This is for debugging. void print(FILE*) const; diff --git a/gold/script.h b/gold/script.h index ea19cfa617a..26abd463ac4 100644 --- a/gold/script.h +++ b/gold/script.h @@ -338,6 +338,10 @@ class Script_options script_sections() { return &this->script_sections_; } + const Script_sections* + script_sections() const + { return &this->script_sections_; } + // Whether we saw a SECTIONS clause. bool saw_sections_clause() const -- 2.30.2