* ld.texinfo (Simple Example): Add missing punctuation.
[deliverable/binutils-gdb.git] / ld / ldlang.c
index ad75d2648e5ffb8697feec9396e760ce249963c1..6460c32ab6de24826358b29a92e28f50f7a90c7d 100644 (file)
@@ -1,6 +1,6 @@
 /* Linker command language support.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003
+   2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of GLD, the Gnu Linker.
@@ -39,6 +39,7 @@
 #include "ldemul.h"
 #include "fnmatch.h"
 #include "demangle.h"
+#include "hashtab.h"
 
 #ifndef offsetof
 #define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
@@ -444,6 +445,7 @@ new_afile (const char *name,
   p->next = NULL;
   p->symbol_count = 0;
   p->dynamic = config.dynamic_link;
+  p->as_needed = as_needed;
   p->whole_archive = whole_archive;
   p->loaded = FALSE;
   lang_statement_append (&input_file_chain,
@@ -621,7 +623,7 @@ lang_output_section_statement_lookup (const char *const name)
 
       lookup->next = NULL;
       lookup->bfd_section = NULL;
-      lookup->processed = FALSE;
+      lookup->processed = 0;
       lookup->sectype = normal_section;
       lookup->addr_tree = NULL;
       lang_list_init (&lookup->children);
@@ -774,6 +776,10 @@ exp_init_os (etree_type *exp)
       exp_init_os (exp->trinary.rhs);
       break;
 
+    case etree_assert:
+      exp_init_os (exp->assert_s.child);
+      break;
+      
     case etree_unary:
       exp_init_os (exp->unary.child);
       break;
@@ -1096,10 +1102,6 @@ lang_add_section (lang_statement_list_type *ptr,
          flags &= ~ (SEC_MERGE | SEC_STRINGS);
        }
 
-      /* For now make .tbss normal section.  */
-      if ((flags & SEC_THREAD_LOCAL) && ! link_info.relocatable)
-       flags |= SEC_LOAD;
-
       section->output_section->flags |= flags;
 
       if (flags & SEC_MERGE)
@@ -1319,16 +1321,21 @@ lookup_name (const char *name)
        search != NULL;
        search = (lang_input_statement_type *) search->next_real_file)
     {
-      if (search->filename == NULL && name == NULL)
+      /* Use the local_sym_name as the name of the file that has
+        already been loaded as filename might have been transformed
+        via the search directory lookup mechanism.  */
+      const char * filename = search->local_sym_name;
+
+      if (filename == NULL && name == NULL)
        return search;
-      if (search->filename != NULL
+      if (filename != NULL
          && name != NULL
-         && strcmp (search->filename, name) == 0)
+         && strcmp (filename, name) == 0)
        break;
     }
 
   if (search == NULL)
-    search = new_afile (name, lang_input_file_is_file_enum, default_target,
+    search = new_afile (name, lang_input_file_is_search_file_enum, default_target,
                        FALSE);
 
   /* If we have already added this file, or this file is not real
@@ -1793,6 +1800,30 @@ ldlang_open_output (lang_statement_union_type *statement)
     }
 }
 
+/* Convert between addresses in bytes and sizes in octets.
+   For currently supported targets, octets_per_byte is always a power
+   of two, so we can use shifts.  */
+#define TO_ADDR(X) ((X) >> opb_shift)
+#define TO_SIZE(X) ((X) << opb_shift)
+
+/* Support the above.  */
+static unsigned int opb_shift = 0;
+
+static void
+init_opb (void)
+{
+  unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+                                             ldfile_output_machine);
+  opb_shift = 0;
+  if (x > 1)
+    while ((x & 1) == 0)
+      {
+       x >>= 1;
+       ++opb_shift;
+      }
+  ASSERT (x == 1);
+}
+
 /* Open all the input files.  */
 
 static void
@@ -1812,7 +1843,7 @@ open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
          /* Maybe we should load the file's symbols.  */
          if (s->wild_statement.filename
              && ! wildcardp (s->wild_statement.filename))
-           (void) lookup_name (s->wild_statement.filename);
+           lookup_name (s->wild_statement.filename);
          open_input_bfds (s->wild_statement.children.head, force);
          break;
        case lang_group_statement_enum:
@@ -2064,10 +2095,14 @@ map_input_to_output_sections
                                        target,
                                        output_section_statement);
          break;
+       case lang_data_statement_enum:
+         /* Make sure that any sections mentioned in the expression
+            are initialized.  */
+         exp_init_os (s->data_statement.exp);
+         /* FALLTHROUGH */
        case lang_fill_statement_enum:
        case lang_input_section_enum:
        case lang_object_symbols_statement_enum:
-       case lang_data_statement_enum:
        case lang_reloc_statement_enum:
        case lang_padding_statement_enum:
        case lang_input_statement_enum:
@@ -2266,8 +2301,8 @@ print_input_section (lang_input_section_type *in)
 {
   asection *i = in->section;
   bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
+
+  init_opb ();
   if (size != 0)
     {
       print_space ();
@@ -2291,7 +2326,7 @@ print_input_section (lang_input_section_type *in)
            }
 
          minfo ("0x%V %W %B\n",
-                i->output_section->vma + i->output_offset, size / opb,
+                i->output_section->vma + i->output_offset, TO_ADDR (size),
                 i->owner);
 
          if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size)
@@ -2313,7 +2348,8 @@ print_input_section (lang_input_section_type *in)
 
          bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
 
-         print_dot = i->output_section->vma + i->output_offset + size / opb;
+         print_dot = (i->output_section->vma + i->output_offset
+                      + TO_ADDR (size));
        }
     }
 }
@@ -2336,9 +2372,8 @@ print_data_statement (lang_data_statement_type *data)
   bfd_vma addr;
   bfd_size_type size;
   const char *name;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -2382,8 +2417,7 @@ print_data_statement (lang_data_statement_type *data)
 
   print_nl ();
 
-  print_dot = addr + size / opb;
-
+  print_dot = addr + TO_ADDR (size);
 }
 
 /* Print an address statement.  These are generated by options like
@@ -2405,9 +2439,8 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
   int i;
   bfd_vma addr;
   bfd_size_type size;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
     print_space ();
 
@@ -2428,7 +2461,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc)
 
   print_nl ();
 
-  print_dot = addr + size / opb;
+  print_dot = addr + TO_ADDR (size);
 }
 
 static void
@@ -2436,9 +2469,8 @@ print_padding_statement (lang_padding_statement_type *s)
 {
   int len;
   bfd_vma addr;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
+  init_opb ();
   minfo (" *fill*");
 
   len = sizeof " *fill*" - 1;
@@ -2463,7 +2495,7 @@ print_padding_statement (lang_padding_statement_type *s)
 
   print_nl ();
 
-  print_dot = addr + s->size / opb;
+  print_dot = addr + TO_ADDR (s->size);
 }
 
 static void
@@ -2692,8 +2724,6 @@ size_input_section (lang_statement_union_type **this_ptr,
 
   if (!is->ifile->just_syms_flag)
     {
-      unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                                   ldfile_output_machine);
       unsigned int alignment_needed;
       asection *o;
 
@@ -2713,7 +2743,7 @@ size_input_section (lang_statement_union_type **this_ptr,
 
       if (alignment_needed != 0)
        {
-         insert_pad (this_ptr, fill, alignment_needed * opb, o, dot);
+         insert_pad (this_ptr, fill, TO_SIZE (alignment_needed), o, dot);
          dot += alignment_needed;
        }
 
@@ -2723,10 +2753,10 @@ size_input_section (lang_statement_union_type **this_ptr,
 
       /* Mark how big the output section must be to contain this now.  */
       if (i->_cooked_size != 0)
-       dot += i->_cooked_size / opb;
+       dot += TO_ADDR (i->_cooked_size);
       else
-       dot += i->_raw_size / opb;
-      o->_raw_size = (dot - o->vma) * opb;
+       dot += TO_ADDR (i->_raw_size);
+      o->_raw_size = TO_SIZE (dot - o->vma);
     }
   else
     {
@@ -2737,8 +2767,11 @@ size_input_section (lang_statement_union_type **this_ptr,
 }
 
 #define IGNORE_SECTION(bfd, s) \
-  (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD))  \
-    != (SEC_ALLOC | SEC_LOAD))                                 \
+  (((bfd_get_section_flags (bfd, s) & SEC_THREAD_LOCAL)                        \
+    ? ((bfd_get_section_flags (bfd, s) & (SEC_LOAD | SEC_NEVER_LOAD))  \
+       != SEC_LOAD)                                                    \
+    :  ((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_NEVER_LOAD)) \
+       != SEC_ALLOC))                                                  \
    || bfd_section_size (bfd, s) == 0)
 
 /* Check to see if any allocated sections overlap with other allocated
@@ -2749,7 +2782,6 @@ static void
 lang_check_section_addresses (void)
 {
   asection *s;
-  unsigned opb = bfd_octets_per_byte (output_bfd);
 
   /* Scan all sections in the output list.  */
   for (s = output_bfd->sections; s != NULL; s = s->next)
@@ -2777,10 +2809,10 @@ lang_check_section_addresses (void)
          /* We must check the sections' LMA addresses not their
             VMA addresses because overlay sections can have
             overlapping VMAs but they must have distinct LMAs.  */
-         s_start  = bfd_section_lma (output_bfd, s);
+         s_start = bfd_section_lma (output_bfd, s);
          os_start = bfd_section_lma (output_bfd, os);
-         s_end    = s_start  + bfd_section_size (output_bfd, s) / opb - 1;
-         os_end   = os_start + bfd_section_size (output_bfd, os) / opb - 1;
+         s_end = s_start + TO_ADDR (bfd_section_size (output_bfd, s)) - 1;
+         os_end = os_start + TO_ADDR (bfd_section_size (output_bfd, os)) - 1;
 
          /* Look for an overlap.  */
          if ((s_end < os_start) || (s_start > os_end))
@@ -2804,7 +2836,7 @@ _("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
 
 static void
 os_region_check (lang_output_section_statement_type *os,
-                struct memory_region_struct *region,
+                lang_memory_region_type *region,
                 etree_type *tree,
                 bfd_vma base)
 {
@@ -2845,9 +2877,6 @@ lang_size_sections_1
    bfd_boolean *relax,
    bfd_boolean check_regions)
 {
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
-
   /* Size up the sections from their constituent parts.  */
   for (; s != NULL; s = s->header.next)
     {
@@ -2909,8 +2938,6 @@ lang_size_sections_1
                       region, and some non default memory regions were
                       defined, issue an error message.  */
                    if (!IGNORE_SECTION (output_bfd, os->bfd_section)
-                       && (bfd_get_section_flags (output_bfd, os->bfd_section)
-                           & SEC_NEVER_LOAD) == 0
                        && ! link_info.relocatable
                        && check_regions
                        && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0
@@ -2922,8 +2949,8 @@ lang_size_sections_1
                        /* By default this is an error rather than just a
                           warning because if we allocate the section to the
                           default memory region we can end up creating an
-                          excessivly large binary, or even seg faulting when
-                          attmepting to perform a negative seek.  See
+                          excessively large binary, or even seg faulting when
+                          attempting to perform a negative seek.  See
                             http://sources.redhat.com/ml/binutils/2003-04/msg00423.html
                           for an example of this.  This behaviour can be
                           overridden by the using the --no-check-sections
@@ -2957,12 +2984,15 @@ lang_size_sections_1
                  {
                    etree_value_type r;
 
+                   os->processed = -1;
                    r = exp_fold_tree (os->addr_tree,
                                       abs_output_section,
                                       lang_allocating_phase_enum,
                                       dot, &dot);
+                   os->processed = 0;
+                   
                    if (!r.valid_p)
-                     einfo (_("%F%S: non constant address expression for section %s\n"),
+                     einfo (_("%F%S: non constant or forward reference address expression for section %s\n"),
                             os->name);
 
                    dot = r.value + r.section->bfd_section->vma;
@@ -2984,22 +3014,25 @@ lang_size_sections_1
 
            /* Put the section within the requested block size, or
               align at the block boundary.  */
-           after = align_n (os->bfd_section->vma
-                            + os->bfd_section->_raw_size / opb,
-                            (bfd_vma) os->block_value);
+           after = ((os->bfd_section->vma
+                     + TO_ADDR (os->bfd_section->_raw_size)
+                     + os->block_value - 1)
+                    & - (bfd_vma) os->block_value);
 
            if (bfd_is_abs_section (os->bfd_section))
              ASSERT (after == os->bfd_section->vma);
-           else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0
-                    && (os->bfd_section->flags & SEC_THREAD_LOCAL)
-                    && ! link_info.relocatable)
-             os->bfd_section->_raw_size = 0;
            else
-             os->bfd_section->_raw_size =
-               (after - os->bfd_section->vma) * opb;
+             os->bfd_section->_raw_size
+               = TO_SIZE (after - os->bfd_section->vma);
+
+           dot = os->bfd_section->vma;
+           /* .tbss sections effectively have zero size.  */
+           if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+               || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+               || link_info.relocatable)
+             dot += TO_ADDR (os->bfd_section->_raw_size);
 
-           dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
-           os->processed = TRUE;
+           os->processed = 1;
 
            if (os->update_dot_tree != 0)
              exp_fold_tree (os->update_dot_tree, abs_output_section,
@@ -3036,7 +3069,7 @@ lang_size_sections_1
                    /* Set load_base, which will be handled later.  */
                    os->load_base = exp_intop (os->lma_region->current);
                    os->lma_region->current +=
-                     os->bfd_section->_raw_size / opb;
+                     TO_ADDR (os->bfd_section->_raw_size);
                    if (check_regions)
                      os_region_check (os, os->lma_region, NULL,
                                       os->bfd_section->lma);
@@ -3061,6 +3094,11 @@ lang_size_sections_1
            s->data_statement.output_section =
              output_section_statement->bfd_section;
 
+           /* We might refer to provided symbols in the expression, and
+              need to mark them as needed.  */
+           exp_fold_tree (s->data_statement.exp, abs_output_section,
+                          lang_allocating_phase_enum, dot, &dot);
+
            switch (s->data_statement.type)
              {
              default:
@@ -3079,9 +3117,9 @@ lang_size_sections_1
                size = BYTE_SIZE;
                break;
              }
-           if (size < opb)
-             size = opb;
-           dot += size / opb;
+           if (size < TO_SIZE ((unsigned) 1))
+             size = TO_SIZE ((unsigned) 1);
+           dot += TO_ADDR (size);
            output_section_statement->bfd_section->_raw_size += size;
            /* The output section gets contents, and then we inspect for
               any flags set in the input script which override any ALLOC.  */
@@ -3103,7 +3141,7 @@ lang_size_sections_1
            s->reloc_statement.output_section =
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
-           dot += size / opb;
+           dot += TO_ADDR (size);
            output_section_statement->bfd_section->_raw_size += size;
          }
          break;
@@ -3178,13 +3216,19 @@ lang_size_sections_1
                    /* Insert a pad after this statement.  We can't
                       put the pad before when relaxing, in case the
                       assignment references dot.  */
-                   insert_pad (&s->header.next, fill, (newdot - dot) * opb,
+                   insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot),
                                output_section_statement->bfd_section, dot);
 
                    /* Don't neuter the pad below when relaxing.  */
                    s = s->header.next;
                  }
 
+               /* If dot is advanced, this implies that the section should
+                  have space allocated to it, unless the user has explicitly
+                  stated that the section should never be loaded.  */
+               if (!(output_section_statement->flags & (SEC_NEVER_LOAD | SEC_ALLOC)))
+                 output_section_statement->bfd_section->flags |= SEC_ALLOC;
+
                dot = newdot;
              }
          }
@@ -3260,6 +3304,7 @@ lang_size_sections
          && first + last <= exp_data_seg.pagesize)
        {
          exp_data_seg.phase = exp_dataseg_adjust;
+         lang_statement_iteration++;
          result = lang_size_sections_1 (s, output_section_statement, prev,
                                         fill, dot, relax, check_regions);
        }
@@ -3285,9 +3330,6 @@ lang_do_assignments_1
    fill_type *fill,
    bfd_vma dot)
 {
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
-
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
@@ -3307,10 +3349,12 @@ lang_do_assignments_1
            if (os->bfd_section != NULL)
              {
                dot = os->bfd_section->vma;
-               (void) lang_do_assignments_1 (os->children.head, os,
-                                             os->fill, dot);
-               dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
-
+               lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+               /* .tbss sections effectively have zero size.  */
+               if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
+                   || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+                   || link_info.relocatable)
+                 dot += TO_ADDR (os->bfd_section->_raw_size);
              }
            if (os->load_base)
              {
@@ -3347,9 +3391,10 @@ lang_do_assignments_1
            value = exp_fold_tree (s->data_statement.exp,
                                   abs_output_section,
                                   lang_final_phase_enum, dot, &dot);
-           s->data_statement.value = value.value;
            if (!value.valid_p)
              einfo (_("%F%P: invalid data statement\n"));
+           s->data_statement.value
+             = value.value + value.section->bfd_section->vma;
          }
          {
            unsigned int size;
@@ -3371,9 +3416,9 @@ lang_do_assignments_1
                size = BYTE_SIZE;
                break;
              }
-           if (size < opb)
-             size = opb;
-           dot += size / opb;
+           if (size < TO_SIZE ((unsigned) 1))
+             size = TO_SIZE ((unsigned) 1);
+           dot += TO_ADDR (size);
          }
          break;
 
@@ -3388,7 +3433,7 @@ lang_do_assignments_1
            if (!value.valid_p)
              einfo (_("%F%P: invalid reloc statement\n"));
          }
-         dot += bfd_get_reloc_size (s->reloc_statement.howto) / opb;
+         dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
          break;
 
        case lang_input_section_enum:
@@ -3396,9 +3441,9 @@ lang_do_assignments_1
            asection *in = s->input_section.section;
 
            if (in->_cooked_size != 0)
-             dot += in->_cooked_size / opb;
+             dot += TO_ADDR (in->_cooked_size);
            else
-             dot += in->_raw_size / opb;
+             dot += TO_ADDR (in->_raw_size);
          }
          break;
 
@@ -3418,7 +3463,7 @@ lang_do_assignments_1
 
          break;
        case lang_padding_statement_enum:
-         dot += s->padding_statement.size / opb;
+         dot += TO_ADDR (s->padding_statement.size);
          break;
 
        case lang_group_statement_enum:
@@ -3439,10 +3484,9 @@ lang_do_assignments_1
   return dot;
 }
 
-bfd_vma
+void
 lang_do_assignments (lang_statement_union_type *s,
-                    lang_output_section_statement_type
-                    *output_section_statement,
+                    lang_output_section_statement_type *output_section_statement,
                     fill_type *fill,
                     bfd_vma dot)
 {
@@ -3488,15 +3532,11 @@ lang_set_startof (void)
       h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
       if (h != NULL && h->type == bfd_link_hash_undefined)
        {
-         unsigned opb;
-
-         opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                              ldfile_output_machine);
          h->type = bfd_link_hash_defined;
          if (s->_cooked_size != 0)
-           h->u.def.value = s->_cooked_size / opb;
+           h->u.def.value = TO_ADDR (s->_cooked_size);
          else
-           h->u.def.value = s->_raw_size / opb;
+           h->u.def.value = TO_ADDR (s->_raw_size);
          h->u.def.section = bfd_abs_section_ptr;
        }
 
@@ -3649,7 +3689,7 @@ lang_check (void)
          if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
            {
              if (command_line.warn_mismatch)
-               einfo (_("%E%X: failed to merge target specific data of file %B\n"),
+               einfo (_("%P%X: failed to merge target specific data of file %B\n"),
                       input_bfd);
            }
          if (! command_line.warn_mismatch)
@@ -3690,8 +3730,6 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   unsigned int power_of_two;
   bfd_vma size;
   asection *section;
-  unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
-                                               ldfile_output_machine);
 
   if (h->type != bfd_link_hash_common)
     return TRUE;
@@ -3705,9 +3743,9 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   section = h->u.c.p->section;
 
-  /* Increase the size of the section.  */
-  section->_cooked_size = align_n ((section->_cooked_size + opb - 1) / opb,
-                                  (bfd_vma) 1 << power_of_two) * opb;
+  /* Increase the size of the section to align the common sym.  */
+  section->_cooked_size += ((bfd_vma) 1 << (power_of_two + opb_shift)) - 1;
+  section->_cooked_size &= (- (bfd_vma) 1 << (power_of_two + opb_shift));
 
   /* Adjust the alignment if necessary.  */
   if (power_of_two > section->alignment_power)
@@ -3902,24 +3940,6 @@ lang_for_each_file (void (*func) (lang_input_statement_type *))
     }
 }
 
-#if 0
-
-/* Not used.  */
-
-void
-lang_for_each_input_section (void (*func) (bfd *ab, asection *as))
-{
-  LANG_FOR_EACH_INPUT_STATEMENT (f)
-    {
-      asection *s;
-
-      for (s = f->the_bfd->sections; s != NULL; s = s->next)
-       func (f->the_bfd, s);
-    }
-}
-
-#endif
-
 void
 ldlang_add_file (lang_input_statement_type *entry)
 {
@@ -3988,7 +4008,6 @@ lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
                                     enum section_type sectype,
-                                    bfd_vma block_value,
                                     etree_type *align,
                                     etree_type *subalign,
                                     etree_type *ebase)
@@ -4015,7 +4034,7 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
     os->flags = SEC_NO_FLAGS;
   else
     os->flags = SEC_NEVER_LOAD;
-  os->block_value = block_value ? block_value : 1;
+  os->block_value = 1;
   stat_ptr = &os->children;
 
   os->subsection_alignment =
@@ -4141,6 +4160,7 @@ lang_process (void)
 
   /* Open the output file.  */
   lang_for_each_statement (ldlang_open_output);
+  init_opb ();
 
   ldemul_create_output_section_statements ();
 
@@ -4234,8 +4254,6 @@ lang_process (void)
 
       do
        {
-         lang_reset_memory_regions ();
-
          relax_again = FALSE;
 
          /* Note: pe-dll.c does something like this also.  If you find
@@ -4247,6 +4265,10 @@ lang_process (void)
          lang_do_assignments (statement_list.head, abs_output_section,
                               NULL, 0);
 
+         /* We must do this after lang_do_assignments, because it uses
+            _raw_size.  */
+         lang_reset_memory_regions ();
+
          /* Perform another relax pass - this time we know where the
             globals are, so can make a better guess.  */
          lang_size_sections (statement_list.head, abs_output_section,
@@ -4254,17 +4276,17 @@ lang_process (void)
 
          /* If the normal relax is done and the relax finalize pass
             is not performed yet, we perform another relax pass.  */
-         if (!relax_again && !link_info.relax_finalizing)
+         if (!relax_again && link_info.need_relax_finalize)
            {
-             link_info.relax_finalizing = TRUE;
+             link_info.need_relax_finalize = FALSE;
              relax_again = TRUE;
            }
        }
       while (relax_again);
 
       /* Final extra sizing to report errors.  */
-      lang_reset_memory_regions ();
       lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
+      lang_reset_memory_regions ();
       lang_size_sections (statement_list.head, abs_output_section,
                          &statement_list.head, 0, 0, NULL, TRUE);
     }
@@ -4484,34 +4506,38 @@ lang_float (bfd_boolean maybe)
    It is an error to specify both a load region and a load address.  */
 
 static void
-lang_get_regions (struct memory_region_struct **region,
-                 struct memory_region_struct **lma_region,
+lang_get_regions (lang_memory_region_type **region,
+                 lang_memory_region_type **lma_region,
                  const char *memspec,
                  const char *lma_memspec,
-                 int have_lma_p)
+                 bfd_boolean have_lma,
+                 bfd_boolean have_vma)
 {
   *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
 
-  /* If no runtime region has been given, but the load region has
-     been, use the load region.  */
-  if (lma_memspec != 0 && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
+  /* If no runtime region or VMA has been specified, but the load region has
+     been specified, then use the load region for the runtime region as well.  */
+  if (lma_memspec != NULL
+      && ! have_vma
+      && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
     *region = lang_memory_region_lookup (memspec, FALSE);
 
-  if (have_lma_p && lma_memspec != 0)
+  if (have_lma && lma_memspec != 0)
     einfo (_("%X%P:%S: section has both a load address and a load region\n"));
 }
 
 void
-lang_leave_output_section_statement
-  (fill_type *fill, const char *memspec,
-   struct lang_output_section_phdr_list *phdrs, const char *lma_memspec)
+lang_leave_output_section_statement (fill_type *fill, const char *memspec,
+                                    lang_output_section_phdr_list *phdrs,
+                                    const char *lma_memspec)
 {
   lang_get_regions (&current_section->region,
                    &current_section->lma_region,
                    memspec, lma_memspec,
-                   current_section->load_base != 0);
+                   current_section->load_base != NULL,
+                   current_section->addr_tree != NULL);
   current_section->fill = fill;
   current_section->phdrs = phdrs;
   stat_ptr = &statement_list;
@@ -4574,8 +4600,7 @@ lang_abs_symbol_at_end_of (const char *secname, const char *name)
        h->u.def.value = 0;
       else
        h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
-                         + bfd_section_size (output_bfd, sec) /
-                          bfd_octets_per_byte (output_bfd));
+                         + TO_ADDR (bfd_section_size (output_bfd, sec)));
 
       h->u.def.section = bfd_abs_section_ptr;
     }
@@ -4671,7 +4696,7 @@ lang_record_phdrs (void)
 {
   unsigned int alc;
   asection **secs;
-  struct lang_output_section_phdr_list *last;
+  lang_output_section_phdr_list *last;
   struct lang_phdr *l;
   lang_statement_union_type *u;
 
@@ -4690,7 +4715,7 @@ lang_record_phdrs (void)
           u = u->output_section_statement.next)
        {
          lang_output_section_statement_type *os;
-         struct lang_output_section_phdr_list *pl;
+         lang_output_section_phdr_list *pl;
 
          os = &u->output_section_statement;
 
@@ -4750,7 +4775,7 @@ lang_record_phdrs (void)
        u != NULL;
        u = u->output_section_statement.next)
     {
-      struct lang_output_section_phdr_list *pl;
+      lang_output_section_phdr_list *pl;
 
       if (u->output_section_statement.bfd_section == NULL)
        continue;
@@ -4767,7 +4792,7 @@ lang_record_phdrs (void)
 /* Record a list of sections which may not be cross referenced.  */
 
 void
-lang_add_nocrossref (struct lang_nocrossref *l)
+lang_add_nocrossref (lang_nocrossref_type *l)
 {
   struct lang_nocrossrefs *n;
 
@@ -4824,7 +4849,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, normal_section,
-                                      0, 0, overlay_subalign, 0);
+                                      0, overlay_subalign, 0);
 
   /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
@@ -4852,7 +4877,7 @@ lang_enter_overlay_section (const char *name)
 
 void
 lang_leave_overlay_section (fill_type *fill,
-                           struct lang_output_section_phdr_list *phdrs)
+                           lang_output_section_phdr_list *phdrs)
 {
   const char *name;
   char *clean, *s2;
@@ -4899,17 +4924,17 @@ lang_leave_overlay (etree_type *lma_expr,
                    int nocrossrefs,
                    fill_type *fill,
                    const char *memspec,
-                   struct lang_output_section_phdr_list *phdrs,
+                   lang_output_section_phdr_list *phdrs,
                    const char *lma_memspec)
 {
   lang_memory_region_type *region;
   lang_memory_region_type *lma_region;
   struct overlay_list *l;
-  struct lang_nocrossref *nocrossref;
+  lang_nocrossref_type *nocrossref;
 
   lang_get_regions (&region, &lma_region,
                    memspec, lma_memspec,
-                   lma_expr != 0);
+                   lma_expr != NULL, FALSE);
 
   nocrossref = NULL;
 
@@ -4946,7 +4971,7 @@ lang_leave_overlay (etree_type *lma_expr,
 
       if (nocrossrefs)
        {
-         struct lang_nocrossref *nc;
+         lang_nocrossref_type *nc;
 
          nc = xmalloc (sizeof *nc);
          nc->name = l->os->name;
@@ -4973,65 +4998,152 @@ lang_leave_overlay (etree_type *lma_expr,
 
 struct bfd_elf_version_tree *lang_elf_version_info;
 
-static int
-lang_vers_match_lang_c (struct bfd_elf_version_expr *expr,
-                       const char *sym)
-{
-  if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
-    return 1;
-  return fnmatch (expr->pattern, sym, 0) == 0;
-}
+/* If PREV is NULL, return first version pattern matching particular symbol.
+   If PREV is non-NULL, return first version pattern matching particular
+   symbol after PREV (previously returned by lang_vers_match).  */
 
-static int
-lang_vers_match_lang_cplusplus (struct bfd_elf_version_expr *expr,
-                               const char *sym)
+static struct bfd_elf_version_expr *
+lang_vers_match (struct bfd_elf_version_expr_head *head,
+                struct bfd_elf_version_expr *prev,
+                const char *sym)
 {
-  char *alt_sym;
-  int result;
+  const char *cxx_sym = sym;
+  const char *java_sym = sym;
+  struct bfd_elf_version_expr *expr = NULL;
 
-  if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
-    return 1;
+  if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
+    {
+      cxx_sym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI);
+      if (!cxx_sym)
+       cxx_sym = sym;
+    }
+  if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
+    {
+      java_sym = cplus_demangle (sym, DMGL_JAVA);
+      if (!java_sym)
+       java_sym = sym;
+    }
 
-  alt_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0);
-  if (!alt_sym)
+  if (head->htab && (prev == NULL || prev->symbol))
     {
-      /* cplus_demangle (also) returns NULL when it is not a C++ symbol.
-        Should we early out FALSE in this case?  */
-      result = fnmatch (expr->pattern, sym, 0) == 0;
+      struct bfd_elf_version_expr e;
+
+      switch (prev ? prev->mask : 0)
+       {
+         case 0:
+           if (head->mask & BFD_ELF_VERSION_C_TYPE)
+             {
+               e.symbol = sym;
+               expr = htab_find (head->htab, &e);
+               while (expr && strcmp (expr->symbol, sym) == 0)
+                 if (expr->mask == BFD_ELF_VERSION_C_TYPE)
+                   goto out_ret;
+               else
+                 expr = expr->next;
+             }
+           /* Fallthrough */
+         case BFD_ELF_VERSION_C_TYPE:
+           if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
+             {
+               e.symbol = cxx_sym;
+               expr = htab_find (head->htab, &e);
+               while (expr && strcmp (expr->symbol, cxx_sym) == 0)
+                 if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
+                   goto out_ret;
+               else
+                 expr = expr->next;
+             }
+           /* Fallthrough */
+         case BFD_ELF_VERSION_CXX_TYPE:
+           if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
+             {
+               e.symbol = java_sym;
+               expr = htab_find (head->htab, &e);
+               while (expr && strcmp (expr->symbol, java_sym) == 0)
+                 if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
+                   goto out_ret;
+               else
+                 expr = expr->next;
+             }
+           /* Fallthrough */
+         default:
+           break;
+       }
     }
+
+  /* Finally, try the wildcards.  */
+  if (prev == NULL || prev->symbol)
+    expr = head->remaining;
   else
+    expr = prev->next;
+  while (expr)
     {
-      result = fnmatch (expr->pattern, alt_sym, 0) == 0;
-      free (alt_sym);
+      const char *s;
+
+      if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
+       break;
+
+      if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
+       s = java_sym;
+      else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
+       s = cxx_sym;
+      else
+       s = sym;
+      if (fnmatch (expr->pattern, s, 0) == 0)
+       break;
+      expr = expr->next;
     }
 
-  return result;
+out_ret:
+  if (cxx_sym != sym)
+    free ((char *) cxx_sym);
+  if (java_sym != sym)
+    free ((char *) java_sym);
+  return expr;
 }
 
-static int
-lang_vers_match_lang_java (struct bfd_elf_version_expr *expr,
-                          const char *sym)
+/* Return NULL if the PATTERN argument is a glob pattern, otherwise,
+   return a string pointing to the symbol name.  */
+
+static const char *
+realsymbol (const char *pattern)
 {
-  char *alt_sym;
-  int result;
+  const char *p;
+  bfd_boolean changed = FALSE, backslash = FALSE;
+  char *s, *symbol = xmalloc (strlen (pattern) + 1);
+
+  for (p = pattern, s = symbol; *p != '\0'; ++p)
+    {
+      /* It is a glob pattern only if there is no preceding
+        backslash.  */
+      if (! backslash && (*p == '?' || *p == '*' || *p == '['))
+       {
+         free (symbol);
+         return NULL;
+       }
 
-  if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
-    return 1;
+      if (backslash)
+       {
+         /* Remove the preceding backslash.  */
+         *(s - 1) = *p;
+         changed = TRUE;
+       }
+      else
+       *s++ = *p;
 
-  alt_sym = cplus_demangle (sym, DMGL_JAVA);
-  if (!alt_sym)
+      backslash = *p == '\\';
+    }
+
+  if (changed)
     {
-      /* cplus_demangle (also) returns NULL when it is not a Java symbol.
-        Should we early out FALSE in this case?  */
-      result = fnmatch (expr->pattern, sym, 0) == 0;
+      *s = '\0';
+      return symbol;
     }
   else
     {
-      result = fnmatch (expr->pattern, alt_sym, 0) == 0;
-      free (alt_sym);
+      free (symbol);
+      return pattern;
     }
-
-  return result;
 }
 
 /* This is called for each variable name or match expression.  */
@@ -5048,18 +5160,19 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
   ret->pattern = new;
   ret->symver = 0;
   ret->script = 0;
+  ret->symbol = realsymbol (new);
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
-    ret->match = lang_vers_match_lang_c;
+    ret->mask = BFD_ELF_VERSION_C_TYPE;
   else if (strcasecmp (lang, "C++") == 0)
-    ret->match = lang_vers_match_lang_cplusplus;
+    ret->mask = BFD_ELF_VERSION_CXX_TYPE;
   else if (strcasecmp (lang, "Java") == 0)
-    ret->match = lang_vers_match_lang_java;
+    ret->mask = BFD_ELF_VERSION_JAVA_TYPE;
   else
     {
       einfo (_("%X%P: unknown language `%s' in version information\n"),
             lang);
-      ret->match = lang_vers_match_lang_c;
+      ret->mask = BFD_ELF_VERSION_C_TYPE;
     }
 
   return ldemul_new_vers_pattern (ret);
@@ -5074,15 +5187,11 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
 {
   struct bfd_elf_version_tree *ret;
 
-  ret = xmalloc (sizeof *ret);
-  ret->next = NULL;
-  ret->name = NULL;
-  ret->vernum = 0;
-  ret->globals = globals;
-  ret->locals = locals;
-  ret->deps = NULL;
+  ret = xcalloc (1, sizeof *ret);
+  ret->globals.list = globals;
+  ret->locals.list = locals;
+  ret->match = lang_vers_match;
   ret->name_indx = (unsigned int) -1;
-  ret->used = 0;
   return ret;
 }
 
@@ -5090,6 +5199,102 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
 
 static int version_index;
 
+static hashval_t
+version_expr_head_hash (const void *p)
+{
+  const struct bfd_elf_version_expr *e = p;
+
+  return htab_hash_string (e->symbol);
+}
+
+static int
+version_expr_head_eq (const void *p1, const void *p2)
+{
+  const struct bfd_elf_version_expr *e1 = p1;
+  const struct bfd_elf_version_expr *e2 = p2;
+
+  return strcmp (e1->symbol, e2->symbol) == 0;
+}
+
+static void
+lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
+{
+  size_t count = 0;
+  struct bfd_elf_version_expr *e, *next;
+  struct bfd_elf_version_expr **list_loc, **remaining_loc;
+
+  for (e = head->list; e; e = e->next)
+    {
+      if (e->symbol)
+       count++;
+      head->mask |= e->mask;
+    }
+
+  if (count)
+    {
+      head->htab = htab_create (count * 2, version_expr_head_hash,
+                               version_expr_head_eq, NULL);
+      list_loc = &head->list;
+      remaining_loc = &head->remaining;
+      for (e = head->list; e; e = next)
+       {
+         next = e->next;
+         if (!e->symbol)
+           {
+             *remaining_loc = e;
+             remaining_loc = &e->next;
+           }
+         else
+           {
+             void **loc = htab_find_slot (head->htab, e, INSERT);
+
+             if (*loc)
+               {
+                 struct bfd_elf_version_expr *e1, *last;
+
+                 e1 = *loc;
+                 last = NULL;
+                 do
+                   {
+                     if (e1->mask == e->mask)
+                       {
+                         last = NULL;
+                         break;
+                       }
+                     last = e1;
+                     e1 = e1->next;
+                   }
+                 while (e1 && strcmp (e1->symbol, e->symbol) == 0);
+
+                 if (last == NULL)
+                   {
+                     /* This is a duplicate.  */
+                     /* FIXME: Memory leak.  Sometimes pattern is not
+                        xmalloced alone, but in larger chunk of memory.  */
+                     /* free (e->symbol); */
+                     free (e);
+                   }
+                 else
+                   {
+                     e->next = last->next;
+                     last->next = e;
+                   }
+               }
+             else
+               {
+                 *loc = e;
+                 *list_loc = e;
+                 list_loc = &e->next;
+               }
+           }
+       }
+      *remaining_loc = NULL;
+      *list_loc = head->remaining;
+    }
+  else
+    head->remaining = head->list;
+}
+
 /* This is called when we know the name and dependencies of the
    version.  */
 
@@ -5117,32 +5322,59 @@ lang_register_vers_node (const char *name,
     if (strcmp (t->name, name) == 0)
       einfo (_("%X%P: duplicate version tag `%s'\n"), name);
 
+  lang_finalize_version_expr_head (&version->globals);
+  lang_finalize_version_expr_head (&version->locals);
+
   /* Check the global and local match names, and make sure there
      aren't any duplicates.  */
 
-  for (e1 = version->globals; e1 != NULL; e1 = e1->next)
+  for (e1 = version->globals.list; e1 != NULL; e1 = e1->next)
     {
       for (t = lang_elf_version_info; t != NULL; t = t->next)
        {
          struct bfd_elf_version_expr *e2;
 
-         for (e2 = t->locals; e2 != NULL; e2 = e2->next)
-           if (strcmp (e1->pattern, e2->pattern) == 0)
-             einfo (_("%X%P: duplicate expression `%s' in version information\n"),
-                    e1->pattern);
+         if (t->locals.htab && e1->symbol)
+           {
+             e2 = htab_find (t->locals.htab, e1);
+             while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+               {
+                 if (e1->mask == e2->mask)
+                   einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+                          e1->symbol);
+                 e2 = e2->next;
+               }
+           }
+         else if (!e1->symbol)
+           for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
+             if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
+               einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+                      e1->pattern);
        }
     }
 
-  for (e1 = version->locals; e1 != NULL; e1 = e1->next)
+  for (e1 = version->locals.list; e1 != NULL; e1 = e1->next)
     {
       for (t = lang_elf_version_info; t != NULL; t = t->next)
        {
          struct bfd_elf_version_expr *e2;
 
-         for (e2 = t->globals; e2 != NULL; e2 = e2->next)
-           if (strcmp (e1->pattern, e2->pattern) == 0)
-             einfo (_("%X%P: duplicate expression `%s' in version information\n"),
-                    e1->pattern);
+         if (t->globals.htab && e1->symbol)
+           {
+             e2 = htab_find (t->globals.htab, e1);
+             while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+               {
+                 if (e1->mask == e2->mask)
+                   einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+                          e1->symbol);
+                 e2 = e2->next;
+               }
+           }
+         else if (!e1->symbol)
+           for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
+             if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
+               einfo (_("%X%P: duplicate expression `%s' in version information\n"),
+                      e1->pattern);
        }
     }
 
This page took 0.039252 seconds and 4 git commands to generate.