Fix internal error in gold when script uses section address in assignment.
authorCary Coutant <ccoutant@gmail.com>
Wed, 26 Aug 2015 00:41:19 +0000 (17:41 -0700)
committerCary Coutant <ccoutant@gmail.com>
Wed, 26 Aug 2015 01:11:19 +0000 (18:11 -0700)
When processing assignment expressions in a linker script, gold processes
absolute assignments early, but when one of those assignments involves the
address of a section that has not yet been finalized, we get an internal
error in address. This patch fixes the problem by gracefully returning
from expression evaluation even if the address is not yet valid, and
deferring the assignment in such a case.

gold/
PR gold/14746
* expression.cc (Expression::Expression_eval_info): Add
is_valid_pointer field.
(Expression::eval_maybe_dot): Add is_valid_pointer parameter.
Adjust all callers.
(Addr_expression::value_from_output_section): Check whether address
is valid.
* script.cc (Symbol_assignment::set_if_absolute): Defer assignment
if evaluation failed due to address that is not yet valid.
* script.h: (Expression::eval_maybe_dot): Add is_valid_pointer
parameter.

gold/ChangeLog
gold/expression.cc
gold/script.cc
gold/script.h

index 5190e7e0d1b0610c06e24c9a57af68561f597eee..ebed52b2ee0bbaa9c7bda54439735b0a3a20835c 100644 (file)
@@ -1,3 +1,17 @@
+2015-08-25  Cary Coutant  <ccoutant@gmail.com>
+
+       PR gold/14746
+       * expression.cc (Expression::Expression_eval_info): Add
+       is_valid_pointer field.
+       (Expression::eval_maybe_dot): Add is_valid_pointer parameter.
+       Adjust all callers.
+       (Addr_expression::value_from_output_section): Check whether address
+       is valid.
+       * script.cc (Symbol_assignment::set_if_absolute): Defer assignment
+       if evaluation failed due to address that is not yet valid.
+       * script.h: (Expression::eval_maybe_dot): Add is_valid_pointer
+       parameter.
+
 2015-08-25  Cary Coutant  <ccoutant@gmail.com>
 
        PR gold/18866
index a64fa42302f65d76776e50c59ca49f13425e7c21..484a49341dc066ffb78560b68b3208efe13087f4 100644 (file)
@@ -74,6 +74,10 @@ struct Expression::Expression_eval_info
   elfcpp::STV* vis_pointer;
   // Pointer to where the rest of the symbol's st_other field should be stored.
   unsigned char* nonvis_pointer;
+  // Whether the value is valid.  In Symbol_assignment::set_if_absolute, we
+  // may be trying to evaluate the address of a section whose address is not
+  // yet finalized, and we need to fail the evaluation gracefully.
+  bool *is_valid_pointer;
 };
 
 // Evaluate an expression.
@@ -83,7 +87,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, NULL, NULL, NULL, false);
+                             NULL, NULL, NULL, NULL, NULL, NULL, false, NULL);
 }
 
 // Evaluate an expression which may refer to the dot symbol.
@@ -99,7 +103,7 @@ Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
   return this->eval_maybe_dot(symtab, layout, check_assertions, true,
                              dot_value, dot_section, result_section_pointer,
                              result_alignment_pointer, NULL, NULL, NULL,
-                             is_section_dot_assignment);
+                             is_section_dot_assignment, NULL);
 }
 
 // Evaluate an expression which may or may not refer to the dot
@@ -114,7 +118,8 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
                           elfcpp::STT* type_pointer,
                           elfcpp::STV* vis_pointer,
                           unsigned char* nonvis_pointer,
-                          bool is_section_dot_assignment)
+                          bool is_section_dot_assignment,
+                          bool* is_valid_pointer)
 {
   Expression_eval_info eei;
   eei.symtab = symtab;
@@ -138,8 +143,18 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
 
   eei.result_alignment_pointer = result_alignment_pointer;
 
+  // Assume the value is valid until we try to evaluate an expression
+  // that can't be evaluated yet.
+  bool is_valid = true;
+  eei.is_valid_pointer = &is_valid;
+
   uint64_t val = this->value(&eei);
 
+  if (is_valid_pointer != NULL)
+    *is_valid_pointer = is_valid;
+  else
+    gold_assert(is_valid);
+
   // 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)
@@ -295,7 +310,8 @@ class Unary_expression : public Expression
                                      NULL,
                                      NULL,
                                      NULL,
-                                     false);
+                                     false,
+                                     eei->is_valid_pointer);
   }
 
   void
@@ -378,7 +394,8 @@ class Binary_expression : public Expression
                                       NULL,
                                       NULL,
                                       NULL,
-                                      false);
+                                      false,
+                                      eei->is_valid_pointer);
   }
 
   uint64_t
@@ -396,7 +413,8 @@ class Binary_expression : public Expression
                                        NULL,
                                        NULL,
                                        NULL,
-                                       false);
+                                       false,
+                                       eei->is_valid_pointer);
   }
 
   void
@@ -550,7 +568,8 @@ class Trinary_expression : public Expression
                                       NULL,
                                       NULL,
                                       NULL,
-                                      false);
+                                      false,
+                                      eei->is_valid_pointer);
   }
 
   uint64_t
@@ -568,7 +587,8 @@ class Trinary_expression : public Expression
                                       NULL,
                                       NULL,
                                       NULL,
-                                      false);
+                                      false,
+                                      eei->is_valid_pointer);
   }
 
   uint64_t
@@ -586,7 +606,8 @@ class Trinary_expression : public Expression
                                       NULL,
                                       NULL,
                                       NULL,
-                                      false);
+                                      false,
+                                      eei->is_valid_pointer);
   }
 
   void
@@ -945,7 +966,10 @@ class Addr_expression : public Section_expression
   {
     if (eei->result_section_pointer != NULL)
       *eei->result_section_pointer = os;
-    return os->address();
+    if (os->is_address_valid())
+      return os->address();
+    *eei->is_valid_pointer = false;
+    return 0;
   }
 
   uint64_t
index 56f126c738a047f6e0c2e0d2c9fb030c3bcc4b1f..cfa3116e18a48b59eeb783f771de4dd5707887d2 100644 (file)
@@ -987,7 +987,7 @@ Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
                                                  is_dot_available,
                                                  dot_value, dot_section,
                                                  &section, NULL, &type,
-                                                 &vis, &nonvis, false);
+                                                 &vis, &nonvis, false, NULL);
   Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
   ssym->set_value(final_val);
   ssym->set_type(type);
@@ -1009,11 +1009,12 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
     return;
 
   Output_section* val_section;
+  bool is_valid;
   uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
                                            is_dot_available, dot_value,
                                            dot_section, &val_section, NULL,
-                                           NULL, NULL, NULL, false);
-  if (val_section != NULL && val_section != dot_section)
+                                           NULL, NULL, NULL, false, &is_valid);
+  if (!is_valid || (val_section != NULL && val_section != dot_section))
     return;
 
   if (parameters->target().get_size() == 32)
index 1731985d83ed267d9eda70e2e35a0894b78f0d24..739baf16ed0e8bacedfddedf59492280bc34e631 100644 (file)
@@ -113,7 +113,7 @@ class Expression
                 Output_section* dot_section,
                 Output_section** result_section, uint64_t* result_alignment,
                 elfcpp::STT* type, elfcpp::STV* vis, unsigned char* nonvis,
-                bool is_section_dot_assignment);
+                bool is_section_dot_assignment, bool* is_valid_pointer);
 
   // Print the expression to the FILE.  This is for debugging.
   virtual void