ld relro
[platform/upstream/binutils.git] / ld / lexsup.c
index 71b426a..082a328 100644 (file)
@@ -1,7 +1,5 @@
 /* Parse options for the GNU linker.
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 1991-2014 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -40,6 +38,9 @@
 #include "ldver.h"
 #include "ldemul.h"
 #include "demangle.h"
+#ifdef ENABLE_PLUGINS
+#include "plugin.h"
+#endif /* ENABLE_PLUGINS */
 
 #ifndef PATH_SEPARATOR
 #if defined (__MSDOS__) || (defined (_WIN32) && ! defined (__CYGWIN32__))
@@ -59,116 +60,6 @@ static void set_section_start (char *, char *);
 static void set_segment_start (const char *, char *);
 static void help (void);
 
-/* Non-zero if we are processing a --defsym from the command line.  */
-int parsing_defsym = 0;
-
-/* Codes used for the long options with no short synonyms.  150 isn't
-   special; it's just an arbitrary non-ASCII char value.  */
-enum option_values
-{
-  OPTION_ASSERT = 150,
-  OPTION_CALL_SHARED,
-  OPTION_CREF,
-  OPTION_DEFSYM,
-  OPTION_DEMANGLE,
-  OPTION_DYNAMIC_LINKER,
-  OPTION_SYSROOT,
-  OPTION_EB,
-  OPTION_EL,
-  OPTION_EMBEDDED_RELOCS,
-  OPTION_EXPORT_DYNAMIC,
-  OPTION_NO_EXPORT_DYNAMIC,
-  OPTION_HELP,
-  OPTION_IGNORE,
-  OPTION_MAP,
-  OPTION_NO_DEMANGLE,
-  OPTION_NO_KEEP_MEMORY,
-  OPTION_NO_WARN_MISMATCH,
-  OPTION_NO_WARN_SEARCH_MISMATCH,
-  OPTION_NOINHIBIT_EXEC,
-  OPTION_NON_SHARED,
-  OPTION_NO_WHOLE_ARCHIVE,
-  OPTION_OFORMAT,
-  OPTION_RELAX,
-  OPTION_RETAIN_SYMBOLS_FILE,
-  OPTION_RPATH,
-  OPTION_RPATH_LINK,
-  OPTION_SHARED,
-  OPTION_SONAME,
-  OPTION_SORT_COMMON,
-  OPTION_SORT_SECTION,
-  OPTION_STATS,
-  OPTION_SYMBOLIC,
-  OPTION_SYMBOLIC_FUNCTIONS,
-  OPTION_TASK_LINK,
-  OPTION_TBSS,
-  OPTION_TDATA,
-  OPTION_TTEXT,
-  OPTION_TTEXT_SEGMENT,
-  OPTION_TRADITIONAL_FORMAT,
-  OPTION_UR,
-  OPTION_VERBOSE,
-  OPTION_VERSION,
-  OPTION_VERSION_SCRIPT,
-  OPTION_VERSION_EXPORTS_SECTION,
-  OPTION_DYNAMIC_LIST,
-  OPTION_DYNAMIC_LIST_CPP_NEW,
-  OPTION_DYNAMIC_LIST_CPP_TYPEINFO,
-  OPTION_DYNAMIC_LIST_DATA,
-  OPTION_WARN_COMMON,
-  OPTION_WARN_CONSTRUCTORS,
-  OPTION_WARN_FATAL,
-  OPTION_NO_WARN_FATAL,
-  OPTION_WARN_MULTIPLE_GP,
-  OPTION_WARN_ONCE,
-  OPTION_WARN_SECTION_ALIGN,
-  OPTION_SPLIT_BY_RELOC,
-  OPTION_SPLIT_BY_FILE ,
-  OPTION_WHOLE_ARCHIVE,
-  OPTION_ADD_DT_NEEDED_FOR_DYNAMIC,
-  OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC,
-  OPTION_ADD_DT_NEEDED_FOR_REGULAR,
-  OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR,
-  OPTION_WRAP,
-  OPTION_FORCE_EXE_SUFFIX,
-  OPTION_GC_SECTIONS,
-  OPTION_NO_GC_SECTIONS,
-  OPTION_PRINT_GC_SECTIONS,
-  OPTION_NO_PRINT_GC_SECTIONS,
-  OPTION_HASH_SIZE,
-  OPTION_CHECK_SECTIONS,
-  OPTION_NO_CHECK_SECTIONS,
-  OPTION_NO_UNDEFINED,
-  OPTION_INIT,
-  OPTION_FINI,
-  OPTION_SECTION_START,
-  OPTION_UNIQUE,
-  OPTION_TARGET_HELP,
-  OPTION_ALLOW_SHLIB_UNDEFINED,
-  OPTION_NO_ALLOW_SHLIB_UNDEFINED,
-  OPTION_ALLOW_MULTIPLE_DEFINITION,
-  OPTION_NO_UNDEFINED_VERSION,
-  OPTION_DEFAULT_SYMVER,
-  OPTION_DEFAULT_IMPORTED_SYMVER,
-  OPTION_DISCARD_NONE,
-  OPTION_SPARE_DYNAMIC_TAGS,
-  OPTION_NO_DEFINE_COMMON,
-  OPTION_NOSTDLIB,
-  OPTION_NO_OMAGIC,
-  OPTION_STRIP_DISCARDED,
-  OPTION_NO_STRIP_DISCARDED,
-  OPTION_ACCEPT_UNKNOWN_INPUT_ARCH,
-  OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH,
-  OPTION_PIE,
-  OPTION_UNRESOLVED_SYMBOLS,
-  OPTION_WARN_UNRESOLVED_SYMBOLS,
-  OPTION_ERROR_UNRESOLVED_SYMBOLS,
-  OPTION_WARN_SHARED_TEXTREL,
-  OPTION_WARN_ALTERNATE_EM,
-  OPTION_REDUCE_MEMORY_OVERHEADS,
-  OPTION_DEFAULT_SCRIPT
-};
-
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
 
@@ -270,6 +161,21 @@ static const struct ld_option ld_options[] =
     'o', N_("FILE"), N_("Set output file name"), EXACTLY_TWO_DASHES },
   { {NULL, required_argument, NULL, '\0'},
     'O', NULL, N_("Optimize output file"), ONE_DASH },
+#ifdef ENABLE_PLUGINS
+  { {"plugin", required_argument, NULL, OPTION_PLUGIN},
+    '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
+  { {"plugin-opt", required_argument, NULL, OPTION_PLUGIN_OPT},
+    '\0', N_("ARG"), N_("Send arg to last-loaded plugin"), ONE_DASH },
+  { {"flto", optional_argument, NULL, OPTION_IGNORE},
+    '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
+    ONE_DASH },
+  { {"flto-partition=", required_argument, NULL, OPTION_IGNORE},
+    '\0', NULL, N_("Ignored for GCC LTO option compatibility"),
+    ONE_DASH },
+#endif /* ENABLE_PLUGINS */
+  { {"fuse-ld=", required_argument, NULL, OPTION_IGNORE},
+    '\0', NULL, N_("Ignored for GCC linker option compatibility"),
+    ONE_DASH },
   { {"Qy", no_argument, NULL, OPTION_IGNORE},
     '\0', NULL, N_("Ignored for SVR4 compatibility"), ONE_DASH },
   { {"emit-relocs", no_argument, NULL, 'q'},
@@ -336,8 +242,7 @@ static const struct ld_option ld_options[] =
 
   /* The next two options are deprecated because of their similarity to
      --as-needed and --no-as-needed.  They have been replaced by
-     --resolve-implicit-dynamic-symbols and
-     --no-resolve-implicit-dynamic-symbols.  */
+     --copy-dt-needed-entries and --no-copy-dt-needed-entries.  */
   { {"add-needed", no_argument, NULL, OPTION_ADD_DT_NEEDED_FOR_DYNAMIC},
     '\0', NULL, NULL, NO_HELP },
   { {"no-add-needed", no_argument, NULL, OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC},
@@ -435,7 +340,7 @@ static const struct ld_option ld_options[] =
     '\0', NULL, N_("Do not allow unresolved references in object files"),
     TWO_DASHES },
   { {"allow-shlib-undefined", no_argument, NULL, OPTION_ALLOW_SHLIB_UNDEFINED},
-    '\0', NULL, N_("Allow unresolved references in shared libaries"),
+    '\0', NULL, N_("Allow unresolved references in shared libraries"),
     TWO_DASHES },
   { {"no-allow-shlib-undefined", no_argument, NULL,
      OPTION_NO_ALLOW_SHLIB_UNDEFINED},
@@ -472,6 +377,10 @@ static const struct ld_option ld_options[] =
   { {"oformat", required_argument, NULL, OPTION_OFORMAT},
     '\0', N_("TARGET"), N_("Specify target of output file"),
     EXACTLY_TWO_DASHES },
+  { {"print-output-format", no_argument, NULL, OPTION_PRINT_OUTPUT_FORMAT},
+    '\0', NULL, N_("Print default output format"), TWO_DASHES },
+  { {"print-sysroot", no_argument, NULL, OPTION_PRINT_SYSROOT},
+    '\0', NULL, N_("Print current sysroot"), TWO_DASHES },
   { {"qmagic", no_argument, NULL, OPTION_IGNORE},
     '\0', NULL, N_("Ignored for Linux compatibility"), ONE_DASH },
   { {"reduce-memory-overheads", no_argument, NULL,
@@ -479,7 +388,9 @@ static const struct ld_option ld_options[] =
     '\0', NULL, N_("Reduce memory overheads, possibly taking much longer"),
     TWO_DASHES },
   { {"relax", no_argument, NULL, OPTION_RELAX},
-    '\0', NULL, N_("Relax branches on certain targets"), TWO_DASHES },
+    '\0', NULL, N_("Reduce code size by using target specific optimizations"), TWO_DASHES },
+  { {"no-relax", no_argument, NULL, OPTION_NO_RELAX},
+    '\0', NULL, N_("Do not use relaxation techniques to reduce code size"), TWO_DASHES },
   { {"retain-symbols-file", required_argument, NULL,
      OPTION_RETAIN_SYMBOLS_FILE},
     '\0', N_("FILE"), N_("Keep only symbols listed in FILE"), TWO_DASHES },
@@ -497,13 +408,13 @@ static const struct ld_option ld_options[] =
   { {"pic-executable", no_argument, NULL, OPTION_PIE},
     '\0', NULL, NULL, TWO_DASHES },
   { {"sort-common", optional_argument, NULL, OPTION_SORT_COMMON},
-    '\0', N_("[=ascending|descending]"), 
-    N_("Sort common symbols by alignment [in specified order]"), 
+    '\0', N_("[=ascending|descending]"),
+    N_("Sort common symbols by alignment [in specified order]"),
     TWO_DASHES },
   { {"sort_common", no_argument, NULL, OPTION_SORT_COMMON},
     '\0', NULL, NULL, NO_HELP },
   { {"sort-section", required_argument, NULL, OPTION_SORT_SECTION},
-    '\0', N_("name|alignment"), 
+    '\0', N_("name|alignment"),
     N_("Sort sections by name or maximum alignment"), TWO_DASHES },
   { {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS},
     '\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"),
@@ -533,14 +444,19 @@ static const struct ld_option ld_options[] =
     '\0', N_("ADDRESS"), N_("Set address of .text section"), ONE_DASH },
   { {"Ttext-segment", required_argument, NULL, OPTION_TTEXT_SEGMENT},
     '\0', N_("ADDRESS"), N_("Set address of text segment"), ONE_DASH },
+  { {"Trodata-segment", required_argument, NULL, OPTION_TRODATA_SEGMENT},
+    '\0', N_("ADDRESS"), N_("Set address of rodata segment"), ONE_DASH },
+  { {"Tldata-segment", required_argument, NULL, OPTION_TLDATA_SEGMENT},
+    '\0', N_("ADDRESS"), N_("Set address of ldata segment"), ONE_DASH },
   { {"unresolved-symbols=<method>", required_argument, NULL,
      OPTION_UNRESOLVED_SYMBOLS},
     '\0', NULL, N_("How to handle unresolved symbols.  <method> is:\n"
                   "                                ignore-all, report-all, ignore-in-object-files,\n"
                   "                                ignore-in-shared-libs"),
     TWO_DASHES },
-  { {"verbose", no_argument, NULL, OPTION_VERBOSE},
-    '\0', NULL, N_("Output lots of information during link"), TWO_DASHES },
+  { {"verbose", optional_argument, NULL, OPTION_VERBOSE},
+    '\0', N_("[=NUMBER]"),
+    N_("Output lots of information during link"), TWO_DASHES },
   { {"dll-verbose", no_argument, NULL, OPTION_VERBOSE}, /* Linux.  */
     '\0', NULL, NULL, NO_HELP },
   { {"version-script", required_argument, NULL, OPTION_VERSION_SCRIPT },
@@ -587,6 +503,16 @@ static const struct ld_option ld_options[] =
     TWO_DASHES },
   { {"wrap", required_argument, NULL, OPTION_WRAP},
     '\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES },
+  { {"ignore-unresolved-symbol", required_argument, NULL,
+    OPTION_IGNORE_UNRESOLVED_SYMBOL},
+    '\0', N_("SYMBOL"),
+    N_("Unresolved SYMBOL will not cause an error or warning"), TWO_DASHES },
+  { {"push-state", no_argument, NULL, OPTION_PUSH_STATE},
+    '\0', NULL, N_("Push state of flags governing input file handling"),
+    TWO_DASHES },
+  { {"pop-state", no_argument, NULL, OPTION_POP_STATE},
+    '\0', NULL, N_("Pop state of flags governing input file handling"),
+    TWO_DASHES },
 };
 
 #define OPTION_COUNT ARRAY_SIZE (ld_options)
@@ -699,11 +625,15 @@ parse_args (unsigned argc, char **argv)
        }
     }
 
+  optarg = "relro";
+  ldemul_handle_option ('z');
+
   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
@@ -752,10 +682,10 @@ parse_args (unsigned argc, char **argv)
             ``use only shared libraries'' but, then, we don't
             currently support shared libraries on HP/UX anyhow.  */
          if (strcmp (optarg, "archive") == 0)
-           config.dynamic_link = FALSE;
+           input_flags.dynamic = FALSE;
          else if (strcmp (optarg, "shared") == 0
                   || strcmp (optarg, "default") == 0)
-           config.dynamic_link = TRUE;
+           input_flags.dynamic = TRUE;
          else
            einfo (_("%P%F: unrecognized -a option `%s'\n"), optarg);
          break;
@@ -784,10 +714,10 @@ parse_args (unsigned argc, char **argv)
          yyparse ();
          break;
        case OPTION_CALL_SHARED:
-         config.dynamic_link = TRUE;
+         input_flags.dynamic = TRUE;
          break;
        case OPTION_NON_SHARED:
-         config.dynamic_link = FALSE;
+         input_flags.dynamic = FALSE;
          break;
        case OPTION_CREF:
          command_line.cref = TRUE;
@@ -798,11 +728,9 @@ parse_args (unsigned argc, char **argv)
          break;
        case OPTION_DEFSYM:
          lex_string = optarg;
-         lex_redirect (optarg);
+         lex_redirect (optarg, "--defsym", ++defsym_count);
          parser_input = input_defsym;
-         parsing_defsym = 1;
          yyparse ();
-         parsing_defsym = 0;
          lex_string = NULL;
          break;
        case OPTION_DEMANGLE:
@@ -813,7 +741,7 @@ parse_args (unsigned argc, char **argv)
 
              style = cplus_demangle_name_to_style (optarg);
              if (style == unknown_demangling)
-               einfo (_("%F%P: unknown demangling style `%s'"),
+               einfo (_("%F%P: unknown demangling style `%s'\n"),
                       optarg);
 
              cplus_demangle_set_style (style);
@@ -913,17 +841,17 @@ parse_args (unsigned argc, char **argv)
        case 'N':
          config.text_read_only = FALSE;
          config.magic_demand_paged = FALSE;
-         config.dynamic_link = FALSE;
+         input_flags.dynamic = FALSE;
          break;
        case OPTION_NO_OMAGIC:
          config.text_read_only = TRUE;
          config.magic_demand_paged = TRUE;
-         /* NB/ Does not set dynamic_link to TRUE.
+         /* NB/ Does not set input_flags.dynamic to TRUE.
             Use --call-shared or -Bdynamic for this.  */
          break;
        case 'n':
          config.magic_demand_paged = FALSE;
-         config.dynamic_link = FALSE;
+         input_flags.dynamic = FALSE;
          break;
        case OPTION_NO_DEFINE_COMMON:
          command_line.inhibit_common_definition = TRUE;
@@ -1019,7 +947,7 @@ parse_args (unsigned argc, char **argv)
          config.only_cmd_line_lib_dirs = TRUE;
          break;
        case OPTION_NO_WHOLE_ARCHIVE:
-         whole_archive = FALSE;
+         input_flags.whole_archive = FALSE;
          break;
        case 'O':
          /* FIXME "-O<non-digits> <value>" used to set the address of
@@ -1037,6 +965,23 @@ parse_args (unsigned argc, char **argv)
        case OPTION_OFORMAT:
          lang_add_output_format (optarg, NULL, NULL, 0);
          break;
+       case OPTION_PRINT_SYSROOT:
+         if (*ld_sysroot)
+           puts (ld_sysroot);
+         xexit (0);
+         break;
+       case OPTION_PRINT_OUTPUT_FORMAT:
+         command_line.print_output_format = TRUE;
+         break;
+#ifdef ENABLE_PLUGINS
+       case OPTION_PLUGIN:
+         plugin_opt_plugin (optarg);
+         break;
+       case OPTION_PLUGIN_OPT:
+         if (plugin_opt_plugin_arg (optarg))
+           einfo(_("%P%F: bad -plugin-opt option\n"));
+         break;
+#endif /* ENABLE_PLUGINS */
        case 'q':
          link_info.emitrelocations = TRUE;
          break;
@@ -1057,7 +1002,7 @@ parse_args (unsigned argc, char **argv)
          config.build_constructors = FALSE;
          config.magic_demand_paged = FALSE;
          config.text_read_only = FALSE;
-         config.dynamic_link = FALSE;
+         input_flags.dynamic = FALSE;
          break;
        case 'R':
          /* The GNU linker traditionally uses -R to mean to include
@@ -1132,8 +1077,11 @@ parse_args (unsigned argc, char **argv)
              command_line.rpath_link = buf;
            }
          break;
+       case OPTION_NO_RELAX:
+         DISABLE_RELAXATION;
+         break;
        case OPTION_RELAX:
-         command_line.relax = TRUE;
+         ENABLE_RELAXATION;
          break;
        case OPTION_RETAIN_SYMBOLS_FILE:
          add_keepsyms_file (optarg);
@@ -1175,7 +1123,11 @@ parse_args (unsigned argc, char **argv)
          break;
        case 'h':               /* Used on Solaris.  */
        case OPTION_SONAME:
-         command_line.soname = optarg;
+         if (optarg[0] == '\0' && command_line.soname
+             && command_line.soname[0])
+           einfo (_("%P: SONAME must not be empty string; keeping previous one\n"));
+         else
+           command_line.soname = optarg;
          break;
        case OPTION_SORT_COMMON:
          if (optarg == NULL
@@ -1264,6 +1216,12 @@ parse_args (unsigned argc, char **argv)
        case OPTION_TTEXT_SEGMENT:
          set_segment_start (".text-segment", optarg);
          break;
+       case OPTION_TRODATA_SEGMENT:
+         set_segment_start (".rodata-segment", optarg);
+         break;
+       case OPTION_TLDATA_SEGMENT:
+         set_segment_start (".ldata-segment", optarg);
+         break;
        case OPTION_TRADITIONAL_FORMAT:
          link_info.traditional_format = TRUE;
          break;
@@ -1275,10 +1233,10 @@ parse_args (unsigned argc, char **argv)
          config.build_constructors = TRUE;
          config.magic_demand_paged = FALSE;
          config.text_read_only = FALSE;
-         config.dynamic_link = FALSE;
+         input_flags.dynamic = FALSE;
          break;
        case 'u':
-         ldlang_add_undef (optarg);
+         ldlang_add_undef (optarg, TRUE);
          break;
        case OPTION_UNIQUE:
          if (optarg != NULL)
@@ -1289,8 +1247,18 @@ parse_args (unsigned argc, char **argv)
        case OPTION_VERBOSE:
          ldversion (1);
          version_printed = TRUE;
-         trace_file_tries = TRUE;
+         verbose = TRUE;
          overflow_cutoff_limit = -2;
+         if (optarg != NULL)
+           {
+             char *end;
+             int level ATTRIBUTE_UNUSED = strtoul (optarg, &end, 0);
+             if (*end)
+               einfo (_("%P%F: invalid number `%s'\n"), optarg);
+#ifdef ENABLE_PLUGINS
+             report_plugin_symbols = level > 1;
+#endif /* ENABLE_PLUGINS */
+           }
          break;
        case 'v':
          ldversion (0);
@@ -1389,23 +1357,26 @@ parse_args (unsigned argc, char **argv)
          link_info.warn_alternate_em = TRUE;
          break;
        case OPTION_WHOLE_ARCHIVE:
-         whole_archive = TRUE;
+         input_flags.whole_archive = TRUE;
          break;
        case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC:
-         add_DT_NEEDED_for_dynamic = TRUE;
+         input_flags.add_DT_NEEDED_for_dynamic = TRUE;
          break;
        case OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC:
-         add_DT_NEEDED_for_dynamic = FALSE;
+         input_flags.add_DT_NEEDED_for_dynamic = FALSE;
          break;
        case OPTION_ADD_DT_NEEDED_FOR_REGULAR:
-         add_DT_NEEDED_for_regular = TRUE;
+         input_flags.add_DT_NEEDED_for_regular = TRUE;
          break;
        case OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR:
-         add_DT_NEEDED_for_regular = FALSE;
+         input_flags.add_DT_NEEDED_for_regular = FALSE;
          break;
        case OPTION_WRAP:
          add_wrap (optarg);
          break;
+       case OPTION_IGNORE_UNRESOLVED_SYMBOL:
+         add_ignoresym (&link_info, optarg);
+         break;
        case OPTION_DISCARD_NONE:
          link_info.discard = discard_none;
          break;
@@ -1453,18 +1424,15 @@ parse_args (unsigned argc, char **argv)
          command_line.accept_unknown_input_arch = FALSE;
          break;
        case '(':
-         if (ingroup)
-           einfo (_("%P%F: may not nest groups (--help for usage)\n"));
-
          lang_enter_group ();
-         ingroup = 1;
+         ingroup++;
          break;
        case ')':
          if (! ingroup)
            einfo (_("%P%F: group ended before it began (--help for usage)\n"));
 
          lang_leave_group ();
-         ingroup = 0;
+         ingroup--;
          break;
 
        case OPTION_INIT:
@@ -1492,11 +1460,37 @@ parse_args (unsigned argc, char **argv)
               einfo (_("%P%X: --hash-size needs a numeric argument\n"));
           }
           break;
+
+       case OPTION_PUSH_STATE:
+         input_flags.pushed = xmemdup (&input_flags,
+                                       sizeof (input_flags),
+                                       sizeof (input_flags));
+         break;
+
+       case OPTION_POP_STATE:
+         if (input_flags.pushed == NULL)
+           einfo (_("%P%F: no state pushed before popping\n"));
+         else
+           {
+             struct lang_input_statement_flags *oldp = input_flags.pushed;
+             memcpy (&input_flags, oldp, sizeof (input_flags));
+             free (oldp);
+           }
+         break;
        }
     }
 
-  if (ingroup)
-    lang_leave_group ();
+  if (command_line.soname && command_line.soname[0] == '\0')
+    {
+      einfo (_("%P: SONAME must not be empty string; ignored\n"));
+      command_line.soname = NULL;
+    }
+
+  while (ingroup)
+    {
+      lang_leave_group ();
+      ingroup--;
+    }
 
   if (default_dirlist != NULL)
     {
@@ -1511,6 +1505,72 @@ parse_args (unsigned argc, char **argv)
   if (link_info.unresolved_syms_in_shared_libs == RM_NOT_YET_SET)
     /* FIXME: Should we allow emulations a chance to set this ?  */
     link_info.unresolved_syms_in_shared_libs = how_to_report_unresolved_symbols;
+
+  if (link_info.relocatable)
+    {
+      if (command_line.check_section_addresses < 0)
+       command_line.check_section_addresses = 0;
+      if (link_info.shared)
+       einfo (_("%P%F: -r and -shared may not be used together\n"));
+    }
+
+  /* We may have -Bsymbolic, -Bsymbolic-functions, --dynamic-list-data,
+     --dynamic-list-cpp-new, --dynamic-list-cpp-typeinfo and
+     --dynamic-list FILE.  -Bsymbolic and -Bsymbolic-functions are
+     for shared libraries.  -Bsymbolic overrides all others and vice
+     versa.  */
+  switch (command_line.symbolic)
+    {
+    case symbolic_unset:
+      break;
+    case symbolic:
+      /* -Bsymbolic is for shared library only.  */
+      if (link_info.shared)
+       {
+         link_info.symbolic = TRUE;
+         /* Should we free the unused memory?  */
+         link_info.dynamic_list = NULL;
+         command_line.dynamic_list = dynamic_list_unset;
+       }
+      break;
+    case symbolic_functions:
+      /* -Bsymbolic-functions is for shared library only.  */
+      if (link_info.shared)
+       command_line.dynamic_list = dynamic_list_data;
+      break;
+    }
+
+  switch (command_line.dynamic_list)
+    {
+    case dynamic_list_unset:
+      break;
+    case dynamic_list_data:
+      link_info.dynamic_data = TRUE;
+    case dynamic_list:
+      link_info.dynamic = TRUE;
+      break;
+    }
+
+  if (! link_info.shared)
+    {
+      if (command_line.filter_shlib)
+       einfo (_("%P%F: -F may not be used without -shared\n"));
+      if (command_line.auxiliary_filters)
+       einfo (_("%P%F: -f may not be used without -shared\n"));
+    }
+
+  if (! link_info.shared || link_info.pie)
+    link_info.executable = TRUE;
+
+  /* Treat ld -r -s as ld -r -S -x (i.e., strip all local symbols).  I
+     don't see how else this can be handled, since in this case we
+     must preserve all externally visible symbols.  */
+  if (link_info.relocatable && link_info.strip == strip_all)
+    {
+      link_info.strip = strip_debugger;
+      if (link_info.discard == discard_sec_merge)
+       link_info.discard = discard_all;
+    }
 }
 
 /* Add the (colon-separated) elements of DIRLIST_PTR to the