예제 #1
0
bfd_boolean
ldfile_open_file_search (const char *arch,
			 lang_input_statement_type *entry,
			 const char *lib,
			 const char *suffix)
{
  search_dirs_type *search;

  /* If this is not an archive, try to open it in the current
     directory first.  */
  if (! entry->flags.maybe_archive)
    {
      if (entry->flags.sysrooted && IS_ABSOLUTE_PATH (entry->filename))
	{
	  char *name = concat (ld_sysroot, entry->filename,
			       (const char *) NULL);
	  if (ldfile_try_open_bfd (name, entry))
	    {
	      entry->filename = name;
	      return TRUE;
	    }
	  free (name);
	}
      else if (ldfile_try_open_bfd (entry->filename, entry))
	return TRUE;

      if (IS_ABSOLUTE_PATH (entry->filename))
	return FALSE;
    }

  for (search = search_head; search != NULL; search = search->next)
    {
      char *string;

      if (entry->flags.dynamic && !bfd_link_relocatable (&link_info))
	{
	  if (ldemul_open_dynamic_archive (arch, search, entry))
	    return TRUE;
	}

      if (entry->flags.maybe_archive && !entry->flags.full_name_provided)
	string = concat (search->name, slash, lib, entry->filename,
			 arch, suffix, (const char *) NULL);
      else
	string = concat (search->name, slash, entry->filename,
			 (const char *) 0);

      if (ldfile_try_open_bfd (string, entry))
	{
	  entry->filename = string;
	  return TRUE;
	}

      free (string);
    }

  return FALSE;
}
예제 #2
0
/* Return TRUE if a defined symbol might be reachable from outside the
   universe of claimed objects.  */
static inline bfd_boolean
is_visible_from_outside (struct ld_plugin_symbol *lsym,
                         struct bfd_link_hash_entry *blhe)
{
    struct bfd_sym_chain *sym;

    if (bfd_link_relocatable (&link_info))
        return TRUE;
    if (link_info.export_dynamic || bfd_link_dll (&link_info))
    {
        /* Check if symbol is hidden by version script.  */
        if (bfd_hide_sym_by_version (link_info.version_info,
                                     blhe->root.string))
            return FALSE;
        /* Only ELF symbols really have visibility.  */
        if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
        {
            struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
            int vis = ELF_ST_VISIBILITY (el->other);
            return vis == STV_DEFAULT || vis == STV_PROTECTED;
        }
        /* On non-ELF targets, we can safely make inferences by considering
        what visibility the plugin would have liked to apply when it first
         sent us the symbol.  During ELF symbol processing, visibility only
         ever becomes more restrictive, not less, when symbols are merged,
         so this is a conservative estimate; it may give false positives,
         declaring something visible from outside when it in fact would
         not have been, but this will only lead to missed optimisation
         opportunities during LTRANS at worst; it will not give false
         negatives, which can lead to the disastrous conclusion that the
         related symbol is IRONLY.  (See GCC PR46319 for an example.)  */
        return (lsym->visibility == LDPV_DEFAULT
                || lsym->visibility == LDPV_PROTECTED);
    }

    for (sym = &entry_symbol; sym != NULL; sym = sym->next)
        if (sym->name
                && strcmp (sym->name, blhe->root.string) == 0)
            return TRUE;

    return FALSE;
}
예제 #3
0
파일: reloc16.c 프로젝트: ChrisG0x20/gdb
bfd_boolean
bfd_coff_reloc16_relax_section (bfd *abfd,
				asection *input_section,
				struct bfd_link_info *link_info,
				bfd_boolean *again)
{
  /* Get enough memory to hold the stuff.  */
  bfd *input_bfd = input_section->owner;
  unsigned *shrinks;
  unsigned shrink = 0;
  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  arelent **reloc_vector = NULL;
  long reloc_count;

  if (bfd_link_relocatable (link_info))
    (*link_info->callbacks->einfo)
      (_("%P%F: --relax and -r may not be used together\n"));

  /* We only do global relaxation once.  It is not safe to do it multiple
     times (see discussion of the "shrinks" array below).  */
  *again = FALSE;

  if (reloc_size < 0)
    return FALSE;

  reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size);
  if (!reloc_vector && reloc_size > 0)
    return FALSE;

  /* Get the relocs and think about them.  */
  reloc_count =
    bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
			    _bfd_generic_link_get_symbols (input_bfd));
  if (reloc_count < 0)
    {
      free (reloc_vector);
      return FALSE;
    }

  /* The reloc16.c and related relaxing code is very simple, the price
     for that simplicity is we can only call this function once for
     each section.

     So, to get the best results within that limitation, we do multiple
     relaxing passes over each section here.  That involves keeping track
     of the "shrink" at each reloc in the section.  This allows us to
     accurately determine the relative location of two relocs within
     this section.

     In theory, if we kept the "shrinks" array for each section for the
     entire link, we could use the generic relaxing code in the linker
     and get better results, particularly for jsr->bsr and 24->16 bit
     memory reference relaxations.  */

  if (reloc_count > 0)
    {
      int another_pass = 0;
      bfd_size_type amt;

      /* Allocate and initialize the shrinks array for this section.
	 The last element is used as an accumulator of shrinks.  */
      amt = reloc_count + 1;
      amt *= sizeof (unsigned);
      shrinks = (unsigned *) bfd_zmalloc (amt);

      /* Loop until nothing changes in this section.  */
      do
	{
	  arelent **parent;
	  unsigned int i;
	  long j;

	  another_pass = 0;

	  for (i = 0, parent = reloc_vector; *parent; parent++, i++)
	    {
	      /* Let the target/machine dependent code examine each reloc
		 in this section and attempt to shrink it.  */
	      shrink = bfd_coff_reloc16_estimate (abfd, input_section, *parent,
						  shrinks[i], link_info);

	      /* If it shrunk, note it in the shrinks array and set up for
		 another pass.  */
	      if (shrink != shrinks[i])
		{
		  another_pass = 1;
		  for (j = i + 1; j <= reloc_count; j++)
		    shrinks[j] += shrink - shrinks[i];
		}
	    }
	}
      while (another_pass);

      shrink = shrinks[reloc_count];
      free ((char *) shrinks);
    }

  input_section->rawsize = input_section->size;
  input_section->size -= shrink;
  free ((char *) reloc_vector);
  return TRUE;
}
예제 #4
0
/* Helper to size leading part of tv array and set it up. */
static void
set_tv_header (struct ld_plugin_tv *tv)
{
    size_t i;

    /* Version info.  */
    static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL);
    static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100;

    for (i = 0; i < tv_header_size; i++)
    {
        tv[i].tv_tag = tv_header_tags[i];
#define TVU(x) tv[i].tv_u.tv_ ## x
        switch (tv[i].tv_tag)
        {
        case LDPT_MESSAGE:
            TVU(message) = message;
            break;
        case LDPT_API_VERSION:
            TVU(val) = LD_PLUGIN_API_VERSION;
            break;
        case LDPT_GNU_LD_VERSION:
            TVU(val) = major * 100 + minor;
            break;
        case LDPT_LINKER_OUTPUT:
            TVU(val) = (bfd_link_relocatable (&link_info) ? LDPO_REL
                        : bfd_link_pde (&link_info) ? LDPO_EXEC
                        : bfd_link_pie (&link_info) ? LDPO_PIE
                        : LDPO_DYN);
            break;
        case LDPT_OUTPUT_NAME:
            TVU(string) = output_filename;
            break;
        case LDPT_REGISTER_CLAIM_FILE_HOOK:
            TVU(register_claim_file) = register_claim_file;
            break;
        case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
            TVU(register_all_symbols_read) = register_all_symbols_read;
            break;
        case LDPT_REGISTER_CLEANUP_HOOK:
            TVU(register_cleanup) = register_cleanup;
            break;
        case LDPT_ADD_SYMBOLS:
            TVU(add_symbols) = add_symbols;
            break;
        case LDPT_GET_INPUT_FILE:
            TVU(get_input_file) = get_input_file;
            break;
        case LDPT_GET_VIEW:
            TVU(get_view) = get_view;
            break;
        case LDPT_RELEASE_INPUT_FILE:
            TVU(release_input_file) = release_input_file;
            break;
        case LDPT_GET_SYMBOLS:
            TVU(get_symbols) = get_symbols_v1;
            break;
        case LDPT_GET_SYMBOLS_V2:
            TVU(get_symbols) = get_symbols_v2;
            break;
        case LDPT_ADD_INPUT_FILE:
            TVU(add_input_file) = add_input_file;
            break;
        case LDPT_ADD_INPUT_LIBRARY:
            TVU(add_input_library) = add_input_library;
            break;
        case LDPT_SET_EXTRA_LIBRARY_PATH:
            TVU(set_extra_library_path) = set_extra_library_path;
            break;
        default:
            /* Added a new entry to the array without adding
               a new case to set up its value is a bug.  */
            FAIL ();
        }
#undef TVU
    }
}
예제 #5
0
파일: ldmain.c 프로젝트: msmania/gdb
int
main (int argc, char **argv)
{
  char *emulation;
  long start_time = get_run_time ();
#ifdef HAVE_SBRK
  char *start_sbrk = (char *) sbrk (0);
#endif

#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
  setlocale (LC_MESSAGES, "");
#endif
#if defined (HAVE_SETLOCALE)
  setlocale (LC_CTYPE, "");
#endif
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  program_name = argv[0];
  xmalloc_set_program_name (program_name);

  START_PROGRESS (program_name, 0);

  expandargv (&argc, &argv);

  bfd_init ();

  bfd_set_error_program_name (program_name);

  /* We want to notice and fail on those nasty BFD assertions which are
     likely to signal incorrect output being generated but otherwise may
     leave no trace.  */
  default_bfd_assert_handler = bfd_set_assert_handler (ld_bfd_assert_handler);

  xatexit (ld_cleanup);

  /* Set up the sysroot directory.  */
  ld_sysroot = get_sysroot (argc, argv);
  if (*ld_sysroot)
    ld_canon_sysroot = lrealpath (ld_sysroot);
  if (ld_canon_sysroot)
    ld_canon_sysroot_len = strlen (ld_canon_sysroot);
  else
    ld_canon_sysroot_len = -1;

  /* 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
     a different target.  The macro TARGET is defined by Makefile.  */
  if (! bfd_set_default_target (TARGET))
    {
      einfo (_("%X%P: can't set BFD default target to `%s': %E\n"), TARGET);
      xexit (1);
    }

#if YYDEBUG
  {
    extern int yydebug;
    yydebug = 1;
  }
#endif

  config.build_constructors = TRUE;
  config.rpath_separator = ':';
  config.split_by_reloc = (unsigned) -1;
  config.split_by_file = (bfd_size_type) -1;
  config.make_executable = TRUE;
  config.magic_demand_paged = TRUE;
  config.text_read_only = TRUE;
  link_info.disable_target_specific_optimizations = -1;

  command_line.warn_mismatch = TRUE;
  command_line.warn_search_mismatch = TRUE;
  command_line.check_section_addresses = -1;

  /* We initialize DEMANGLING based on the environment variable
     COLLECT_NO_DEMANGLE.  The gcc collect2 program will demangle the
     output of the linker, unless COLLECT_NO_DEMANGLE is set in the
     environment.  Acting the same way here lets us provide the same
     interface by default.  */
  demangling = getenv ("COLLECT_NO_DEMANGLE") == NULL;

  link_info.allow_undefined_version = TRUE;
  link_info.keep_memory = TRUE;
  link_info.combreloc = TRUE;
  link_info.strip_discarded = TRUE;
  link_info.emit_hash = TRUE;
  link_info.callbacks = &link_callbacks;
  link_info.input_bfds_tail = &link_info.input_bfds;
  /* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
     and _fini symbols.  We are compatible.  */
  link_info.init_function = "_init";
  link_info.fini_function = "_fini";
  link_info.relax_pass = 1;
  link_info.extern_protected_data = -1;
  link_info.dynamic_undefined_weak = -1;
  link_info.pei386_auto_import = -1;
  link_info.spare_dynamic_tags = 5;
  link_info.path_separator = ':';
#ifdef DEFAULT_FLAG_COMPRESS_DEBUG
  link_info.compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
#endif

  ldfile_add_arch ("");
  emulation = get_emulation (argc, argv);
  ldemul_choose_mode (emulation);
  default_target = ldemul_choose_target (argc, argv);
  config.maxpagesize = bfd_emul_get_maxpagesize (default_target);
  config.commonpagesize = bfd_emul_get_commonpagesize (default_target);
  lang_init ();
  ldexp_init ();
  ldemul_before_parse ();
  lang_has_input_file = FALSE;
  parse_args (argc, argv);

  if (config.hash_table_size != 0)
    bfd_hash_set_default_size (config.hash_table_size);

#ifdef ENABLE_PLUGINS
  /* Now all the plugin arguments have been gathered, we can load them.  */
  plugin_load_plugins ();
#endif /* ENABLE_PLUGINS */

  ldemul_set_symbols ();

  /* If we have not already opened and parsed a linker script,
     try the default script from command line first.  */
  if (saved_script_handle == NULL
      && command_line.default_script != NULL)
    {
      ldfile_open_command_file (command_line.default_script);
      parser_input = input_script;
      yyparse ();
    }

  /* If we have not already opened and parsed a linker script
     read the emulation's appropriate default script.  */
  if (saved_script_handle == NULL)
    {
      int isfile;
      char *s = ldemul_get_script (&isfile);

      if (isfile)
	ldfile_open_default_command_file (s);
      else
	{
	  lex_string = s;
	  lex_redirect (s, _("built in linker script"), 1);
	}
      parser_input = input_script;
      yyparse ();
      lex_string = NULL;
    }

  if (verbose)
    {
      if (saved_script_handle)
	info_msg (_("using external linker script:"));
      else
	info_msg (_("using internal linker script:"));
      info_msg ("\n==================================================\n");

      if (saved_script_handle)
	{
	  static const int ld_bufsz = 8193;
	  size_t n;
	  char *buf = (char *) xmalloc (ld_bufsz);

	  rewind (saved_script_handle);
	  while ((n = fread (buf, 1, ld_bufsz - 1, saved_script_handle)) > 0)
	    {
	      buf[n] = 0;
	      info_msg (buf);
	    }
	  rewind (saved_script_handle);
	  free (buf);
	}
      else
	{
	  int isfile;

	  info_msg (ldemul_get_script (&isfile));
	}

      info_msg ("\n==================================================\n");
    }

  if (command_line.print_output_format)
    info_msg ("%s\n", lang_get_output_target ());

  lang_final ();

  /* 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);

  if (!lang_has_input_file)
    {
      if (version_printed || command_line.print_output_format)
	xexit (0);
      einfo (_("%P%F: no input files\n"));
    }

  if (trace_files)
    info_msg (_("%P: mode %s\n"), emulation);

  ldemul_after_parse ();

  if (config.map_filename)
    {
      if (strcmp (config.map_filename, "-") == 0)
	{
	  config.map_file = stdout;
	}
      else
	{
	  config.map_file = fopen (config.map_filename, FOPEN_WT);
	  if (config.map_file == (FILE *) NULL)
	    {
	      bfd_set_error (bfd_error_system_call);
	      einfo (_("%P%F: cannot open map file %s: %E\n"),
		     config.map_filename);
	    }
	}
    }

  lang_process ();

  /* Print error messages for any missing symbols, for any warning
     symbols, and possibly multiple definitions.  */
  if (bfd_link_relocatable (&link_info))
    link_info.output_bfd->flags &= ~EXEC_P;
  else
    link_info.output_bfd->flags |= EXEC_P;

  if ((link_info.compress_debug & COMPRESS_DEBUG))
    {
      link_info.output_bfd->flags |= BFD_COMPRESS;
      if (link_info.compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
	link_info.output_bfd->flags |= BFD_COMPRESS_GABI;
    }

  ldwrite ();

  if (config.map_file != NULL)
    lang_map ();
  if (command_line.cref)
    output_cref (config.map_file != NULL ? config.map_file : stdout);
  if (nocrossref_list != NULL)
    check_nocrossrefs ();
  if (command_line.print_memory_usage)
    lang_print_memory_usage ();
#if 0
  {
    struct bfd_link_hash_entry * h;

    h = bfd_link_hash_lookup (link_info.hash, "__image_base__", 0,0,1);
    fprintf (stderr, "lookup = %p val %lx\n", h, h ? h->u.def.value : 1);
  }
#endif
  ldexp_finish ();
  lang_finish ();

  /* Even if we're producing relocatable output, some non-fatal errors should
     be reported in the exit status.  (What non-fatal errors, if any, do we
     want to ignore for relocatable output?)  */
  if (!config.make_executable && !force_make_executable)
    {
      if (trace_files)
	einfo (_("%P: link errors found, deleting executable `%s'\n"),
	       output_filename);

      /* The file will be removed by ld_cleanup.  */
      xexit (1);
    }
  else
    {
      if (! bfd_close (link_info.output_bfd))
	einfo (_("%F%B: final close failed: %E\n"), link_info.output_bfd);

      /* If the --force-exe-suffix is enabled, and we're making an
	 executable file and it doesn't end in .exe, copy it to one
	 which does.  */
      if (!bfd_link_relocatable (&link_info)
	  && command_line.force_exe_suffix)
	{
	  int len = strlen (output_filename);

	  if (len < 4
	      || (strcasecmp (output_filename + len - 4, ".exe") != 0
		  && strcasecmp (output_filename + len - 4, ".dll") != 0))
	    {
	      FILE *src;
	      FILE *dst;
	      const int bsize = 4096;
	      char *buf = (char *) xmalloc (bsize);
	      int l;
	      char *dst_name = (char *) xmalloc (len + 5);

	      strcpy (dst_name, output_filename);
	      strcat (dst_name, ".exe");
	      src = fopen (output_filename, FOPEN_RB);
	      dst = fopen (dst_name, FOPEN_WB);

	      if (!src)
		einfo (_("%P%F: unable to open for source of copy `%s'\n"),
		       output_filename);
	      if (!dst)
		einfo (_("%P%F: unable to open for destination of copy `%s'\n"),
		       dst_name);
	      while ((l = fread (buf, 1, bsize, src)) > 0)
		{
		  int done = fwrite (buf, 1, l, dst);

		  if (done != l)
		    einfo (_("%P: Error writing file `%s'\n"), dst_name);
		}

	      fclose (src);
	      if (fclose (dst) == EOF)
		einfo (_("%P: Error closing file `%s'\n"), dst_name);
	      free (dst_name);
	      free (buf);
	    }
	}
    }

  END_PROGRESS (program_name);

  if (config.stats)
    {
#ifdef HAVE_SBRK
      char *lim = (char *) sbrk (0);
#endif
      long run_time = get_run_time () - start_time;

      fflush (stdout);
      fprintf (stderr, _("%s: total time in link: %ld.%06ld\n"),
	       program_name, run_time / 1000000, run_time % 1000000);
#ifdef HAVE_SBRK
      fprintf (stderr, _("%s: data size %ld\n"), program_name,
	       (long) (lim - start_sbrk));
#endif
      fflush (stderr);
    }

  /* Prevent ld_cleanup from doing anything, after a successful link.  */
  output_filename = NULL;

  xexit (0);
  return 0;
}
예제 #6
0
파일: ldctor.c 프로젝트: ChrisG0x20/gdb
void
ldctor_build_sets (void)
{
  static bfd_boolean called;
  bfd_boolean header_printed;
  struct set_info *p;

  /* The emulation code may call us directly, but we only want to do
     this once.  */
  if (called)
    return;
  called = TRUE;

  if (constructors_sorted)
    {
      for (p = sets; p != NULL; p = p->next)
	{
	  int c, i;
	  struct set_element *e;
	  struct set_element **array;

	  if (p->elements == NULL)
	    continue;

	  c = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    ++c;

	  array = (struct set_element **) xmalloc (c * sizeof *array);

	  i = 0;
	  for (e = p->elements; e != NULL; e = e->next)
	    {
	      array[i] = e;
	      ++i;
	    }

	  qsort (array, c, sizeof *array, ctor_cmp);

	  e = array[0];
	  p->elements = e;
	  for (i = 0; i < c - 1; i++)
	    array[i]->next = array[i + 1];
	  array[i]->next = NULL;

	  free (array);
	}
    }

  lang_list_init (&constructor_list);
  push_stat_ptr (&constructor_list);

  header_printed = FALSE;
  for (p = sets; p != NULL; p = p->next)
    {
      struct set_element *e;
      reloc_howto_type *howto;
      int reloc_size, size;

      /* If the symbol is defined, we may have been invoked from
	 collect, and the sets may already have been built, so we do
	 not do anything.  */
      if (p->h->type == bfd_link_hash_defined
	  || p->h->type == bfd_link_hash_defweak)
	continue;

      /* For each set we build:
	   set:
	     .long number_of_elements
	     .long element0
	     ...
	     .long elementN
	     .long 0
	 except that we use the right size instead of .long.  When
	 generating relocatable output, we generate relocs instead of
	 addresses.  */
      howto = bfd_reloc_type_lookup (link_info.output_bfd, p->reloc);
      if (howto == NULL)
	{
	  if (bfd_link_relocatable (&link_info))
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (link_info.output_bfd),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }

	  /* If this is not a relocatable link, all we need is the
	     size, which we can get from the input BFD.  */
	  if (p->elements->section->owner != NULL)
	    howto = bfd_reloc_type_lookup (p->elements->section->owner,
					   p->reloc);
	  if (howto == NULL)
	    {
	      einfo (_("%P%X: %s does not support reloc %s for set %s\n"),
		     bfd_get_target (p->elements->section->owner),
		     bfd_get_reloc_code_name (p->reloc),
		     p->h->root.string);
	      continue;
	    }
	}

      reloc_size = bfd_get_reloc_size (howto);
      switch (reloc_size)
	{
	case 1: size = BYTE; break;
	case 2: size = SHORT; break;
	case 4: size = LONG; break;
	case 8:
	  if (howto->complain_on_overflow == complain_overflow_signed)
	    size = SQUAD;
	  else
	    size = QUAD;
	  break;
	default:
	  einfo (_("%P%X: Unsupported size %d for set %s\n"),
		 bfd_get_reloc_size (howto), p->h->root.string);
	  size = LONG;
	  break;
	}

      lang_add_assignment (exp_assign (".",
				       exp_unop (ALIGN_K,
						 exp_intop (reloc_size)),
				       FALSE));
      lang_add_assignment (exp_assign (p->h->root.string,
				       exp_nameop (NAME, "."),
				       FALSE));
      lang_add_data (size, exp_intop (p->count));

      for (e = p->elements; e != NULL; e = e->next)
	{
	  if (config.map_file != NULL)
	    {
	      int len;

	      if (! header_printed)
		{
		  minfo (_("\nSet                 Symbol\n\n"));
		  header_printed = TRUE;
		}

	      minfo ("%s", p->h->root.string);
	      len = strlen (p->h->root.string);

	      if (len >= 19)
		{
		  print_nl ();
		  len = 0;
		}
	      while (len < 20)
		{
		  print_space ();
		  ++len;
		}

	      if (e->name != NULL)
		minfo ("%T\n", e->name);
	      else
		minfo ("%G\n", e->section->owner, e->section, e->value);
	    }

	  /* Need SEC_KEEP for --gc-sections.  */
	  if (! bfd_is_abs_section (e->section))
	    e->section->flags |= SEC_KEEP;

	  if (bfd_link_relocatable (&link_info))
	    lang_add_reloc (p->reloc, howto, e->section, e->name,
			    exp_intop (e->value));
	  else
	    lang_add_data (size, exp_relop (e->section, e->value));
	}

      lang_add_data (size, exp_intop (0));
    }

  pop_stat_ptr ();
}