Explicit locations: introduce explicit locations
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 888082147a1794cfd096fe306d05f2a82d55f6a2..0d6419d91ddaadc7d5449bd7ddcb77f8fc35d7d3 100644 (file)
@@ -3413,6 +3413,55 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Structure used to build the list of symbols that the user has required
+   be defined.  */
+
+struct require_defined_symbol
+{
+  const char *name;
+  struct require_defined_symbol *next;
+};
+
+/* The list of symbols that the user has required be defined.  */
+
+static struct require_defined_symbol *require_defined_symbol_list;
+
+/* Add a new symbol NAME to the list of symbols that are required to be
+   defined.  */
+
+void
+ldlang_add_require_defined (const char * const name)
+{
+  struct require_defined_symbol *ptr;
+
+  ldlang_add_undef (name, TRUE);
+  ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+  ptr->next = require_defined_symbol_list;
+  ptr->name = strdup (name);
+  require_defined_symbol_list = ptr;
+}
+
+/* Check that all symbols the user required to be defined, are defined,
+   raise an error if we find a symbol that is not defined.  */
+
+static void
+ldlang_check_require_defined_symbols (void)
+{
+  struct require_defined_symbol *ptr;
+
+  for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next)
+    {
+      struct bfd_link_hash_entry *h;
+
+      h = bfd_link_hash_lookup (link_info.hash, ptr->name,
+                                FALSE, FALSE, TRUE);
+      if (h == NULL
+          || (h->type != bfd_link_hash_defined
+              && h->type != bfd_link_hash_defweak))
+        einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
+    }
+}
+
 /* Check for all readonly or some readwrite sections.  */
 
 static void
@@ -5382,55 +5431,51 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
   if (expld.dataseg.phase == exp_dataseg_end_seen
       && link_info.relro && expld.dataseg.relro_end)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
-        to put expld.dataseg.relro_end on a (common) page boundary.  */
-      bfd_vma min_base, relro_end, maxpage;
+      bfd_vma initial_base, relro_end, desired_end;
+      asection *sec;
 
-      expld.dataseg.phase = exp_dataseg_relro_adjust;
-      maxpage = expld.dataseg.maxpagesize;
-      /* MIN_BASE is the absolute minimum address we are allowed to start the
-        read-write segment (byte before will be mapped read-only).  */
-      min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
-      expld.dataseg.base += (-expld.dataseg.relro_end
-                            & (expld.dataseg.pagesize - 1));
       /* Compute the expected PT_GNU_RELRO segment end.  */
       relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
                   & ~(expld.dataseg.pagesize - 1));
-      if (min_base + maxpage < expld.dataseg.base)
-       {
-         expld.dataseg.base -= maxpage;
-         relro_end -= maxpage;
-       }
+
+      /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END.  */
+      desired_end = relro_end - expld.dataseg.relro_offset;
+
+      /* For sections in the relro segment..  */
+      for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+       if (!IGNORE_SECTION (sec)
+           && sec->vma >= expld.dataseg.base
+           && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset)
+         {
+           /* Where do we want to put this section so that it ends as
+              desired?  */
+           bfd_vma start = sec->vma;
+           bfd_vma end = start + sec->size;
+           bfd_vma bump = desired_end - end;
+           /* We'd like to increase START by BUMP, but we must heed
+              alignment so the increase might be less than optimum.  */
+           start += bump & ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+           /* This is now the desired end for the previous section.  */
+           desired_end = start;
+         }
+
+      expld.dataseg.phase = exp_dataseg_relro_adjust;
+      ASSERT (desired_end >= expld.dataseg.base);
+      initial_base = expld.dataseg.base;
+      expld.dataseg.base = desired_end;
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
+
       if (expld.dataseg.relro_end > relro_end)
        {
-         /* The alignment of sections between DATA_SEGMENT_ALIGN
-            and DATA_SEGMENT_RELRO_END can cause excessive padding to
-            be inserted at DATA_SEGMENT_RELRO_END.  Try to start a
-            bit lower so that the section alignments will fit in.  */
-         asection *sec;
-         unsigned int max_alignment_power = 0;
-
-         /* Find maximum alignment power of sections between
-            DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END.  */
-         for (sec = link_info.output_bfd->sections; sec; sec = sec->next)
-           if (sec->vma >= expld.dataseg.base
-               && sec->vma < expld.dataseg.relro_end
-               && sec->alignment_power > max_alignment_power)
-             max_alignment_power = sec->alignment_power;
-
-         if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
-           {
-             /* Aligning the adjusted base guarantees the padding
-                between sections won't change.  This is better than
-                simply subtracting 1 << max_alignment_power which is
-                what we used to do here.  */
-             expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
-             lang_reset_memory_regions ();
-             one_lang_size_sections_pass (relax, check_regions);
-           }
+         /* Assignments to dot, or to output section address in a
+            user script have increased padding over the original.
+            Revert.  */
+         expld.dataseg.base = initial_base;
+         lang_reset_memory_regions ();
+         one_lang_size_sections_pass (relax, check_regions);
        }
+
       link_info.relro_start = expld.dataseg.base;
       link_info.relro_end = expld.dataseg.relro_end;
     }
@@ -6691,6 +6736,22 @@ lang_process (void)
   link_info.gc_sym_list = &entry_symbol;
   if (entry_symbol.name == NULL)
     link_info.gc_sym_list = ldlang_undef_chain_list_head;
+  if (link_info.init_function != NULL)
+    {
+      struct bfd_sym_chain *sym
+       = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+      sym->next = link_info.gc_sym_list;
+      sym->name = link_info.init_function;
+      link_info.gc_sym_list = sym;
+    }
+  if (link_info.fini_function != NULL)
+    {
+      struct bfd_sym_chain *sym
+       = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
+      sym->next = link_info.gc_sym_list;
+      sym->name = link_info.fini_function;
+      link_info.gc_sym_list = sym;
+    }
 
   ldemul_after_open ();
   if (config.map_file != NULL)
@@ -6793,6 +6854,9 @@ lang_process (void)
   if (command_line.check_section_addresses)
     lang_check_section_addresses ();
 
+  /* Check any required symbols are known.  */
+  ldlang_check_require_defined_symbols ();
+
   lang_end ();
 }
 
@@ -8121,3 +8185,41 @@ lang_ld_feature (char *str)
       p = q;
     }
 }
+
+/* Pretty print memory amount.  */
+
+static void
+lang_print_memory_size (bfd_vma sz)
+{
+  if ((sz & 0x3fffffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+  else if ((sz & 0xfffff) == 0)
+    printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+  else if ((sz & 0x3ff) == 0)
+    printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+  else
+    printf (" %10" BFD_VMA_FMT "u B", sz);
+}
+
+/* Implement --print-memory-usage: disply per region memory usage.  */
+
+void
+lang_print_memory_usage (void)
+{
+  lang_memory_region_type *r;
+
+  printf ("Memory region         Used Size  Region Size  %%age Used\n");
+  for (r = lang_memory_region_list; r->next != NULL; r = r->next)
+    {
+      bfd_vma used_length = r->current - r->origin;
+      double percent;
+
+      printf ("%16s: ",r->name_list.name);
+      lang_print_memory_size (used_length);
+      lang_print_memory_size ((bfd_vma) r->length);
+
+      percent = used_length * 100.0 / r->length;
+
+      printf ("    %6.2f%%\n", percent);
+    }
+}
This page took 0.026934 seconds and 4 git commands to generate.