OSDN Git Service

* scripttempl/elf.sc: Only use DATA_SEGMENT_END() together with
[pf3gnuchains/pf3gnuchains4x.git] / ld / ldexp.c
index ec449fd..903374e 100644 (file)
@@ -1,6 +1,6 @@
 /* This module handles expression trees.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001
+   2001, 2002
    Free Software Foundation, Inc.
    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
 
@@ -39,6 +39,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "ldgram.h"
 #include "ldlang.h"
 #include "libiberty.h"
+#include "safe-ctype.h"
 
 static void exp_print_token PARAMS ((token_code_type code));
 static void make_abs PARAMS ((etree_value_type *ptr));
@@ -46,7 +47,7 @@ static etree_value_type new_abs PARAMS ((bfd_vma value));
 static void check PARAMS ((lang_output_section_statement_type *os,
                           const char *name, const char *op));
 static etree_value_type new_rel
-  PARAMS ((bfd_vma value, lang_output_section_statement_type *section));
+  PARAMS ((bfd_vma, char *, lang_output_section_statement_type *section));
 static etree_value_type new_rel_from_section
   PARAMS ((bfd_vma value, lang_output_section_statement_type *section));
 static etree_value_type fold_binary
@@ -64,6 +65,8 @@ static etree_value_type exp_fold_tree_no_dot
           lang_output_section_statement_type *current_section,
           lang_phase_type allocation_done));
 
+struct exp_data_seg exp_data_seg;
+
 static void
 exp_print_token (code)
      token_code_type code;
@@ -114,6 +117,8 @@ exp_print_token (code)
     { LOADADDR, "LOADADDR" },
     { MAX_K, "MAX_K" },
     { REL, "relocateable" },
+    { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
+    { DATA_SEGMENT_END, "DATA_SEGMENT_END" }
   };
   unsigned int idx;
 
@@ -172,9 +177,22 @@ exp_intop (value)
   etree_type *new = (etree_type *) stat_alloc (sizeof (new->value));
   new->type.node_code = INT;
   new->value.value = value;
+  new->value.str = NULL;
   new->type.node_class = etree_value;
   return new;
+}
 
+etree_type *
+exp_bigintop (value, str)
+     bfd_vma value;
+     char *str;
+{
+  etree_type *new = (etree_type *) stat_alloc (sizeof (new->value));
+  new->type.node_code = INT;
+  new->value.value = value;
+  new->value.str = str;
+  new->type.node_class = etree_value;
+  return new;
 }
 
 /* Build an expression representing an unnamed relocateable value.  */
@@ -193,13 +211,15 @@ exp_relop (section, value)
 }
 
 static etree_value_type
-new_rel (value, section)
+new_rel (value, str, section)
      bfd_vma value;
+     char *str;
      lang_output_section_statement_type *section;
 {
   etree_value_type new;
   new.valid_p = true;
   new.value = value;
+  new.str = str;
   new.section = section;
   return new;
 }
@@ -212,6 +232,7 @@ new_rel_from_section (value, section)
   etree_value_type new;
   new.valid_p = true;
   new.value = value;
+  new.str = NULL;
   new.section = section;
 
   new.value -= section->bfd_section->vma;
@@ -314,6 +335,33 @@ fold_binary (tree, current_section, allocation_done, dot, dotp)
                result = other;
              break;
 
+           case DATA_SEGMENT_ALIGN:
+             if (allocation_done != lang_first_phase_enum
+                 && current_section == abs_output_section
+                 && (exp_data_seg.phase == exp_dataseg_none
+                     || exp_data_seg.phase == exp_dataseg_adjust
+                     || allocation_done != lang_allocating_phase_enum))
+               {
+                 bfd_vma maxpage = result.value;
+
+                 result.value = ALIGN_N (dot, maxpage);
+                 if (exp_data_seg.phase != exp_dataseg_adjust)
+                   {
+                     result.value += dot & (maxpage - 1);
+                     if (allocation_done == lang_allocating_phase_enum)
+                       {
+                         exp_data_seg.phase = exp_dataseg_align_seen;
+                         exp_data_seg.base = result.value;
+                         exp_data_seg.pagesize = other.value;
+                       }
+                   }
+                 else if (other.value < maxpage)
+                   result.value += dot & (maxpage - other.value);
+               }
+             else
+               result.valid_p = false;
+             break;
+
            default:
              FAIL ();
            }
@@ -419,6 +467,7 @@ fold_name (tree, current_section, allocation_done, dot)
                         being linked with -R?  */
                      result = new_rel ((h->u.def.value
                                         + h->u.def.section->output_offset),
+                                       NULL,
                                        os);
                    }
                }
@@ -436,7 +485,7 @@ fold_name (tree, current_section, allocation_done, dot)
 
          os = lang_output_section_find (tree->name.name);
          check (os, tree->name.name, "ADDR");
-         result = new_rel (0, os);
+         result = new_rel (0, NULL, os);
        }
       else
        result = invalid ();
@@ -450,7 +499,7 @@ fold_name (tree, current_section, allocation_done, dot)
          os = lang_output_section_find (tree->name.name);
          check (os, tree->name.name, "LOADADDR");
          if (os->load_base == NULL)
-           result = new_rel (0, os);
+           result = new_rel (0, NULL, os);
          else
            result = exp_fold_tree_no_dot (os->load_base,
                                           abs_output_section,
@@ -501,7 +550,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
   switch (tree->type.node_class)
     {
     case etree_value:
-      result = new_rel (tree->value.value, current_section);
+      result = new_rel (tree->value.value, tree->value.str, current_section);
       break;
 
     case etree_rel:
@@ -511,6 +560,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
        result = new_rel ((tree->rel.value
                           + tree->rel.section->output_section->vma
                           + tree->rel.section->output_offset),
+                         NULL,
                          current_section);
       break;
 
@@ -578,6 +628,23 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
                result.valid_p = false;
              break;
 
+           case DATA_SEGMENT_END:
+             if (allocation_done != lang_first_phase_enum
+                 && current_section == abs_output_section
+                 && (exp_data_seg.phase == exp_dataseg_align_seen
+                     || exp_data_seg.phase == exp_dataseg_adjust
+                     || allocation_done != lang_allocating_phase_enum))
+               {
+                 if (exp_data_seg.phase == exp_dataseg_align_seen)
+                   {
+                     exp_data_seg.phase = exp_dataseg_end_seen;
+                     exp_data_seg.end = result.value;
+                   }
+               }
+             else
+               result.valid_p = false;
+             break;
+
            default:
              FAIL ();
              break;
@@ -615,7 +682,7 @@ exp_fold_tree (tree, current_section, allocation_done, dot, dotp)
            {
              result = exp_fold_tree (tree->assign.src,
                                      current_section,
-                                     lang_allocating_phase_enum, dot,
+                                     allocation_done, dot,
                                      dotp);
              if (! result.valid_p)
                einfo (_("%F%S invalid assignment to location counter\n"));
@@ -977,6 +1044,65 @@ exp_get_value_int (tree, def, name, allocation_done)
   return (int) exp_get_vma (tree, (bfd_vma) def, name, allocation_done);
 }
 
+fill_type *
+exp_get_fill (tree, def, name, allocation_done)
+     etree_type *tree;
+     fill_type *def;
+     char *name;
+     lang_phase_type allocation_done;
+{
+  fill_type *fill;
+  etree_value_type r;
+  size_t len;
+  unsigned int val;
+
+  if (tree == NULL)
+    return def;
+
+  r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done);
+  if (! r.valid_p && name != NULL)
+    einfo (_("%F%S nonconstant expression for %s\n"), name);
+
+  if (r.str != NULL && (len = strlen (r.str)) != 0)
+    {
+      unsigned char *dst;
+      unsigned char *s;
+      fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
+      fill->size = (len + 1) / 2;
+      dst = fill->data;
+      s = r.str;
+      val = 0;
+      do
+       {
+         unsigned int digit;
+
+         digit = *s++ - '0';
+         if (digit > 9)
+           digit = (digit - 'A' + '0' + 10) & 0xf;
+         val <<= 4;
+         val += digit;
+         --len;
+         if ((len & 1) == 0)
+           {
+             *dst++ = val;
+             val = 0;
+           }
+       }
+      while (len != 0);
+    }
+  else
+    {
+      fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
+      val = r.value;
+      fill->data[0] = (val >> 24) & 0xff;
+      fill->data[1] = (val >> 16) & 0xff;
+      fill->data[2] = (val >>  8) & 0xff;
+      fill->data[3] = (val >>  0) & 0xff;
+      fill->size = 4;
+    }
+  return fill;
+}
+
 bfd_vma
 exp_get_abs_int (tree, def, name, allocation_done)
      etree_type *tree;