This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 12/16] binutils: Introduce "ld_main" and state-purging within "ld" subdir


As before in "gas", introduce code to ld to restore state.

I've only tested this on x86_64, and there are some hacks in here
that hardcode that, but hopefully this is enough to show the idea.
---
 ld/emultempl/elf32.em |  77 +++++++++++++++++++++++++++++++++----
 ld/ld.h               |   8 ++++
 ld/ldexp.c            |  11 ++++++
 ld/ldlang.c           |  90 +++++++++++++++++++++++++++++++++++++++++++
 ld/ldmain.c           | 103 +++++++++++++++++++++++++++++++++++++++++++++-----
 ld/ldmainmain.c       |  34 +++++++++++++++++
 ld/lexsup.c           |  12 +++++-
 ld/libld.h            |  41 ++++++++++++++++++++
 8 files changed, 359 insertions(+), 17 deletions(-)
 create mode 100644 ld/ldmainmain.c
 create mode 100644 ld/libld.h

diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 0802d76..e24987e 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1740,12 +1740,9 @@ output_rel_find (asection *sec, int isdyn)
 /* Place an orphan section.  We use this to put random SHF_ALLOC
    sections in the right segment.  */
 
-static lang_output_section_statement_type *
-gld${EMULATION_NAME}_place_orphan (asection *s,
-				   const char *secname,
-				   int constraint)
-{
-  static struct orphan_save hold[] =
+static int orphan_init_done = 0;
+
+static struct orphan_save hold[] =
     {
       { ".text",
 	SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE,
@@ -1775,6 +1772,12 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
 	SEC_HAS_CONTENTS,
 	0, 0, 0, 0 },
     };
+
+static lang_output_section_statement_type *
+gld${EMULATION_NAME}_place_orphan (asection *s,
+				   const char *secname,
+				   int constraint)
+{
   enum orphan_save_index
     {
       orphan_text = 0,
@@ -1787,7 +1790,6 @@ gld${EMULATION_NAME}_place_orphan (asection *s,
       orphan_sdata,
       orphan_nonalloc
     };
-  static int orphan_init_done = 0;
   struct orphan_save *place;
   lang_output_section_statement_type *after;
   lang_output_section_statement_type *os;
@@ -2441,3 +2443,64 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
 };
 EOF
+
+fragment <<EOF
+
+/* FIXME: how to arrange for this to actually be called? */
+extern void
+gld${EMULATION_NAME}_finalize (void);
+
+void
+gld${EMULATION_NAME}_finalize (void)
+{
+  global_needed = NULL;
+  CLEAR_VAR (global_stat);
+  global_found = NULL;
+  global_vercheck_needed = NULL;
+  global_vercheck_failed = 0;
+  audit = NULL;
+  depaudit = NULL;
+  emit_note_gnu_build_id = NULL;
+  orphan_init_done = 0;
+
+  /* Reset the "hold" table.  */
+  CLEAR_VAR (hold);
+
+#define INIT_HOLD(IDX, NAME, FLAGS)   \
+  do {                                \
+    hold[IDX].name = (NAME);          \
+    hold[IDX].flags = (FLAGS);        \
+  } while (0)
+
+  INIT_HOLD (0,
+             ".text",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE);
+  INIT_HOLD (1,
+             ".rodata",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA);
+  INIT_HOLD (2,
+             ".tdata",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_THREAD_LOCAL);
+  INIT_HOLD (3,
+             ".data",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA);
+  INIT_HOLD (4,
+             ".bss",
+             SEC_ALLOC);
+  INIT_HOLD (5,
+             NULL,
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA);
+  INIT_HOLD (6,
+             ".interp",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA);
+  INIT_HOLD (7,
+             ".sdata",
+             SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA);
+  INIT_HOLD (8,
+             ".comment",
+             SEC_HAS_CONTENTS);
+
+#undef INIT_HOLD
+}
+
+EOF
diff --git a/ld/ld.h b/ld/ld.h
index f804f9c..e114f45 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -302,4 +302,12 @@ extern void ld_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
 #undef abort
 #define abort() ld_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__)
 
+extern struct ctimer *ld_timer;
+
+#define TIMER_PUSH(ITEM_NAME) \
+  do { CTIMER_PUSH (ld_timer, (ITEM_NAME)); } while (0)
+
+#define TIMER_POP() \
+  do { CTIMER_POP (ld_timer); } while (0)
+
 #endif
diff --git a/ld/ldexp.c b/ld/ldexp.c
index a5192b1..0c18cb5 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -1580,3 +1580,14 @@ ldexp_finish (void)
 {
   bfd_hash_table_free (&definedness_table);
 }
+
+/* FIXME.  */
+extern void ldexp_c_finalize (void);
+
+/* FIXME.  */
+void ldexp_c_finalize (void)
+{
+   segments = NULL;
+   CLEAR_VAR (expld);
+   CLEAR_VAR (definedness_table);
+}
diff --git a/ld/ldlang.c b/ld/ldlang.c
index c96c21f..d44bcab 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2722,7 +2722,9 @@ load_symbols (lang_input_statement_type *entry,
   if (entry->flags.loaded)
     return TRUE;
 
+  TIMER_PUSH ("load_symbols: ldfile_open_file");
   ldfile_open_file (entry);
+  TIMER_POP ();
 
   /* Do not process further if the file was missing.  */
   if (entry->flags.missing_file)
@@ -2851,10 +2853,12 @@ load_symbols (lang_input_statement_type *entry,
       break;
     }
 
+  TIMER_PUSH ("load_symbols: bfd_link_add_symbols");
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
     entry->flags.loaded = TRUE;
   else
     einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd);
+  TIMER_POP ();
 
   return entry->flags.loaded;
 }
@@ -3086,6 +3090,8 @@ lang_get_output_target (void)
 static void
 open_output (const char *name)
 {
+  TIMER_PUSH ("open_output");
+
   output_target = lang_get_output_target ();
 
   /* Has the user requested a particular endianness on the command
@@ -3161,6 +3167,8 @@ open_output (const char *name)
     einfo (_("%P%F: can not create hash table: %E\n"));
 
   bfd_set_gp_size (link_info.output_bfd, g_switch_value);
+
+  TIMER_POP ();
 }
 
 static void
@@ -3233,6 +3241,7 @@ static lang_input_statement_type *plugin_insert = NULL;
 static void
 open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 {
+  TIMER_PUSH ("open_input_bfds");
   for (; s != NULL; s = s->header.next)
     {
       switch (s->header.type)
@@ -3279,6 +3288,8 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 	      lang_statement_list_type add;
 	      bfd *abfd;
 
+              TIMER_PUSH ("lang_input_statement_enum");
+
 	      s->input_statement.target = current_target;
 
 	      /* If we are being called from within a group, and this
@@ -3308,8 +3319,10 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 	      os_tail = lang_output_section_statement.tail;
 	      lang_list_init (&add);
 
+              TIMER_PUSH ("open_input_bfds:load_symbols");
 	      if (! load_symbols (&s->input_statement, &add))
 		config.make_executable = FALSE;
+              TIMER_POP ();
 
 	      if (add.head != NULL)
 		{
@@ -3333,6 +3346,8 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 		      s->header.next = add.head;
 		    }
 		}
+
+              TIMER_POP ();
 	    }
 #ifdef ENABLE_PLUGINS
 	  /* If we have found the point at which a plugin added new
@@ -3354,6 +3369,8 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
   /* Exit if any of the files were missing.  */
   if (input_flags.missing_file)
     einfo ("%F");
+
+  TIMER_POP ();
 }
 
 /* Add the supplied name to the symbol table as an undefined reference.
@@ -6192,6 +6209,8 @@ lang_for_each_file (void (*func) (lang_input_statement_type *))
 void
 ldlang_add_file (lang_input_statement_type *entry)
 {
+  TIMER_PUSH ("ldlang_add_file");
+
   lang_statement_append (&file_chain,
 			 (lang_statement_union_type *) entry,
 			 &entry->next);
@@ -6217,6 +6236,8 @@ ldlang_add_file (lang_input_statement_type *entry)
      this, we should probably handle SEC_EXCLUDE in the same way.  */
 
   bfd_map_over_sections (entry->the_bfd, section_already_linked, entry);
+
+  TIMER_POP ();
 }
 
 void
@@ -6605,6 +6626,8 @@ lang_list_remove_tail (lang_statement_list_type *destlist,
 void
 lang_process (void)
 {
+  TIMER_PUSH ("lang_process: 1st half");
+
   /* Finalize dynamic list.  */
   if (link_info.dynamic_list)
     lang_finalize_version_expr_head (&link_info.dynamic_list->head);
@@ -6773,6 +6796,10 @@ lang_process (void)
 	}
     }
 
+  TIMER_POP ();
+
+  TIMER_PUSH ("lang_process: 2nd half");
+
   /* Do anything special before sizing sections.  This is where ELF
      and other back-ends size dynamic sections.  */
   ldemul_before_allocation ();
@@ -6806,6 +6833,8 @@ lang_process (void)
     lang_check_section_addresses ();
 
   lang_end ();
+
+  TIMER_POP ();
 }
 
 /* EXPORTED TO YACC */
@@ -8133,3 +8162,64 @@ lang_ld_feature (char *str)
       p = q;
     }
 }
+
+/* FIXME.  */
+extern void ldlang_c_finalize (void);
+
+/* FIXME.  */
+void ldlang_c_finalize (void)
+{
+  obstack_free (&stat_obstack, 0);
+  CLEAR_VAR (stat_obstack);
+  obstack_free (&map_obstack, 0);
+  CLEAR_VAR (map_obstack);
+  entry_symbol_default = "start";
+  placed_commons = FALSE;
+  map_head_is_link_order = FALSE;
+  default_common_section = NULL;
+  map_option_f = 0;
+  print_dot = 0;
+  first_file = NULL;
+  current_target = NULL;
+  CLEAR_VAR (statement_list);
+  CLEAR_VAR (stat_save);
+  stat_save_ptr = &stat_save[0];
+  unique_section_list = NULL;
+  asneeded_list_head = NULL;
+  output_target = NULL;
+  abs_output_section = NULL;
+  CLEAR_VAR (lang_output_section_statement);
+  stat_ptr = &statement_list;
+  CLEAR_VAR (file_chain);
+  CLEAR_VAR (input_file_chain);
+  CLEAR_VAR (entry_symbol);
+  entry_section = ".text";
+  CLEAR_VAR (input_flags);
+  entry_from_cmdline = 0;
+  undef_from_cmdline = 0;
+  lang_has_input_file = FALSE;
+  had_output_filename = FALSE;
+  lang_float_flag = FALSE;
+  delete_output_file_on_failure = FALSE;
+  lang_phdr_list = NULL;
+  nocrossref_list = NULL;
+  asneeded_list_tail = NULL;
+  lang_statement_iteration = 0;
+  CLEAR_VAR (output_section_statement_table);
+  lang_memory_region_list = NULL;
+  lang_memory_region_list_tail = &lang_memory_region_list;
+  excluded_libs = NULL;
+  winner = NULL;
+  opb_shift = 0;
+#ifdef ENABLE_PLUGINS
+  plugin_insert = NULL;
+#endif
+  current_section = NULL;
+  current_assign = NULL;
+  prefer_next_section = 0;
+  overlay_vma = NULL;
+  overlay_subalign = NULL;
+  overlay_max = NULL;
+  overlay_list = NULL;
+  version_index = 0;
+}
diff --git a/ld/ldmain.c b/ld/ldmain.c
index a7b72bd..daa4903 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -27,6 +27,8 @@
 #include "bfdlink.h"
 #include "filenames.h"
 
+#include "libld.h"
+
 #include "ld.h"
 #include "ldmain.h"
 #include "ldmisc.h"
@@ -138,7 +140,7 @@ static bfd_boolean notice
   (struct bfd_link_info *, struct bfd_link_hash_entry *,
    struct bfd_link_hash_entry *, bfd *, asection *, bfd_vma, flagword);
 
-static struct bfd_link_callbacks link_callbacks =
+static const struct bfd_link_callbacks link_callbacks =
 {
   add_archive_element,
   multiple_definition,
@@ -183,8 +185,10 @@ ld_bfd_assert_handler (const char *fmt, const char *bfdver,
   config.make_executable = FALSE;
 }
 
-int
-main (int argc, char **argv)
+/* FIXME.  */
+
+static int
+ld_internal_main (int argc, char **argv, int standalone)
 {
   char *emulation;
   long start_time = get_run_time ();
@@ -192,6 +196,8 @@ main (int argc, char **argv)
   char *start_sbrk = (char *) sbrk (0);
 #endif
 
+  TIMER_PUSH ("ld_internal_main: init");
+
 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
   setlocale (LC_MESSAGES, "");
 #endif
@@ -217,7 +223,8 @@ main (int argc, char **argv)
      leave no trace.  */
   default_bfd_assert_handler = bfd_set_assert_handler (ld_bfd_assert_handler);
 
-  xatexit (ld_cleanup);
+  if (standalone)
+    xatexit (ld_cleanup);
 
   /* Set up the sysroot directory.  */
   ld_sysroot = get_sysroot (argc, argv);
@@ -236,6 +243,8 @@ main (int argc, char **argv)
   else
     ld_canon_sysroot_len = -1;
 
+  TIMER_POP ();
+
   /* Set the default BFD target based on the configured target.  Doing
      this permits the linker to be configured for a particular target,
      and linked against a shared BFD library which was configured for
@@ -243,7 +252,7 @@ main (int argc, char **argv)
   if (! bfd_set_default_target (TARGET))
     {
       einfo (_("%X%P: can't set BFD default target to `%s': %E\n"), TARGET);
-      xexit (1);
+      return 1;
     }
 
 #if YYDEBUG
@@ -377,19 +386,21 @@ main (int argc, char **argv)
   if (command_line.print_output_format)
     info_msg ("%s\n", lang_get_output_target ());
 
+  TIMER_PUSH ("ldmain.c: lang_final");
   lang_final ();
+  TIMER_POP ();
 
   /* If the only command line argument has been -v or --version or --verbose
      then ignore any input files provided by linker scripts and exit now.
      We do not want to create an output file when the linker is just invoked
      to provide version information.  */
   if (argc == 2 && version_printed)
-    xexit (0);
+    return 0;
 
   if (!lang_has_input_file)
     {
       if (version_printed || command_line.print_output_format)
-	xexit (0);
+	return 0;
       einfo (_("%P%F: no input files\n"));
     }
 
@@ -416,7 +427,9 @@ main (int argc, char **argv)
 	}
     }
 
+  TIMER_PUSH ("ldmain.c: lang_process");
   lang_process ();
+  TIMER_POP ();
 
   /* Print error messages for any missing symbols, for any warning
      symbols, and possibly multiple definitions.  */
@@ -432,7 +445,9 @@ main (int argc, char **argv)
 	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
     }
 
+  TIMER_PUSH ("ldmain.c: ldwrite");
   ldwrite ();
+  TIMER_POP ();
 
   if (config.map_file != NULL)
     lang_map ();
@@ -461,7 +476,7 @@ main (int argc, char **argv)
 	       output_filename);
 
       /* The file will be removed by ld_cleanup.  */
-      xexit (1);
+      return 1;
     }
   else
     {
@@ -536,10 +551,56 @@ main (int argc, char **argv)
   /* Prevent ld_cleanup from doing anything, after a successful link.  */
   output_filename = NULL;
 
-  xexit (0);
   return 0;
 }
 
+/* FIXME. */
+extern void ldexp_c_finalize (void);
+extern void ldlang_c_finalize (void);
+
+static void ldmain_c_finalize (void);
+
+/* FIXME: hardcoded; really ought to be calling all of these.  */
+extern void
+gldelf_x86_64_finalize (void);
+
+/* The global ctimer instance (or NULL).  */
+struct ctimer *ld_timer;
+
+/* FIXME. */
+int
+ld_main (int argc, char **argv, int standalone, struct ctimer *timer)
+{
+  int result;
+
+  /* Set global ld_timer.  */
+  ld_timer = timer;
+
+  result = ld_internal_main (argc, argv, standalone);
+  if (!standalone)
+    {
+      TIMER_PUSH ("ld_main cleanup");
+      ld_cleanup ();
+
+      /* TODO.  */
+      bfd_uninit ();
+
+      ldexp_c_finalize ();
+      ldlang_c_finalize ();
+      ldmain_c_finalize ();
+
+      /* FIXME: hardcoded.  */
+      gldelf_x86_64_finalize ();
+
+      TIMER_POP ();
+    }
+
+  /* Unset global ld_timer.  */
+  ld_timer = NULL;
+
+  return result;
+}
+
 /* If the configured sysroot is relocatable, try relocating it based on
    default prefix FROM.  Return the relocated directory if it exists,
    otherwise return null.  */
@@ -1486,3 +1547,27 @@ notice (struct bfd_link_info *info,
 
   return TRUE;
 }
+
+/* FIXME.  */
+static void ldmain_c_finalize (void)
+{
+  saved_script_handle = NULL;
+  previous_script_handle = NULL;
+  force_make_executable = FALSE;
+  default_target = NULL;
+  output_filename = "a.out";
+  program_name = NULL;
+  ld_sysroot = NULL;
+  ld_canon_sysroot = NULL;
+  ld_canon_sysroot_len = 0;
+  g_switch_value = 8;
+  trace_files = 0;
+  verbose = 0;
+  version_printed = 0;
+  CLEAR_VAR (command_line);
+  CLEAR_VAR (config);
+  sort_section = 0;
+  default_bfd_assert_handler = NULL;
+  CLEAR_VAR (link_info);
+  overflow_cutoff_limit = 10;
+}
diff --git a/ld/ldmainmain.c b/ld/ldmainmain.c
new file mode 100644
index 0000000..d897cd8
--- /dev/null
+++ b/ld/ldmainmain.c
@@ -0,0 +1,34 @@
+/* The entrypoint to the GNU linker.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "libiberty.h"
+#include "libld.h"
+
+/* FIXME.  */
+
+int
+main (int argc, char **argv)
+{
+  int result = ld_main (argc, argv, 1, NULL); /* standalone */
+  xexit (result);
+}
diff --git a/ld/lexsup.c b/ld/lexsup.c
index b618241..9cac4a7 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -527,6 +527,8 @@ static const struct ld_option ld_options[] =
 
 #define OPTION_COUNT ARRAY_SIZE (ld_options)
 
+static unsigned int defsym_count;
+
 void
 parse_args (unsigned argc, char **argv)
 {
@@ -635,12 +637,16 @@ parse_args (unsigned argc, char **argv)
 	}
     }
 
+  /* Reset internal state of getopt_long_only.  */
+  optind = 0;
+
+  defsym_count = 0;
+
   last_optind = -1;
   while (1)
     {
       int longind;
       int optc;
-      static unsigned int defsym_count;
 
       /* Using last_optind lets us avoid calling ldemul_parse_args
 	 multiple times on a single option, which would lead to
@@ -1584,6 +1590,10 @@ parse_args (unsigned argc, char **argv)
       if (link_info.discard == discard_sec_merge)
 	link_info.discard = discard_all;
     }
+
+  free (shortopts);
+  free (longopts);
+  free (really_longopts);
 }
 
 /* Add the (colon-separated) elements of DIRLIST_PTR to the
diff --git a/ld/libld.h b/ld/libld.h
new file mode 100644
index 0000000..9604ac9
--- /dev/null
+++ b/ld/libld.h
@@ -0,0 +1,41 @@
+/* API for the GNU linker.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of the GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#ifndef LIBLD_H
+#define LIBLD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ctimer;
+
+extern int
+ld_main (int argc,
+         char **argv,
+         int standalone,
+         struct ctimer *timer);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBLD_H) */
-- 
1.8.5.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]