Ejemplo n.º 1
0
static bool translate_addresses(bfd *abfd, const char *addr,
                                addr2line_data *adata) {
    if (!abfd) return false;
    adata->pc = bfd_scan_vma(addr, nullptr, 16);

    adata->found = FALSE;
    bfd_map_over_sections(abfd, find_address_in_section, adata);

    if (!adata->found || !adata->functionname || !*adata->functionname) {
        return false;
    }
    return true;
}
Ejemplo n.º 2
0
int BFDmanager_translateAddress (bfd *bfdImage, asymbol **bfdSymbols,
	void *address, char **function, char **file, int *line)
{
	BFDmanager_symbolInfo_t syminfo;
	char caddress[32];

#if defined(DEBUG)
	printf ("DEBUG: BFDmanager_translateAddress (%p, %p, address = %p)\n", bfdImage, bfdSymbols, address);
#endif

	syminfo.found = FALSE;

	if (bfdImage && bfdSymbols)
	{
		/* Convert the address into hexadecimal string format */
		sprintf (caddress, "%p", address);

		/* Prepare the query for BFD */
		syminfo.pc = bfd_scan_vma (caddress, NULL, 16);
		syminfo.symbols = bfdSymbols;

		/* Iterate through sections of the given bfd image */
		bfd_map_over_sections (bfdImage, BFDmanager_findAddressInSection, &syminfo);

		/* Found the symbol ? If so, copy the data */
		if (syminfo.found)
		{
			char *demangled = NULL;
			*file = (char*) syminfo.filename;
			*line = syminfo.line;

#if defined(HAVE_BFD_DEMANGLE)
			if (syminfo.function)
				demangled = bfd_demangle (bfdImage, syminfo.function, 0);

			if (demangled)
				*function = demangled;
			else
				*function = (char*) syminfo.function;
#else
			*function = (char*) syminfo.function;
#endif
		}
	}

	return syminfo.found;
}
Ejemplo n.º 3
0
void
parse_args (unsigned argc, char **argv)
{
  unsigned i;
  int is, il, irl;
  int ingroup = 0;
  char *default_dirlist = NULL;
  char *shortopts;
  struct option *longopts;
  struct option *really_longopts;
  int last_optind;
  enum report_method how_to_report_unresolved_symbols = RM_GENERATE_ERROR;

  shortopts = xmalloc (OPTION_COUNT * 3 + 2);
  longopts = xmalloc (sizeof (*longopts) * (OPTION_COUNT + 1));
  really_longopts = xmalloc (sizeof (*really_longopts) * (OPTION_COUNT + 1));

  /* Starting the short option string with '-' is for programs that
     expect options and other ARGV-elements in any order and that care about
     the ordering of the two.  We describe each non-option ARGV-element
     as if it were the argument of an option with character code 1.  */
  shortopts[0] = '-';
  is = 1;
  il = 0;
  irl = 0;
  for (i = 0; i < OPTION_COUNT; i++)
    {
      if (ld_options[i].shortopt != '\0')
	{
	  shortopts[is] = ld_options[i].shortopt;
	  ++is;
	  if (ld_options[i].opt.has_arg == required_argument
	      || ld_options[i].opt.has_arg == optional_argument)
	    {
	      shortopts[is] = ':';
	      ++is;
	      if (ld_options[i].opt.has_arg == optional_argument)
		{
		  shortopts[is] = ':';
		  ++is;
		}
	    }
	}
      if (ld_options[i].opt.name != NULL)
	{
	  if (ld_options[i].control == EXACTLY_TWO_DASHES)
	    {
	      really_longopts[irl] = ld_options[i].opt;
	      ++irl;
	    }
	  else
	    {
	      longopts[il] = ld_options[i].opt;
	      ++il;
	    }
	}
    }
  shortopts[is] = '\0';
  longopts[il].name = NULL;
  really_longopts[irl].name = NULL;

  ldemul_add_options (is, &shortopts, il, &longopts, irl, &really_longopts);

  /* The -G option is ambiguous on different platforms.  Sometimes it
     specifies the largest data size to put into the small data
     section.  Sometimes it is equivalent to --shared.  Unfortunately,
     the first form takes an argument, while the second does not.

     We need to permit the --shared form because on some platforms,
     such as Solaris, gcc -shared will pass -G to the linker.

     To permit either usage, we look through the argument list.  If we
     find -G not followed by a number, we change it into --shared.
     This will work for most normal cases.  */
  for (i = 1; i < argc; i++)
    if (strcmp (argv[i], "-G") == 0
	&& (i + 1 >= argc
	    || ! ISDIGIT (argv[i + 1][0])))
      argv[i] = (char *) "--shared";

  /* Because we permit long options to start with a single dash, and
     we have a --library option, and the -l option is conventionally
     used with an immediately following argument, we can have bad
     results if somebody tries to use -l with a library whose name
     happens to start with "ibrary", as in -li.  We avoid problems by
     simply turning -l into --library.  This means that users will
     have to use two dashes in order to use --library, which is OK
     since that's how it is documented.

     FIXME: It's possible that this problem can arise for other short
     options as well, although the user does always have the recourse
     of adding a space between the option and the argument.  */
  for (i = 1; i < argc; i++)
    {
      if (argv[i][0] == '-'
	  && argv[i][1] == 'l'
	  && argv[i][2] != '\0')
	{
	  char *n;

	  n = xmalloc (strlen (argv[i]) + 20);
	  sprintf (n, "--library=%s", argv[i] + 2);
	  argv[i] = n;
	}
    }

  last_optind = -1;
  while (1)
    {
      int longind;
      int optc;

      /* Using last_optind lets us avoid calling ldemul_parse_args
	 multiple times on a single option, which would lead to
	 confusion in the internal static variables maintained by
	 getopt.  This could otherwise happen for an argument like
	 -nx, in which the -n is parsed as a single option, and we
	 loop around to pick up the -x.  */
      if (optind != last_optind)
	if (ldemul_parse_args (argc, argv))
	  continue;

      /* getopt_long_only is like getopt_long, but '-' as well as '--'
	 can indicate a long option.  */
      opterr = 0;
      last_optind = optind;
      optc = getopt_long_only (argc, argv, shortopts, longopts, &longind);
      if (optc == '?')
	{
	  optind = last_optind;
	  optc = getopt_long (argc, argv, "-", really_longopts, &longind);
	}

      if (ldemul_handle_option (optc))
	continue;

      if (optc == -1)
	break;

      switch (optc)
	{
	case '?':
	  einfo (_("%P: unrecognized option '%s'\n"), argv[last_optind]);
	default:
	  einfo (_("%P%F: use the --help option for usage information\n"));

	case 1:			/* File name.  */
	  lang_add_input_file (optarg, lang_input_file_is_file_enum, NULL);
	  break;

	case OPTION_IGNORE:
	  break;
	case 'a':
	  /* For HP/UX compatibility.  Actually -a shared should mean
	     ``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;
	  else if (strcmp (optarg, "shared") == 0
		   || strcmp (optarg, "default") == 0)
	    config.dynamic_link = TRUE;
	  else
	    einfo (_("%P%F: unrecognized -a option `%s'\n"), optarg);
	  break;
	case OPTION_ASSERT:
	  /* FIXME: We just ignore these, but we should handle them.  */
	  if (strcmp (optarg, "definitions") == 0)
	    ;
	  else if (strcmp (optarg, "nodefinitions") == 0)
	    ;
	  else if (strcmp (optarg, "nosymbolic") == 0)
	    ;
	  else if (strcmp (optarg, "pure-text") == 0)
	    ;
	  else
	    einfo (_("%P%F: unrecognized -assert option `%s'\n"), optarg);
	  break;
	case 'A':
	  ldfile_add_arch (optarg);
	  break;
	case 'b':
	  lang_add_target (optarg);
	  break;
	case 'c':
	  ldfile_open_command_file (optarg);
	  parser_input = input_mri_script;
	  yyparse ();
	  break;
	case OPTION_CALL_SHARED:
	  config.dynamic_link = TRUE;
	  break;
	case OPTION_NON_SHARED:
	  config.dynamic_link = FALSE;
	  break;
	case OPTION_CREF:
	  command_line.cref = TRUE;
	  link_info.notice_all = TRUE;
	  break;
	case 'd':
	  command_line.force_common_definition = TRUE;
	  break;
	case OPTION_DEFSYM:
	  lex_string = optarg;
	  lex_redirect (optarg);
	  parser_input = input_defsym;
	  parsing_defsym = 1;
	  yyparse ();
	  parsing_defsym = 0;
	  lex_string = NULL;
	  break;
	case OPTION_DEMANGLE:
	  demangling = TRUE;
	  if (optarg != NULL)
	    {
	      enum demangling_styles style;

	      style = cplus_demangle_name_to_style (optarg);
	      if (style == unknown_demangling)
		einfo (_("%F%P: unknown demangling style `%s'"),
		       optarg);

	      cplus_demangle_set_style (style);
	    }
	  break;
	case 'I':		/* Used on Solaris.  */
	case OPTION_DYNAMIC_LINKER:
	  command_line.interpreter = optarg;
	  break;
	case OPTION_EB:
	  command_line.endian = ENDIAN_BIG;
	  break;
	case OPTION_EL:
	  command_line.endian = ENDIAN_LITTLE;
	  break;
	case OPTION_EMBEDDED_RELOCS:
	  command_line.embedded_relocs = TRUE;
	  break;
	case OPTION_EXPORT_DYNAMIC:
	case 'E': /* HP/UX compatibility.  */
	  link_info.export_dynamic = TRUE;
	  break;
	case 'e':
	  lang_add_entry (optarg, TRUE);
	  break;
	case 'f':
	  if (command_line.auxiliary_filters == NULL)
	    {
	      command_line.auxiliary_filters = xmalloc (2 * sizeof (char *));
	      command_line.auxiliary_filters[0] = optarg;
	      command_line.auxiliary_filters[1] = NULL;
	    }
	  else
	    {
	      int c;
	      char **p;

	      c = 0;
	      for (p = command_line.auxiliary_filters; *p != NULL; p++)
		++c;
	      command_line.auxiliary_filters
		= xrealloc (command_line.auxiliary_filters,
			    (c + 2) * sizeof (char *));
	      command_line.auxiliary_filters[c] = optarg;
	      command_line.auxiliary_filters[c + 1] = NULL;
	    }
	  break;
	case 'F':
	  command_line.filter_shlib = optarg;
	  break;
	case OPTION_FORCE_EXE_SUFFIX:
	  command_line.force_exe_suffix = TRUE;
	  break;
	case 'G':
	  {
	    char *end;
	    g_switch_value = strtoul (optarg, &end, 0);
	    if (*end)
	      einfo (_("%P%F: invalid number `%s'\n"), optarg);
	  }
	  break;
	case 'g':
	  /* Ignore.  */
	  break;
	case OPTION_GC_SECTIONS:
	  command_line.gc_sections = TRUE;
	  break;
	case OPTION_HELP:
	  help ();
	  xexit (0);
	  break;
	case 'L':
	  ldfile_add_library_path (optarg, TRUE);
	  break;
	case 'l':
	  lang_add_input_file (optarg, lang_input_file_is_l_enum, NULL);
	  break;
	case 'M':
	  config.map_filename = "-";
	  break;
	case 'm':
	  /* Ignore.  Was handled in a pre-parse.   */
	  break;
	case OPTION_MAP:
	  config.map_filename = optarg;
	  break;
	case 'N':
	  config.text_read_only = FALSE;
	  config.magic_demand_paged = FALSE;
	  config.dynamic_link = FALSE;
	  break;
	case OPTION_NO_OMAGIC:
	  config.text_read_only = TRUE;
	  config.magic_demand_paged = TRUE;
	  /* NB/ Does not set dynamic_link to TRUE.
	     Use --call-shared or -Bdynamic for this.  */
	  break;
	case 'n':
	  config.magic_demand_paged = FALSE;
	  config.dynamic_link = FALSE;
	  break;
	case OPTION_NO_DEFINE_COMMON:
	  command_line.inhibit_common_definition = TRUE;
	  break;
	case OPTION_NO_DEMANGLE:
	  demangling = FALSE;
	  break;
	case OPTION_NO_GC_SECTIONS:
	  command_line.gc_sections = FALSE;
	  break;
	case OPTION_NO_KEEP_MEMORY:
	  link_info.keep_memory = FALSE;
	  break;
	case OPTION_NO_UNDEFINED:
	  link_info.unresolved_syms_in_objects = how_to_report_unresolved_symbols;
	  break;
	case OPTION_ALLOW_SHLIB_UNDEFINED:
	  link_info.unresolved_syms_in_shared_libs = RM_IGNORE;
	  break;
	case OPTION_NO_ALLOW_SHLIB_UNDEFINED:
	  link_info.unresolved_syms_in_shared_libs = how_to_report_unresolved_symbols;
	  break;
	case OPTION_UNRESOLVED_SYMBOLS:
	  if (strcmp (optarg, "ignore-all") == 0)
	    {
	      link_info.unresolved_syms_in_objects = RM_IGNORE;
	      link_info.unresolved_syms_in_shared_libs = RM_IGNORE;
	    }
	  else if (strcmp (optarg, "report-all") == 0)
	    {
	      link_info.unresolved_syms_in_objects = how_to_report_unresolved_symbols;
	      link_info.unresolved_syms_in_shared_libs = how_to_report_unresolved_symbols;
	    }
	  else if (strcmp (optarg, "ignore-in-object-files") == 0)
	    {
	      link_info.unresolved_syms_in_objects = RM_IGNORE;
	      link_info.unresolved_syms_in_shared_libs = how_to_report_unresolved_symbols;
	    }
      	  else if (strcmp (optarg, "ignore-in-shared-libs") == 0)
	    {
	      link_info.unresolved_syms_in_objects = how_to_report_unresolved_symbols;
	      link_info.unresolved_syms_in_shared_libs = RM_IGNORE;
	    }
	  else
	    einfo (_("%P%F: bad --unresolved-symbols option: %s\n"), optarg);
	  break;
	case OPTION_WARN_UNRESOLVED_SYMBOLS:
	  how_to_report_unresolved_symbols = RM_GENERATE_WARNING;
	  if (link_info.unresolved_syms_in_objects == RM_GENERATE_ERROR)
	    link_info.unresolved_syms_in_objects = RM_GENERATE_WARNING;
	  if (link_info.unresolved_syms_in_shared_libs == RM_GENERATE_ERROR)
	    link_info.unresolved_syms_in_shared_libs = RM_GENERATE_WARNING;
	  break;
	  
	case OPTION_ERROR_UNRESOLVED_SYMBOLS:
	  how_to_report_unresolved_symbols = RM_GENERATE_ERROR;
	  if (link_info.unresolved_syms_in_objects == RM_GENERATE_WARNING)
	    link_info.unresolved_syms_in_objects = RM_GENERATE_ERROR;
	  if (link_info.unresolved_syms_in_shared_libs == RM_GENERATE_WARNING)
	    link_info.unresolved_syms_in_shared_libs = RM_GENERATE_ERROR;
	  break;	  
	case OPTION_ALLOW_MULTIPLE_DEFINITION:
	  link_info.allow_multiple_definition = TRUE;
	  break;
	case OPTION_NO_UNDEFINED_VERSION:
	  link_info.allow_undefined_version = FALSE;
	  break;
	case OPTION_NO_WARN_MISMATCH:
	  command_line.warn_mismatch = FALSE;
	  break;
	case OPTION_NOINHIBIT_EXEC:
	  force_make_executable = TRUE;
	  break;
	case OPTION_NOSTDLIB:
	  config.only_cmd_line_lib_dirs = TRUE;
	  break;
	case OPTION_NO_WHOLE_ARCHIVE:
	  whole_archive = FALSE;
	  break;
	case 'O':
	  /* FIXME "-O<non-digits> <value>" used to set the address of
	     section <non-digits>.  Was this for compatibility with
	     something, or can we create a new option to do that
	     (with a syntax similar to -defsym)?
	     getopt can't handle two args to an option without kludges.  */

	  /* Enable optimizations of output files.  */
	  link_info.optimize = strtoul (optarg, NULL, 0) ? TRUE : FALSE;
	  break;
	case 'o':
	  lang_add_output (optarg, 0);
	  break;
	case OPTION_OFORMAT:
	  lang_add_output_format (optarg, NULL, NULL, 0);
	  break;
	case 'q':
	  link_info.emitrelocations = TRUE;
	  break;
	case 'i':
	case 'r':
	  if (optind == last_optind)
	    /* This can happen if the user put "-rpath,a" on the command
	       line.  (Or something similar.  The comma is important).
	       Getopt becomes confused and thinks that this is a -r option
	       but it cannot parse the text after the -r so it refuses to
	       increment the optind counter.  Detect this case and issue
	       an error message here.  We cannot just make this a warning,
	       increment optind, and continue because getopt is too confused
	       and will seg-fault the next time around.  */
	    einfo(_("%P%F: bad -rpath option\n"));

	  link_info.relocatable = TRUE;
	  config.build_constructors = FALSE;
	  config.magic_demand_paged = FALSE;
	  config.text_read_only = FALSE;
	  config.dynamic_link = FALSE;
	  break;
	case 'R':
	  /* The GNU linker traditionally uses -R to mean to include
	     only the symbols from a file.  The Solaris linker uses -R
	     to set the path used by the runtime linker to find
	     libraries.  This is the GNU linker -rpath argument.  We
	     try to support both simultaneously by checking the file
	     named.  If it is a directory, rather than a regular file,
	     we assume -rpath was meant.  */
	  {
	    struct stat s;

	    if (stat (optarg, &s) >= 0
		&& ! S_ISDIR (s.st_mode))
	      {
		lang_add_input_file (optarg,
				     lang_input_file_is_symbols_only_enum,
				     NULL);
		break;
	      }
	  }
	  /* Fall through.  */
	case OPTION_RPATH:
	  if (command_line.rpath == NULL)
	    command_line.rpath = xstrdup (optarg);
	  else
	    {
	      size_t rpath_len = strlen (command_line.rpath);
	      size_t optarg_len = strlen (optarg);
	      char *buf;
	      char *cp = command_line.rpath;

	      /* First see whether OPTARG is already in the path.  */
	      do
		{
		  size_t idx = 0;

		  while (optarg[idx] != '\0' && optarg[idx] == cp[idx])
		    ++idx;
		  if (optarg[idx] == '\0'
		      && (cp[idx] == '\0' || cp[idx] == ':'))
		    /* We found it.  */
		    break;

		  /* Not yet found.  */
		  cp = strchr (cp, ':');
		  if (cp != NULL)
		    ++cp;
		}
	      while (cp != NULL);

	      if (cp == NULL)
		{
		  buf = xmalloc (rpath_len + optarg_len + 2);
		  sprintf (buf, "%s:%s", command_line.rpath, optarg);
		  free (command_line.rpath);
		  command_line.rpath = buf;
		}
	    }
	  break;
	case OPTION_RPATH_LINK:
	  if (command_line.rpath_link == NULL)
	    command_line.rpath_link = xstrdup (optarg);
	  else
	    {
	      char *buf;

	      buf = xmalloc (strlen (command_line.rpath_link)
			     + strlen (optarg)
			     + 2);
	      sprintf (buf, "%s:%s", command_line.rpath_link, optarg);
	      free (command_line.rpath_link);
	      command_line.rpath_link = buf;
	    }
	  break;
	case OPTION_RELAX:
	  command_line.relax = TRUE;
	  break;
	case OPTION_RETAIN_SYMBOLS_FILE:
	  add_keepsyms_file (optarg);
	  break;
	case 'S':
	  link_info.strip = strip_debugger;
	  break;
	case 's':
	  link_info.strip = strip_all;
	  break;
	case OPTION_STRIP_DISCARDED:
	  link_info.strip_discarded = TRUE;
	  break;
	case OPTION_NO_STRIP_DISCARDED:
	  link_info.strip_discarded = FALSE;
	  break;
	case OPTION_SHARED:
	  if (config.has_shared)
	    {
	      link_info.shared = TRUE;
	      /* When creating a shared library, the default
		 behaviour is to ignore any unresolved references.  */
	      if (link_info.unresolved_syms_in_objects == RM_NOT_YET_SET)
		link_info.unresolved_syms_in_objects = RM_IGNORE;
	      if (link_info.unresolved_syms_in_shared_libs == RM_NOT_YET_SET)
		link_info.unresolved_syms_in_shared_libs = RM_IGNORE;
	    }
	  else
	    einfo (_("%P%F: -shared not supported\n"));
	  break;
	case OPTION_PIE:
	  if (config.has_shared)
	    {
	      link_info.shared = TRUE;
	      link_info.pie = TRUE;
	    }
	  else
	    einfo (_("%P%F: -pie not supported\n"));
	  break;
	case 'h':		/* Used on Solaris.  */
	case OPTION_SONAME:
	  command_line.soname = optarg;
	  break;
	case OPTION_SORT_COMMON:
	  config.sort_common = TRUE;
	  break;
	case OPTION_STATS:
	  config.stats = TRUE;
	  break;
	case OPTION_SYMBOLIC:
	  link_info.symbolic = TRUE;
	  break;
	case 't':
	  trace_files = TRUE;
	  break;
	case 'T':
	  ldfile_open_command_file (optarg);
	  parser_input = input_script;
	  yyparse ();
	  break;
	case OPTION_SECTION_START:
	  {
	    char *optarg2;
	    char *sec_name;
	    int len;

	    /* Check for <something>=<somthing>...  */
	    optarg2 = strchr (optarg, '=');
	    if (optarg2 == NULL)
	      einfo (_("%P%F: invalid argument to option \"--section-start\"\n"));

	    optarg2++;

	    /* So far so good.  Are all the args present?  */
	    if ((*optarg == '\0') || (*optarg2 == '\0'))
	      einfo (_("%P%F: missing argument(s) to option \"--section-start\"\n"));

	    /* We must copy the section name as set_section_start
	       doesn't do it for us.  */
	    len = optarg2 - optarg;
	    sec_name = xmalloc (len);
	    memcpy (sec_name, optarg, len - 1);
	    sec_name[len - 1] = 0;

	    /* Then set it...  */
	    set_section_start (sec_name, optarg2);
	  }
	  break;
	case OPTION_TARGET_HELP:
	  /* Mention any target specific options.  */
	  ldemul_list_emulation_options (stdout);
	  exit (0);
	case OPTION_TBSS:
	  set_section_start (".bss", optarg);
	  break;
	case OPTION_TDATA:
	  set_section_start (".data", optarg);
	  break;
	case OPTION_TTEXT:
	  set_section_start (".text", optarg);
	  break;
	case OPTION_TRADITIONAL_FORMAT:
	  link_info.traditional_format = TRUE;
	  break;
	case OPTION_TASK_LINK:
	  link_info.task_link = TRUE;
	  /* Fall through - do an implied -r option.  */
	case OPTION_UR:
	  link_info.relocatable = TRUE;
	  config.build_constructors = TRUE;
	  config.magic_demand_paged = FALSE;
	  config.text_read_only = FALSE;
	  config.dynamic_link = FALSE;
	  break;
	case 'u':
	  ldlang_add_undef (optarg);
	  break;
	case OPTION_UNIQUE:
	  if (optarg != NULL)
	    lang_add_unique (optarg);
	  else
	    config.unique_orphan_sections = TRUE;
	  break;
	case OPTION_VERBOSE:
	  ldversion (1);
	  version_printed = TRUE;
	  trace_file_tries = TRUE;
	  overflow_cutoff_limit = -2;
	  break;
	case 'v':
	  ldversion (0);
	  version_printed = TRUE;
	  break;
	case 'V':
	  ldversion (1);
	  version_printed = TRUE;
	  break;
	case OPTION_VERSION:
	  ldversion (2);
	  xexit (0);
	  break;
	case OPTION_VERSION_SCRIPT:
	  /* This option indicates a small script that only specifies
	     version information.  Read it, but don't assume that
	     we've seen a linker script.  */
	  {
	    FILE *hold_script_handle;

	    hold_script_handle = saved_script_handle;
	    ldfile_open_command_file (optarg);
	    saved_script_handle = hold_script_handle;
	    parser_input = input_version_script;
	    yyparse ();
	  }
	  break;
	case OPTION_VERSION_EXPORTS_SECTION:
	  /* This option records a version symbol to be applied to the
	     symbols listed for export to be found in the object files
	     .exports sections.  */
	  command_line.version_exports_section = optarg;
	  break;
	case OPTION_WARN_COMMON:
	  config.warn_common = TRUE;
	  break;
	case OPTION_WARN_CONSTRUCTORS:
	  config.warn_constructors = TRUE;
	  break;
	case OPTION_WARN_FATAL:
	  config.fatal_warnings = TRUE;
	  break;
	case OPTION_WARN_MULTIPLE_GP:
	  config.warn_multiple_gp = TRUE;
	  break;
	case OPTION_WARN_ONCE:
	  config.warn_once = TRUE;
	  break;
	case OPTION_WARN_SECTION_ALIGN:
	  config.warn_section_align = TRUE;
	  break;
	case OPTION_WHOLE_ARCHIVE:
	  whole_archive = TRUE;
	  break;
	case OPTION_AS_NEEDED:
	  as_needed = TRUE;
	  break;
	case OPTION_NO_AS_NEEDED:
	  as_needed = FALSE;
	  break;
	case OPTION_WRAP:
	  add_wrap (optarg);
	  break;
	case OPTION_DISCARD_NONE:
	  link_info.discard = discard_none;
	  break;
	case 'X':
	  link_info.discard = discard_l;
	  break;
	case 'x':
	  link_info.discard = discard_all;
	  break;
	case 'Y':
	  if (strncmp (optarg, "P,", 2) == 0)
	    optarg += 2;
	  if (default_dirlist != NULL)
	    free (default_dirlist);
	  default_dirlist = xstrdup (optarg);
	  break;
	case 'y':
	  add_ysym (optarg);
	  break;
	case OPTION_SPARE_DYNAMIC_TAGS:
	  link_info.spare_dynamic_tags = strtoul (optarg, NULL, 0);
	  break;
	case OPTION_SPLIT_BY_RELOC:
	  if (optarg != NULL)
	    config.split_by_reloc = strtoul (optarg, NULL, 0);
	  else
	    config.split_by_reloc = 32768;
	  break;
	case OPTION_SPLIT_BY_FILE:
	  if (optarg != NULL)
	    config.split_by_file = bfd_scan_vma (optarg, NULL, 0);
	  else
	    config.split_by_file = 1;
	  break;
	case OPTION_CHECK_SECTIONS:
	  command_line.check_section_addresses = TRUE;
	  break;
	case OPTION_NO_CHECK_SECTIONS:
	  command_line.check_section_addresses = FALSE;
	  break;
	case OPTION_ACCEPT_UNKNOWN_INPUT_ARCH:
	  command_line.accept_unknown_input_arch = TRUE;
	  break;
	case OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH:
	  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;
	  break;
	case ')':
	  if (! ingroup)
	    einfo (_("%P%F: group ended before it began (--help for usage)\n"));

	  lang_leave_group ();
	  ingroup = 0;
	  break;

	case OPTION_INIT:
	  link_info.init_function = optarg;
	  break;

	case OPTION_FINI:
	  link_info.fini_function = optarg;
	  break;
	}
    }

  if (ingroup)
    lang_leave_group ();

  if (default_dirlist != NULL)
    {
      set_default_dirlist (default_dirlist);
      free (default_dirlist);
    }

  if (link_info.unresolved_syms_in_objects == RM_NOT_YET_SET)
    /* FIXME: Should we allow emulations a chance to set this ?  */
    link_info.unresolved_syms_in_objects = how_to_report_unresolved_symbols;
  
  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;
}