[gold patch] PR gold/13023: Fix problem with assignments to dot in linker scripts

Cary Coutant ccoutant@google.com
Fri Oct 28 21:13:00 GMT 2011
PR 13023 complains about gold not handling assignments to dot
correctly. If an absolute value is assigned to dot within an output
section, the value should be treated as an offset relative to the
start of the section. This patch fixes that, and also fixes a related
problem where a dot-relative assignment to a symbol (e.g., "L0 = .")
would produce an absolute symbol rather than a symbol defined in that
section.

I've added a flag to eval_maybe_dot() so that it knows whether we're
assigning to the dot symbol in an output section, and adjusts absolute
values appropriately. I also had to pass in dot_section to
set_if_absolute() so that we can set the values for dot-relative
symbols during the set_section_addresses phase along with actual
absolute symbols.

I've updated script_test_2 to test this case, and also verified that
the test attached to the PR now works.

Tested on x86_64. OK to commit?

-cary


	PR gold/13023
	* expression.cc (Expression::eval_with_dot): Add
	is_section_dot_assignment parameter.
	(Expression::eval_maybe_dot): Likewise.  Adjust value when rhs is
	absolute and assigning to dot within a section.
	* script-sections.cc
	(Output_section_element_assignment::set_section_addresses): Pass
	dot_section to set_if_absolute.
	(Output_section_element_dot_assignment::finalize_symbols): Pass TRUE
	as is_section_dot_assignment flag to eval_with_dot.
	(Output_section_element_dot_assignment::set_section_addresses):
	Likewise.
	* script.cc (Symbol_assignment::set_if_absolute): Add dot_section
	parameter.  Also set value if relative to dot_section; set the
	symbol's output_section.
	* script.h (Expression::eval_with_dot): Add is_section_dot_assignment
	parameter.  Adjust all callers.
	(Expression::eval_maybe_dot): Likewise.
	(Symbol_assignment::set_if_absolute): Add dot_section parameter.
	Adjust all callers.
	* testsuite/script_test_2.t: Test assignment of an absolute value
	to dot within an output section element.
-------------- next part --------------
2011-10-28  Cary Coutant  <ccoutant@google.com>

	PR gold/13023
	* expression.cc (Expression::eval_with_dot): Add
	is_section_dot_assignment parameter.
	(Expression::eval_maybe_dot): Likewise.  Adjust value when rhs is
	absolute and assigning to dot within a section.
	* script-sections.cc
	(Output_section_element_assignment::set_section_addresses): Pass
	dot_section to set_if_absolute.
	(Output_section_element_dot_assignment::finalize_symbols): Pass TRUE
	as is_section_dot_assignment flag to eval_with_dot.
	(Output_section_element_dot_assignment::set_section_addresses):
	Likewise.
	* script.cc (Symbol_assignment::set_if_absolute): Add dot_section
	parameter.  Also set value if relative to dot_section; set the
	symbol's output_section.
	* script.h (Expression::eval_with_dot): Add is_section_dot_assignment
	parameter.  Adjust all callers.
	(Expression::eval_maybe_dot): Likewise.
	(Symbol_assignment::set_if_absolute): Add dot_section parameter.
	Adjust all callers.
	* testsuite/script_test_2.t: Test assignment of an absolute value
	to dot within an output section element.


commit 65ff8bb95ef1657037a19a7c7c71222b065694c7
Author: Cary Coutant <ccoutant@google.com>
Date:   Fri Oct 28 13:47:25 2011 -0700

    Fix assignment to dot in scripts (PR 13023).

diff --git a/gold/expression.cc b/gold/expression.cc
index e527b5e..b611a68 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -77,7 +77,7 @@ Expression::eval(const Symbol_table* symtab, const Layout* layout,
 		 bool check_assertions)
 {
   return this->eval_maybe_dot(symtab, layout, check_assertions,
-			      false, 0, NULL, NULL, NULL);
+			      false, 0, NULL, NULL, NULL, false);
 }
 
 // Evaluate an expression which may refer to the dot symbol.
@@ -87,11 +87,13 @@ Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
 			  bool check_assertions, uint64_t dot_value,
 			  Output_section* dot_section,
 			  Output_section** result_section_pointer,
-			  uint64_t* result_alignment_pointer)
+			  uint64_t* result_alignment_pointer,
+			  bool is_section_dot_assignment)
 {
   return this->eval_maybe_dot(symtab, layout, check_assertions, true,
 			      dot_value, dot_section, result_section_pointer,
-			      result_alignment_pointer);
+			      result_alignment_pointer,
+			      is_section_dot_assignment);
 }
 
 // Evaluate an expression which may or may not refer to the dot
@@ -102,7 +104,8 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
 			   bool check_assertions, bool is_dot_available,
 			   uint64_t dot_value, Output_section* dot_section,
 			   Output_section** result_section_pointer,
-			   uint64_t* result_alignment_pointer)
+			   uint64_t* result_alignment_pointer,
+			   bool is_section_dot_assignment)
 {
   Expression_eval_info eei;
   eei.symtab = symtab;
@@ -113,14 +116,24 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
   eei.dot_section = dot_section;
 
   // We assume the value is absolute, and only set this to a section
-  // if we find a section relative reference.
+  // if we find a section-relative reference.
   if (result_section_pointer != NULL)
     *result_section_pointer = NULL;
   eei.result_section_pointer = result_section_pointer;
 
   eei.result_alignment_pointer = result_alignment_pointer;
 
-  return this->value(&eei);
+  uint64_t val = this->value(&eei);
+
+  // If this is an assignment to dot within a section, and the value
+  // is absolute, treat it as a section-relative offset.
+  if (is_section_dot_assignment && *result_section_pointer == NULL)
+    {
+      gold_assert(dot_section != NULL);
+      val += dot_section->address();
+      *result_section_pointer = dot_section;
+    }
+  return val;
 }
 
 // A number.
@@ -257,7 +270,8 @@ class Unary_expression : public Expression
 				      eei->dot_value,
 				      eei->dot_section,
 				      arg_section_pointer,
-				      eei->result_alignment_pointer);
+				      eei->result_alignment_pointer,
+				      false);
   }
 
   void
@@ -336,7 +350,8 @@ class Binary_expression : public Expression
 				       eei->dot_value,
 				       eei->dot_section,
 				       section_pointer,
-				       alignment_pointer);
+				       alignment_pointer,
+				       false);
   }
 
   uint64_t
@@ -350,7 +365,8 @@ class Binary_expression : public Expression
 					eei->dot_value,
 					eei->dot_section,
 					section_pointer,
-					alignment_pointer);
+					alignment_pointer,
+					false);
   }
 
   void
@@ -500,7 +516,8 @@ class Trinary_expression : public Expression
 				       eei->dot_value,
 				       eei->dot_section,
 				       section_pointer,
-				       NULL);
+				       NULL,
+				       false);
   }
 
   uint64_t
@@ -514,7 +531,8 @@ class Trinary_expression : public Expression
 				       eei->dot_value,
 				       eei->dot_section,
 				       section_pointer,
-				       alignment_pointer);
+				       alignment_pointer,
+				       false);
   }
 
   uint64_t
@@ -528,7 +546,8 @@ class Trinary_expression : public Expression
 				       eei->dot_value,
 				       eei->dot_section,
 				       section_pointer,
-				       alignment_pointer);
+				       alignment_pointer,
+				       false);
   }
 
   void
diff --git a/gold/script-sections.cc b/gold/script-sections.cc
index eba6b9d..f90c0b3 100644
--- a/gold/script-sections.cc
+++ b/gold/script-sections.cc
@@ -680,7 +680,7 @@ class Sections_element_assignment : public Sections_element
   set_section_addresses(Symbol_table* symtab, Layout* layout,
 			uint64_t* dot_value, uint64_t*, uint64_t*)
   {
-    this->assignment_.set_if_absolute(symtab, layout, true, *dot_value);
+    this->assignment_.set_if_absolute(symtab, layout, true, *dot_value, NULL);
   }
 
   // Print for debugging.
@@ -714,7 +714,7 @@ class Sections_element_dot_assignment : public Sections_element
     // output section definition the dot symbol is always considered
     // to be absolute.
     *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value,
-					   NULL, NULL, NULL);
+					   NULL, NULL, NULL, false);
   }
 
   // Update the dot symbol while setting section addresses.
@@ -724,7 +724,7 @@ class Sections_element_dot_assignment : public Sections_element
 			uint64_t* load_address)
   {
     *dot_value = this->val_->eval_with_dot(symtab, layout, false, *dot_value,
-					   NULL, NULL, dot_alignment);
+					   NULL, NULL, dot_alignment, false);
     *load_address = *dot_value;
   }
 
@@ -866,9 +866,11 @@ class Output_section_element_assignment : public Output_section_element
   void
   set_section_addresses(Symbol_table* symtab, Layout* layout, Output_section*,
 			uint64_t, uint64_t* dot_value, uint64_t*,
-			Output_section**, std::string*, Input_section_list*)
+			Output_section** dot_section, std::string*,
+			Input_section_list*)
   {
-    this->assignment_.set_if_absolute(symtab, layout, true, *dot_value);
+    this->assignment_.set_if_absolute(symtab, layout, true, *dot_value,
+				      *dot_section);
   }
 
   // Print for debugging.
@@ -904,14 +906,16 @@ class Output_section_element_dot_assignment : public Output_section_element
 		   uint64_t* dot_value, Output_section** dot_section)
   {
     *dot_value = this->val_->eval_with_dot(symtab, layout, true, *dot_value,
-					   *dot_section, dot_section, NULL);
+					   *dot_section, dot_section, NULL,
+					   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, uint64_t*,
-			Output_section**, std::string*, Input_section_list*);
+			Output_section** dot_section, std::string*,
+			Input_section_list*);
 
   // Print for debugging.
   void
@@ -942,7 +946,8 @@ Output_section_element_dot_assignment::set_section_addresses(
 {
   uint64_t next_dot = this->val_->eval_with_dot(symtab, layout, false,
 						*dot_value, *dot_section,
-						dot_section, dot_alignment);
+						dot_section, dot_alignment,
+						true);
   if (next_dot < *dot_value)
     gold_error(_("dot may not move backward"));
   if (next_dot > *dot_value && output_section != NULL)
@@ -1043,7 +1048,8 @@ Output_data_expression::do_write_to_buffer(unsigned char* buf)
 {
   uint64_t val = this->val_->eval_with_dot(this->symtab_, this->layout_,
 					   true, this->dot_value_,
-					   this->dot_section_, NULL, NULL);
+					   this->dot_section_, NULL, NULL,
+					   false);
 
   if (parameters->target().is_big_endian())
     this->endian_write_to_buffer<true>(val, buf);
@@ -1193,7 +1199,7 @@ class Output_section_element_fill : public Output_section_element
     Output_section* fill_section;
     uint64_t fill_val = this->val_->eval_with_dot(symtab, layout, false,
 						  *dot_value, *dot_section,
-						  &fill_section, NULL);
+						  &fill_section, NULL, false);
     if (fill_section != NULL)
       gold_warning(_("fill value is not absolute"));
     // FIXME: The GNU linker supports fill values of arbitrary length.
@@ -2114,13 +2120,13 @@ Output_section_definition::finalize_symbols(Symbol_table* symtab,
 	{
 	  address = this->address_->eval_with_dot(symtab, layout, true,
 						  *dot_value, NULL,
-						  NULL, NULL);
+						  NULL, NULL, false);
 	}
       if (this->align_ != NULL)
 	{
 	  uint64_t align = this->align_->eval_with_dot(symtab, layout, true,
 						       *dot_value, NULL,
-						       NULL, NULL);
+						       NULL, NULL, false);
 	  address = align_address(address, align);
 	}
       *dot_value = address;
@@ -2309,7 +2315,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
   else
     address = this->address_->eval_with_dot(symtab, layout, true,
 					    *dot_value, NULL, NULL,
-					    dot_alignment);
+					    dot_alignment, false);
   uint64_t align;
   if (this->align_ == NULL)
     {
@@ -2322,7 +2328,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
     {
       Output_section* align_section;
       align = this->align_->eval_with_dot(symtab, layout, true, *dot_value,
-					  NULL, &align_section, NULL);
+					  NULL, &align_section, NULL, false);
       if (align_section != NULL)
 	gold_warning(_("alignment of section %s is not absolute"),
 		     this->name_.c_str());
@@ -2407,7 +2413,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
       laddr = this->load_address_->eval_with_dot(symtab, layout, true,
 						 *dot_value,
 						 this->output_section_,
-						 NULL, NULL);
+						 NULL, NULL, false);
       if (this->output_section_ != NULL)
         this->output_section_->set_load_address(laddr);
     }
@@ -2422,7 +2428,8 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
       Output_section* subalign_section;
       subalign = this->subalign_->eval_with_dot(symtab, layout, true,
 						*dot_value, NULL,
-						&subalign_section, NULL);
+						&subalign_section, NULL,
+						false);
       if (subalign_section != NULL)
 	gold_warning(_("subalign of section %s is not absolute"),
 		     this->name_.c_str());
@@ -2437,7 +2444,7 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
       uint64_t fill_val = this->fill_->eval_with_dot(symtab, layout, true,
 						     *dot_value,
 						     NULL, &fill_section,
-						     NULL);
+						     NULL, false);
       if (fill_section != NULL)
 	gold_warning(_("fill of section %s is not absolute"),
 		     this->name_.c_str());
diff --git a/gold/script.cc b/gold/script.cc
index 7df0c9e..b471cf9 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -983,18 +983,20 @@ Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
   uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, true,
 						  is_dot_available,
 						  dot_value, dot_section,
-						  &section, NULL);
+						  &section, NULL, false);
   Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
   ssym->set_value(final_val);
   if (section != NULL)
     ssym->set_output_section(section);
 }
 
-// Set the symbol value if the expression yields an absolute value.
+// Set the symbol value if the expression yields an absolute value or
+// a value relative to DOT_SECTION.
 
 void
 Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
-				   bool is_dot_available, uint64_t dot_value)
+				   bool is_dot_available, uint64_t dot_value,
+				   Output_section* dot_section)
 {
   if (this->sym_ == NULL)
     return;
@@ -1002,8 +1004,9 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
   Output_section* val_section;
   uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
 					    is_dot_available, dot_value,
-					    NULL, &val_section, NULL);
-  if (val_section != NULL)
+					    dot_section, &val_section, NULL,
+					    false);
+  if (val_section != NULL && val_section != dot_section)
     return;
 
   if (parameters->target().get_size() == 32)
@@ -1026,6 +1029,8 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
     }
   else
     gold_unreachable();
+  if (val_section != NULL)
+    this->sym_->set_output_section(val_section);
 }
 
 // Print for debugging.
@@ -1215,7 +1220,7 @@ 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, 0);
+    (*p)->set_if_absolute(symtab, layout, false, 0, NULL);
 
   return this->script_sections_.set_section_addresses(symtab, layout);
 }
diff --git a/gold/script.h b/gold/script.h
index 73079a4..f41f438 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -90,20 +90,28 @@ class Expression
   // the section address.  If RESULT_ALIGNMENT is not NULL, this sets
   // *RESULT_ALIGNMENT to the alignment of the value of that alignment
   // is larger than *RESULT_ALIGNMENT; this will only be non-zero if
-  // this is an ALIGN expression.
+  // this is an ALIGN expression.  If IS_SECTION_DOT_ASSIGMENT is true,
+  // we are evaluating an assignment to dot within an output section,
+  // and an absolute value should be interpreted as an offset within
+  // the section.
   uint64_t
   eval_with_dot(const Symbol_table*, const Layout*, bool check_assertions,
 		uint64_t dot_value, Output_section* dot_section,
-		Output_section** result_section, uint64_t* result_alignment);
+		Output_section** result_section, uint64_t* result_alignment,
+		bool is_section_dot_assignment);
 
   // Return the value of an expression which may or may not be
   // permitted to refer to the dot symbol, depending on
-  // is_dot_available.
+  // is_dot_available.  If IS_SECTION_DOT_ASSIGMENT is true,
+  // we are evaluating an assignment to dot within an output section,
+  // and an absolute value should be interpreted as an offset within
+  // the section.
   uint64_t
   eval_maybe_dot(const Symbol_table*, const Layout*, bool check_assertions,
 		 bool is_dot_available, uint64_t dot_value,
 		 Output_section* dot_section,
-		 Output_section** result_section, uint64_t* result_alignment);
+		 Output_section** result_section, uint64_t* result_alignment,
+		 bool is_section_dot_assignment);
 
   // Print the expression to the FILE.  This is for debugging.
   virtual void
@@ -339,12 +347,12 @@ class Symbol_assignment
   finalize_with_dot(Symbol_table*, const Layout*, uint64_t dot_value,
 		    Output_section* dot_section);
 
-  // Set the symbol value, but only if the value is absolute.  This is
-  // used while processing a SECTIONS clause.  We assume that dot is
-  // an absolute value here.  We do not check assertions.
+  // Set the symbol value, but only if the value is absolute or relative to
+  // DOT_SECTION.  This is used while processing a SECTIONS clause.
+  // We assume that dot is an absolute value here.  We do not check assertions.
   void
   set_if_absolute(Symbol_table*, const Layout*, bool is_dot_available,
-		  uint64_t dot_value);
+		  uint64_t dot_value, Output_section* dot_section);
 
   const std::string&
   name() const
diff --git a/gold/testsuite/script_test_2.t b/gold/testsuite/script_test_2.t
index 73d39df..6a0188f 100644
--- a/gold/testsuite/script_test_2.t
+++ b/gold/testsuite/script_test_2.t
@@ -49,7 +49,7 @@ SECTIONS
     /* This should match the remaining sections.  */
     *(.gold_test)
 
-    . = . + 4;
+    . = 60;
     start_data = .;
     BYTE(1)
     SHORT(2)


More information about the Binutils mailing list