--- /dev/null
+bfd/
+
+2013-02-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ * ldlang.c (lang_finish): Take a bfd_boolean argument to support
+ object-only output.
+ (cmdline_emit_object_only_section): Pass TRUE to lang_finish.
+
+ * ldlang.h (lang_finish): Updated.
+
+ * ldmain.c (main): Pass FALSE to lang_finish.
+
+2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/14747
+ * elflink.c (_bfd_elf_fix_symbol_flags): Check symbol for linker
+ created section instead.
+
+2012-10-25 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/14747
+ * elflink.c (_bfd_elf_fix_symbol_flags): Never mark
+ _GLOBAL_OFFSET_TABLE_, _PROCEDURE_LINKAGE_TABLE_ nor _DYNAMIC
+ undefined.
+
+2012-06-28 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/14272
+ * elflink.c (_bfd_elf_fix_symbol_flags): Mark the plugin symbol
+ undefined if it is referenced from a non-IR file.
+
+2012-06-04 H.J. Lu <hongjiu.lu@intel.com>
+
+ * plugin.c (add_symbols): Set tdata.plugin_data before calling
+ bfd_plugin_get_symbols_in_object_only.
+
+2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
+
+ * plugin.c (add_symbols): Call
+ bfd_plugin_get_symbols_in_object_only.
+ (bfd_plugin_get_symtab_upper_bound): Don't call
+ bfd_plugin_get_symbols_in_object_only.
+
+2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
+
+ * plugin.c (bfd_plugin_get_symbols_in_object_only): Optimized.
+
+2011-10-16 H.J. Lu <hongjiu.lu@intel.com>
+
+ * plugin.c (bfd_plugin_get_symbols_in_object_only): Properly
+ remove the object only section file.
+
+2011-10-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/13298
+ * opncls.c (bfd_extract_object_only_section): New.
+
+ * plugin.c (add_symbols): Initialize object_only_syms and
+ object_only_nsyms.
+ (bfd_plugin_fake_text_section): New.
+ (bfd_plugin_fake_common_section): Likewise.
+ (bfd_plugin_get_symbols_in_object_only): Likewise.
+ (bfd_plugin_get_symtab_upper_bound): Call
+ bfd_plugin_get_symbols_in_object_only and add symbols from
+ object only section.
+ (bfd_plugin_canonicalize_symtab): Remove fake_section and
+ fake_common_section. Use bfd_plugin_fake_text_section and
+ bfd_plugin_fake_common_section. Set udata.p to NULL. Copy
+ symbols from object only section.
+
+ * plugin.h (plugin_data_struct): Add object_only_nsyms and
+ object_only_syms.
+
+ * bfd-in2.h: Regenerated.
+
+2011-05-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/12758
+ * elflink.c (elf_link_add_archive_symbols): Don't load the IR
+ archive member twice.
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * bfd.c (bfd_lto_object_type): New.
+ (bfd): Add object_only_section and lto_type.
+ (bfd_group_signature): New.
+
+ * elf.c (special_sections_g): Add .gnu_object_only.
+
+ * format.c (bfd_set_lto_type): New.
+ (bfd_check_format_matches): Use it.
+
+ * section.c (GNU_OBJECT_ONLY_SECTION_NAME): New.
+
+ * bfd-in2.h: Regenerated.
+
+binutils/
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * objcopy.c (group_signature): Removed.
+ (is_strip_section): Replace group_signature with
+ bfd_group_signature.
+ (setup_section): Likewise.
+
+ * readelf.c (get_section_type_name): Handle SHT_GNU_OBJECT_ONLY.
+
+gas/testsuite/
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * gas/elf/section9.s: Add the .gnu_object_only test.
+ * gas/elf/section9.d: Updated.
+
+include/
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * bfdlink.h (bfd_link_info): Add emit_gnu_object_only and
+ emitting_gnu_object_only.
+
+include/elf/
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * common.h (SHT_GNU_OBJECT_ONLY): New.
+
+ld/
+
++2014-01-11 H.J. Lu <hongjiu.lu@intel.com>
++
++ * ldlang.c (cmdline_add_object_only_section): Save BFD filename
++ to be used after bfd_close ().
++
+2012-10-20 H.J. Lu <hongjiu.lu@intel.com>
+
+ * ldlang.c (lang_process): Replace trace_file_tries with
+ verbose.
+
+2012-08-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ * emultempl/aarch64elf.em (gld${EMULATION_NAME}_finish): Renamed
+ to ...
+ (aarch64_finish): This. Replace finish_default with
+ gld${EMULATION_NAME}_finish.
+ (LDEMUL_FINISH): Set to aarch64_finish.
+
+2011-10-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/13298
+ * ldlang.c (cmdline_extract_object_only_section): Call
+ bfd_extract_object_only_section.
+
+2011-05-17 H.J. Lu <hongjiu.lu@intel.com>
+
+ * ldlang.c (cmdline_remove_object_only_files): Return if
+ ENABLE_PLUGINS is undefined or plugin_save_temps is true.
+
+2011-05-15 H.J. Lu <hongjiu.lu@intel.com>
+
+ * ldlex.h (option_values): Add OPTION_PLUGIN_SAVE_TEMPS.
+ * lexsup.c (ld_options): Add -plugin-save-temps.
+ (parse_args): Handle OPTION_PLUGIN_SAVE_TEMPS.
+
+ * plugin.c (plugin_save_temps): New.
+ (plugin_call_cleanup): Don't call plugin cleanup_handler if
+ plugin_save_temps is true.
+
+ * plugin.h (plugin_save_temps): New.
+
+2011-05-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/12760
+ * ldmain.c (warning_callback): Don't warn plugin dummy.
+
+2011-04-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * emultempl/alphaelf.em (alpha_finish): Replace finish_default
+ with gld${EMULATION_NAME}_finish.
+
+ * emultempl/armelf.em (gld${EMULATION_NAME}_finish): Renamed
+ to ...
+ (arm_finish): This. Replace finish_default with
+ gld${EMULATION_NAME}_finish.
+ (LDEMUL_FINISH): Set to arm_finish.
+
+ * emultempl/elf32.em (gld${EMULATION_NAME}_finish): New.
+ (orphan_init_done): Likewise.
+ (ld_${EMULATION_NAME}_emulation): Use gld${EMULATION_NAME}_finish.
+ (gld${EMULATION_NAME}_place_orphan): Initialize hold.
+
+ * emultempl/ppc64elf.em (gld${EMULATION_NAME}_finish): Renamed
+ to ...
+ (ppc_finish): This. Replace finish_default with
+ gld${EMULATION_NAME}_finish.
+ (LDEMUL_FINISH): Set to ppc_finish.
+
+ * emultempl/spuelf.em (gld${EMULATION_NAME}_finish): Renamed
+ to ...
+ (spu_finish): This. Replace finish_default with
+ gld${EMULATION_NAME}_finish.
+ (LDEMUL_FINISH): Set to spu_finish.
+
+ * ldfile.c (ldfile_try_open_bfd): Call
+ cmdline_check_object_only_section.
+
+ * ldlang.c: Include "ldwrite.h" and elf-bfd.h.
+ * ldlang.c (cmdline_object_only_file_list): New.
+ (cmdline_object_only_archive_list): Likewise.
+ (cmdline_temp_object_only_list): Likewise.
+ (cmdline_lists_init): Likewise.
+ (cmdline_list_new): Likewise.
+ (cmdline_list_append): Likewise.
+ (print_cmdline_list): Likewise.
+ (cmdline_on_object_only_archive_list_p): Likewise.
+ (cmdline_object_only_list_append): Likewise.
+ (cmdline_get_object_only_input_files): Likewise.
+ (cmdline_arg): Likewise.
+ (setup_section): Likewise.
+ (copy_section): Likewise.
+ (cmdline_fopen_temp): Likewise.
+ (cmdline_add_object_only_section): Likewise.
+ (cmdline_emit_object_only_section): Likewise.
+ (cmdline_extract_object_only_section): Likewise.
+ (cmdline_check_object_only_section): Likewise.
+ (cmdline_remove_object_only_files): Likewise.
+ (lang_init): Take a bfd_boolean argument to supprt object-only
+ output. Call cmdline_lists_init.
+ (load_symbols): Call cmdline_on_object_only_archive_list_p
+ to check if an archive member should be loaded.
+ (lang_process): Handle object-only link.
+
+ * ldlang.h (lang_init): Take a bfd_boolean argument.
+ (cmdline_enum_type): New.
+ (cmdline_header_type): Likewise.
+ (cmdline_file_type): Likewise.
+ (cmdline_bfd_type): Likewise.
+ (cmdline_union_type): Likewise.
+ (cmdline_list_type): Likewise.
+ (cmdline_emit_object_only_section): Likewise.
+ (cmdline_check_object_only_section): Likewise.
+ (cmdline_remove_object_only_files): Likewise.
+
+ * ldmain.c (main): Call xatexit with
+ cmdline_remove_object_only_files. Pass FALSE to lang_init.
+ Use ld_parse_linker_script. Set link_info.output_bfd to NULL
+ after close. Call cmdline_emit_object_only_section if needed.
+ (add_archive_element): Call cmdline_check_object_only_section.
+ (ld_parse_linker_script): New.
+
+ * ldmain.h (ld_parse_linker_script): New.
+
+ * plugin.c (plugin_opt_plugin_arg): Ignore -pass-through=.
+ (plugin_maybe_claim): Call cmdline_check_object_only_section
+ on claimed IR files.
+
+ * scripttempl/armbpabi.sc: Also discard .gnu_object_only
+ sections.
+ * scripttempl/elf.sc: Likewise.
+ * scripttempl/elf32sh-symbian.sc: Likewise.
+ * scripttempl/elf64hppa.sc: Likewise.
+ * scripttempl/elfxtensa.sc: Likewise.
+ * scripttempl/mep.sc: Likewise.
+ * scripttempl/pe.sc: Likewise.
+ * scripttempl/pep.sc: Likewise.
+
+ld/testsuite/
+
+2012-12-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/14918
+ * ld-plugin/lto.exp (lto_link_elf_tests): Add PR ld/14918 test.
+
+ * ld-plugin/pr14918.c: New file.
+ * ld-plugin/pr14918.d: Likewise.
+
+2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/12365
+ * ld-plugin/pr12365a.c: New file.
+ * ld-plugin/pr12365b.c: Likewise.
+ * ld-plugin/pr12365c.c: Likewise.
+
+ * ld-plugin/lto.exp (lto_link_tests): Prepare for the PR ld/12365
+ test.
+ Run the PR ld/12365 test.
+
+2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/12430
+ * ld-plugin/lto-10.out: New file.
+ * ld-plugin/lto-10a.c: Likewise.
+ * ld-plugin/lto-10b.c: Likewise.
+ * ld-plugin/lto-10r.d: Likewise.
+
+ * ld-plugin/lto.exp (lto_link_tests): Prepare for "LTO 10".
+ (lto_run_tests): Add "LTO 10".
+ Run lto-10r and create tmpdir/lto-10.o.
+
+2011-01-22 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/12291
+ * ld-plugin/lto-4.out: Likewise.
+ * ld-plugin/lto-4a.c: Likewise.
+ * ld-plugin/lto-4b.c: Likewise.
+ * ld-plugin/lto-4c.c: Likewise.
+ * ld-plugin/lto-4r-a.d: Likewise.
+ * ld-plugin/lto-4r-b.d: Likewise.
+ * ld-plugin/lto-4r-c.d: Likewise.
+ * ld-plugin/lto-4r-d.d: Likewise.
+
+ * ld-plugin/lto.exp (lto_link_tests): Prepare for "LTO 4[acd]"
+ and "lto-4r-[abcd]" tests.
+ (lto_run_tests): Add "LTO 4[acd]" tests.
+ Build liblto-4.a. Run "lto-4r-[abcd]" tests.
--- /dev/null
--- /dev/null
++bfd/
++
++2014-01-24 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR binutils/16496
++ * elf-bfd.h (bfd_elf_get_symbol_version_string): New.
++ * elf.c (bfd_elf_get_symbol_version_string): New. Extracted
++ from bfd_elf_print_symbol.
++ (bfd_elf_print_symbol): Use it.
++
++binutils/
++
++2014-01-24 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR binutils/16496
++ * objdump.c (objdump_print_symname): Call
++ bfd_elf_get_symbol_version_string to get ELF symbol version
++ string. Append version string if needed.
++
++ * readelf.c (versioned_symbol_info): New enum.
++ (get_symbol_version_string): New. Extracted from
++ process_symbol_table.
++ (dump_relocations): Add a new argument to indicate if dynamic
++ symbol table is used. Use get_symbol_version_string to get
++ symbol version string for dynamic symbol. Append version string
++ if needed.
++ (process_relocs): Updated dump_relocations call.
++ (process_symbol_table): Use get_symbol_version_string.
++
++ld/testsuite/
++
++2014-01-24 H.J. Lu <hongjiu.lu@intel.com>
++
++ PR binutils/16496
++ * ld-cris/weakref3.d: Add symbol version string to versioned
++ symbol names in dynamic relocation.
++ * ld-cris/weakref4.d: Likewise.
++ * ld-elfvers/vers24.rd: Likewise.
++
++ * ld-elf/pr16496a.c: New file.
++ * ld-elf/pr16496a.map: Likewise.
++ * ld-elf/pr16496b.c: Likewise.
++ * ld-elf/pr16496b.od: Likewise.
++
++ * ld-elf/shared.exp (build_tests): Add libpr16496a.so and
++ libpr16496b.so tests.
(bfd *, bfd *);
extern bfd_boolean _bfd_elf_print_private_bfd_data
(bfd *, void *);
++const char * bfd_elf_get_symbol_version_string
++ (bfd *, asymbol *, bfd_boolean *);
extern void bfd_elf_print_symbol
(bfd *, void *, asymbol *, bfd_print_symbol_type);
return FALSE;
}
++/* Get version string. */
++
++const char *
++bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
++ bfd_boolean *hidden)
++{
++ const char *version_string = NULL;
++ if (elf_dynversym (abfd) != 0
++ && (elf_dynverdef (abfd) != 0 || elf_dynverref (abfd) != 0))
++ {
++ unsigned int vernum = ((elf_symbol_type *) symbol)->version;
++
++ *hidden = (vernum & VERSYM_HIDDEN) != 0;
++ vernum &= VERSYM_VERSION;
++
++ if (vernum == 0)
++ version_string = "";
++ else if (vernum == 1)
++ version_string = "Base";
++ else if (vernum <= elf_tdata (abfd)->cverdefs)
++ version_string =
++ elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
++ else
++ {
++ Elf_Internal_Verneed *t;
++
++ version_string = "";
++ for (t = elf_tdata (abfd)->verref;
++ t != NULL;
++ t = t->vn_nextref)
++ {
++ Elf_Internal_Vernaux *a;
++
++ for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
++ {
++ if (a->vna_other == vernum)
++ {
++ version_string = a->vna_nodename;
++ break;
++ }
++ }
++ }
++ }
++ }
++ return version_string;
++}
++
/* Display ELF-specific fields of a symbol. */
void
const struct elf_backend_data *bed;
unsigned char st_other;
bfd_vma val;
++ const char *version_string;
++ bfd_boolean hidden;
section_name = symbol->section ? symbol->section->name : "(*none*)";
bfd_fprintf_vma (abfd, file, val);
/* If we have version information, print it. */
-- if (elf_dynversym (abfd) != 0
-- && (elf_dynverdef (abfd) != 0
-- || elf_dynverref (abfd) != 0))
++ version_string = bfd_elf_get_symbol_version_string (abfd,
++ symbol,
++ &hidden);
++ if (version_string)
{
-- unsigned int vernum;
-- const char *version_string;
--
-- vernum = ((elf_symbol_type *) symbol)->version & VERSYM_VERSION;
--
-- if (vernum == 0)
-- version_string = "";
-- else if (vernum == 1)
-- version_string = "Base";
-- else if (vernum <= elf_tdata (abfd)->cverdefs)
-- version_string =
-- elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
-- else
-- {
-- Elf_Internal_Verneed *t;
--
-- version_string = "";
-- for (t = elf_tdata (abfd)->verref;
-- t != NULL;
-- t = t->vn_nextref)
-- {
-- Elf_Internal_Vernaux *a;
--
-- for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
-- {
-- if (a->vna_other == vernum)
-- {
-- version_string = a->vna_nodename;
-- break;
-- }
-- }
-- }
-- }
--
-- if ((((elf_symbol_type *) symbol)->version & VERSYM_HIDDEN) == 0)
++ if (!hidden)
fprintf (file, " %-11s", version_string);
else
{
#define elf_backend_plt_sym_val elf_i386_plt_sym_val
#define elf_backend_hash_symbol elf_i386_hash_symbol
#define elf_backend_add_symbol_hook elf_i386_add_symbol_hook
- #undef elf_backend_post_process_headers
- #define elf_backend_post_process_headers _bfd_elf_set_osabi
+#define elf_backend_section_from_bfd_section \
+ _bfd_elf_sharable_section_from_bfd_section
+#define elf_backend_symbol_processing \
+ _bfd_elf_sharable_symbol_processing
+#define elf_backend_common_section_index \
+ _bfd_elf_sharable_common_section_index
+#define elf_backend_common_section \
+ _bfd_elf_sharable_common_section
+#define elf_backend_common_definition \
+ _bfd_elf_sharable_common_definition
+#define elf_backend_merge_symbol \
+ _bfd_elf_sharable_merge_symbol
+
#include "elf32-target.h"
/* FreeBSD support. */
return LDPS_OK;
}
- s = bfd_alloc (abfd, sizeof (asymbol));
+static asection bfd_plugin_fake_text_section
+ = BFD_FAKE_SECTION (bfd_plugin_fake_text_section, 0, 0, ".text", 0);
+static asection bfd_plugin_fake_common_section
+ = BFD_FAKE_SECTION (bfd_plugin_fake_common_section, SEC_IS_COMMON, 0,
+ NULL, 0);
+
+/* Get symbols from object only section. */
+
+static void
+bfd_plugin_get_symbols_in_object_only (bfd *abfd)
+{
+ struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
+ const char *object_only_file;
+ bfd *nbfd;
+ long storage;
+ long object_only_nsyms, added_nsyms, i;
+ asymbol **object_only_syms, **added_syms;
+
+ plugin_data->object_only_syms = NULL;
+ plugin_data->object_only_nsyms = 0;
+
+ if (abfd->sections == NULL && abfd->my_archive == NULL)
+ {
+ nbfd = bfd_openr (abfd->filename, NULL);
+ if (nbfd == NULL || !bfd_check_format (nbfd, bfd_object))
+ {
+ (*_bfd_error_handler)
+ (_("%s: failed to open to extract object only section: %s"),
+ abfd->filename, bfd_errmsg (bfd_get_error ()));
+ bfd_close (nbfd);
+ return;
+ }
+ }
+ else
+ {
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ (*_bfd_error_handler)
+ (_("%B: invalid file to extract object only section: %s"),
+ abfd, bfd_errmsg (bfd_get_error ()));
+ return;
+ }
+ nbfd = abfd;
+ }
+
+ if (nbfd->lto_type == lto_mixed_object
+ && (nbfd->flags & HAS_SYMS) != 0)
+ {
+ object_only_file = bfd_extract_object_only_section (nbfd);
+ if (object_only_file == NULL)
+ (*_bfd_error_handler)
+ (_("%B: failed to extract object only section: %s"),
+ abfd, bfd_errmsg (bfd_get_error ()));
+ }
+ else
+ object_only_file = NULL;
+
+ /* Close the new bfd we just opened. */
+ if (nbfd != abfd)
+ bfd_close (nbfd);
+
+ /* Return if there is no object only section or there is no
+ symbol in object only section. */
+ if (!object_only_file)
+ return;
+
+ /* Open the file containing object only section. */
+ nbfd = bfd_openr (object_only_file, NULL);
+ if (!bfd_check_format (nbfd, bfd_object))
+ {
+ (*_bfd_error_handler)
+ (_("%B: failed to open object only section: %s"),
+ abfd, bfd_errmsg (bfd_get_error ()));
+ goto quit;
+ }
+
+ storage = bfd_get_symtab_upper_bound (nbfd);
+ if (storage <= 0)
+ {
+ if (storage < 0)
+ (*_bfd_error_handler)
+ (_("%B: failed to get symbol table in object only section: %s"),
+ abfd, bfd_errmsg (bfd_get_error ()));
+
+ goto quit;
+ }
+
+ object_only_syms = (asymbol **) bfd_malloc (storage);
+ object_only_nsyms = bfd_canonicalize_symtab (nbfd, object_only_syms);
+
+ /* FIXME: We waste some spaces if not all symbols are copied. */
+ added_syms = (asymbol **) bfd_alloc (abfd, storage);
+ added_nsyms = 0;
+
+ /* Copy only global symbols from object only section. */
+ for (i = 0; i < object_only_nsyms; i++)
+ {
+ asection *sec = object_only_syms[i]->section;
+ flagword flags = object_only_syms[i]->flags;
+ asymbol *s;
+
+ if (bfd_is_com_section (sec))
+ sec = &bfd_plugin_fake_common_section;
+ else if (bfd_is_und_section (sec))
+ ;
+ else if ((flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0)
+ sec = &bfd_plugin_fake_text_section;
+ else
+ continue;
+
++ s = bfd_alloc (abfd, sizeof (asymbol));
+ BFD_ASSERT (s);
+ added_syms[added_nsyms++] = s;
+
+ s->section = sec;
+ s->the_bfd = abfd;
+ s->name = xstrdup (object_only_syms[i]->name);
+ s->value = 0;
+ s->flags = flags;
+ s->udata.p = NULL;
+ }
+
+ plugin_data->object_only_syms = added_syms;
+ plugin_data->object_only_nsyms = added_nsyms;
+
+ free (object_only_syms);
+
+quit:
+ /* Close and remove the object only section file. */
+ bfd_close (nbfd);
+ unlink (object_only_file);
+}
+
static enum ld_plugin_status
add_symbols (void * handle,
int nsyms,
asymbol *sym)
{
char *alloc;
-- const char *name;
++ const char *name, *version_string = NULL;
++ bfd_boolean hidden = FALSE;
alloc = NULL;
name = bfd_asymbol_name (sym);
name = alloc;
}
++ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
++ version_string = bfd_elf_get_symbol_version_string (abfd, sym,
++ &hidden);
++
++ if (bfd_is_und_section (bfd_get_section (sym)))
++ hidden = TRUE;
++
if (inf != NULL)
-- (*inf->fprintf_func) (inf->stream, "%s", name);
++ {
++ (*inf->fprintf_func) (inf->stream, "%s", name);
++ if (version_string && *version_string != '\0')
++ (*inf->fprintf_func) (inf->stream, hidden ? "@%s" : "@@%s",
++ version_string);
++ }
else
-- printf ("%s", name);
++ {
++ printf ("%s", name);
++ if (version_string && *version_string != '\0')
++ printf (hidden ? "@%s" : "@@%s", version_string);
++ }
if (alloc != NULL)
free (alloc);
}
print_mode;
++/* Versioned symbol info. */
++enum versioned_symbol_info
++{
++ symbol_undefined,
++ symbol_hidden,
++ symbol_public
++};
++
++static const char *get_symbol_version_string
++ (FILE *file, int is_dynsym, const char *strtab,
++ unsigned long int strtab_size, unsigned int si,
++ Elf_Internal_Sym *psym, enum versioned_symbol_info *sym_info,
++ unsigned short *vna_other);
++
#define UNKNOWN -1
#define SECTION_NAME(X) \
unsigned long nsyms,
char * strtab,
unsigned long strtablen,
-- int is_rela)
++ int is_rela,
++ int is_dynsym)
{
unsigned int i;
Elf_Internal_Rela * rels;
else
{
Elf_Internal_Sym * psym;
++ const char * version_string;
++ enum versioned_symbol_info sym_info;
++ unsigned short vna_other;
psym = symtab + symtab_index;
++ version_string
++ = get_symbol_version_string (file, is_dynsym,
++ strtab, strtablen,
++ symtab_index,
++ psym,
++ &sym_info,
++ &vna_other);
++
printf (" ");
if (ELF_ST_TYPE (psym->st_info) == STT_GNU_IFUNC)
name = strtab + psym->st_name;
len = print_symbol (width, name);
++ if (version_string)
++ printf (sym_info == symbol_public ? "@@%s" : "@%s",
++ version_string);
printf ("()%-*s", len <= width ? (width + 1) - len : 1, " ");
}
else
else if (psym->st_name >= strtablen)
printf (_("<corrupt string table index: %3ld>"), psym->st_name);
else
-- print_symbol (22, strtab + psym->st_name);
++ {
++ print_symbol (22, strtab + psym->st_name);
++ if (version_string)
++ printf (sym_info == symbol_public ? "@@%s" : "@%s",
++ version_string);
++ }
if (is_rela)
{
offset_from_vma (file, rel_offset, rel_size),
rel_size,
dynamic_symbols, num_dynamic_syms,
-- dynamic_strings, dynamic_strings_length, is_rela);
++ dynamic_strings, dynamic_strings_length,
++ is_rela, 1);
}
}
}
dump_relocations (file, rel_offset, rel_size,
-- symtab, nsyms, strtab, strtablen, is_rela);
++ symtab, nsyms, strtab, strtablen,
++ is_rela,
++ symsec->sh_type == SHT_DYNSYM);
if (strtab)
free (strtab);
free (symtab);
}
else
dump_relocations (file, rel_offset, rel_size,
-- NULL, 0, NULL, 0, is_rela);
++ NULL, 0, NULL, 0, is_rela, 0);
found = 1;
}
putchar ('\n');
}
++static const char *
++get_symbol_version_string (FILE *file, int is_dynsym,
++ const char *strtab,
++ unsigned long int strtab_size,
++ unsigned int si, Elf_Internal_Sym *psym,
++ enum versioned_symbol_info *sym_info,
++ unsigned short *vna_other)
++{
++ const char *version_string = NULL;
++
++ if (is_dynsym
++ && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
++ {
++ unsigned char data[2];
++ unsigned short vers_data;
++ unsigned long offset;
++ int is_nobits;
++ int check_def;
++
++ offset = offset_from_vma
++ (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
++ sizeof data + si * sizeof (vers_data));
++
++ if (get_data (&data, file, offset + si * sizeof (vers_data),
++ sizeof (data), 1, _("version data")) == NULL)
++ return NULL;
++
++ vers_data = byte_get (data, 2);
++
++ is_nobits = (psym->st_shndx < elf_header.e_shnum
++ && section_headers[psym->st_shndx].sh_type
++ == SHT_NOBITS);
++
++ check_def = (psym->st_shndx != SHN_UNDEF);
++
++ if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
++ {
++ if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
++ && (is_nobits || ! check_def))
++ {
++ Elf_External_Verneed evn;
++ Elf_Internal_Verneed ivn;
++ Elf_Internal_Vernaux ivna;
++
++ /* We must test both. */
++ offset = offset_from_vma
++ (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
++ sizeof evn);
++
++ do
++ {
++ unsigned long vna_off;
++
++ if (get_data (&evn, file, offset, sizeof (evn), 1,
++ _("version need")) == NULL)
++ {
++ ivna.vna_next = 0;
++ ivna.vna_other = 0;
++ ivna.vna_name = 0;
++ break;
++ }
++
++ ivn.vn_aux = BYTE_GET (evn.vn_aux);
++ ivn.vn_next = BYTE_GET (evn.vn_next);
++
++ vna_off = offset + ivn.vn_aux;
++
++ do
++ {
++ Elf_External_Vernaux evna;
++
++ if (get_data (&evna, file, vna_off,
++ sizeof (evna), 1,
++ _("version need aux (3)")) == NULL)
++ {
++ ivna.vna_next = 0;
++ ivna.vna_other = 0;
++ ivna.vna_name = 0;
++ }
++ else
++ {
++ ivna.vna_other = BYTE_GET (evna.vna_other);
++ ivna.vna_next = BYTE_GET (evna.vna_next);
++ ivna.vna_name = BYTE_GET (evna.vna_name);
++ }
++
++ vna_off += ivna.vna_next;
++ }
++ while (ivna.vna_other != vers_data
++ && ivna.vna_next != 0);
++
++ if (ivna.vna_other == vers_data)
++ break;
++
++ offset += ivn.vn_next;
++ }
++ while (ivn.vn_next != 0);
++
++ if (ivna.vna_other == vers_data)
++ {
++ *sym_info = symbol_undefined;
++ *vna_other = ivna.vna_other;
++ version_string = (ivna.vna_name < strtab_size
++ ? strtab + ivna.vna_name
++ : _("<corrupt>"));
++ check_def = 0;
++ }
++ else if (! is_nobits)
++ error (_("bad dynamic symbol\n"));
++ else
++ check_def = 1;
++ }
++
++ if (check_def)
++ {
++ if (vers_data != 0x8001
++ && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
++ {
++ Elf_Internal_Verdef ivd;
++ Elf_Internal_Verdaux ivda;
++ Elf_External_Verdaux evda;
++ unsigned long off;
++
++ off = offset_from_vma
++ (file,
++ version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
++ sizeof (Elf_External_Verdef));
++
++ do
++ {
++ Elf_External_Verdef evd;
++
++ if (get_data (&evd, file, off, sizeof (evd),
++ 1, _("version def")) == NULL)
++ {
++ ivd.vd_ndx = 0;
++ ivd.vd_aux = 0;
++ ivd.vd_next = 0;
++ }
++ else
++ {
++ ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
++ ivd.vd_aux = BYTE_GET (evd.vd_aux);
++ ivd.vd_next = BYTE_GET (evd.vd_next);
++ }
++
++ off += ivd.vd_next;
++ }
++ while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
++ && ivd.vd_next != 0);
++
++ off -= ivd.vd_next;
++ off += ivd.vd_aux;
++
++ if (get_data (&evda, file, off, sizeof (evda),
++ 1, _("version def aux")) == NULL)
++ return version_string;
++
++ ivda.vda_name = BYTE_GET (evda.vda_name);
++
++ if (psym->st_name != ivda.vda_name)
++ {
++ *sym_info = ((vers_data & VERSYM_HIDDEN) != 0
++ ? symbol_hidden : symbol_public);
++ version_string = (ivda.vda_name < strtab_size
++ ? strtab + ivda.vda_name
++ : _("<corrupt>"));
++ }
++ }
++ }
++ }
++ }
++ return version_string;
++}
++
/* Dump the symbol table. */
static int
process_symbol_table (FILE * file)
for (si = 0, psym = symtab; si < num_syms; si++, psym++)
{
++ const char *version_string;
++ enum versioned_symbol_info sym_info;
++ unsigned short vna_other;
++
printf ("%6d: ", si);
print_vma (psym->st_value, LONG_HEX);
putchar (' ');
print_symbol (25, psym->st_name < strtab_size
? strtab + psym->st_name : _("<corrupt>"));
-- if (section->sh_type == SHT_DYNSYM
-- && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
++ version_string
++ = get_symbol_version_string (file,
++ section->sh_type == SHT_DYNSYM,
++ strtab, strtab_size, si,
++ psym, &sym_info, &vna_other);
++ if (version_string)
{
-- unsigned char data[2];
-- unsigned short vers_data;
-- unsigned long offset;
-- int is_nobits;
-- int check_def;
--
-- offset = offset_from_vma
-- (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
-- sizeof data + si * sizeof (vers_data));
--
-- if (get_data (&data, file, offset + si * sizeof (vers_data),
-- sizeof (data), 1, _("version data")) == NULL)
-- break;
--
-- vers_data = byte_get (data, 2);
--
-- is_nobits = (psym->st_shndx < elf_header.e_shnum
-- && section_headers[psym->st_shndx].sh_type
-- == SHT_NOBITS);
--
-- check_def = (psym->st_shndx != SHN_UNDEF);
--
-- if ((vers_data & VERSYM_HIDDEN) || vers_data > 1)
-- {
-- if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)]
-- && (is_nobits || ! check_def))
-- {
-- Elf_External_Verneed evn;
-- Elf_Internal_Verneed ivn;
-- Elf_Internal_Vernaux ivna;
--
-- /* We must test both. */
-- offset = offset_from_vma
-- (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)],
-- sizeof evn);
--
-- do
-- {
-- unsigned long vna_off;
--
-- if (get_data (&evn, file, offset, sizeof (evn), 1,
-- _("version need")) == NULL)
-- {
-- ivna.vna_next = 0;
-- ivna.vna_other = 0;
-- ivna.vna_name = 0;
-- break;
-- }
--
-- ivn.vn_aux = BYTE_GET (evn.vn_aux);
-- ivn.vn_next = BYTE_GET (evn.vn_next);
--
-- vna_off = offset + ivn.vn_aux;
--
-- do
-- {
-- Elf_External_Vernaux evna;
--
-- if (get_data (&evna, file, vna_off,
-- sizeof (evna), 1,
-- _("version need aux (3)")) == NULL)
-- {
-- ivna.vna_next = 0;
-- ivna.vna_other = 0;
-- ivna.vna_name = 0;
-- }
-- else
-- {
-- ivna.vna_other = BYTE_GET (evna.vna_other);
-- ivna.vna_next = BYTE_GET (evna.vna_next);
-- ivna.vna_name = BYTE_GET (evna.vna_name);
-- }
--
-- vna_off += ivna.vna_next;
-- }
-- while (ivna.vna_other != vers_data
-- && ivna.vna_next != 0);
--
-- if (ivna.vna_other == vers_data)
-- break;
--
-- offset += ivn.vn_next;
-- }
-- while (ivn.vn_next != 0);
--
-- if (ivna.vna_other == vers_data)
-- {
-- printf ("@%s (%d)",
-- ivna.vna_name < strtab_size
-- ? strtab + ivna.vna_name : _("<corrupt>"),
-- ivna.vna_other);
-- check_def = 0;
-- }
-- else if (! is_nobits)
-- error (_("bad dynamic symbol\n"));
-- else
-- check_def = 1;
-- }
--
-- if (check_def)
-- {
-- if (vers_data != 0x8001
-- && version_info[DT_VERSIONTAGIDX (DT_VERDEF)])
-- {
-- Elf_Internal_Verdef ivd;
-- Elf_Internal_Verdaux ivda;
-- Elf_External_Verdaux evda;
-- unsigned long off;
--
-- off = offset_from_vma
-- (file,
-- version_info[DT_VERSIONTAGIDX (DT_VERDEF)],
-- sizeof (Elf_External_Verdef));
--
-- do
-- {
-- Elf_External_Verdef evd;
--
-- if (get_data (&evd, file, off, sizeof (evd),
-- 1, _("version def")) == NULL)
-- {
-- ivd.vd_ndx = 0;
-- ivd.vd_aux = 0;
-- ivd.vd_next = 0;
-- }
-- else
-- {
-- ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
-- ivd.vd_aux = BYTE_GET (evd.vd_aux);
-- ivd.vd_next = BYTE_GET (evd.vd_next);
-- }
--
-- off += ivd.vd_next;
-- }
-- while (ivd.vd_ndx != (vers_data & VERSYM_VERSION)
-- && ivd.vd_next != 0);
--
-- off -= ivd.vd_next;
-- off += ivd.vd_aux;
--
-- if (get_data (&evda, file, off, sizeof (evda),
-- 1, _("version def aux")) == NULL)
-- break;
--
-- ivda.vda_name = BYTE_GET (evda.vda_name);
--
-- if (psym->st_name != ivda.vda_name)
-- printf ((vers_data & VERSYM_HIDDEN)
-- ? "@%s" : "@@%s",
-- ivda.vda_name < strtab_size
-- ? strtab + ivda.vda_name : _("<corrupt>"));
-- }
-- }
-- }
++ if (sym_info == symbol_undefined)
++ printf ("@%s (%d)", version_string, vna_other);
++ else
++ printf (sym_info == symbol_hidden ? "@%s" : "@@%s",
++ version_string);
}
putchar ('\n');
static lang_statement_list_type *stat_save[10];
static lang_statement_list_type **stat_save_ptr = &stat_save[0];
static struct unique_sections *unique_section_list;
+ static struct asneeded_minfo *asneeded_list_head;
+static cmdline_list_type cmdline_object_only_file_list;
+static cmdline_list_type cmdline_object_only_archive_list;
+static cmdline_list_type cmdline_temp_object_only_list;
/* Forward declarations. */
static void exp_init_os (etree_type *);
abs_output_section->bfd_section = bfd_abs_section_ptr;
- /* The value "3" is ad-hoc, somewhat related to the expected number of
- DEFINED expressions in a linker script. For most default linker
- scripts, there are none. Why a hash table then? Well, it's somewhat
- simpler to re-use working machinery than using a linked list in terms
- of code-complexity here in ld, besides the initialization which just
- looks like other code here. */
+ /* The value "13" is ad-hoc, somewhat related to the expected number of
+ assignments in a linker script. */
- if (!bfd_hash_table_init_n (&lang_definedness_table,
- lang_definedness_newfunc,
- sizeof (struct lang_definedness_hash_entry),
- 13))
+ if (!object_only
+ && !bfd_hash_table_init_n (&lang_definedness_table,
+ lang_definedness_newfunc,
+ sizeof (struct lang_definedness_hash_entry),
- 3))
++ 13))
einfo (_("%P%F: can not create hash table: %E\n"));
+
+ asneeded_list_head = NULL;
+ asneeded_list_tail = &asneeded_list_head;
}
void
p = q;
}
}
-
+
+static void
+cmdline_lists_init (void)
+{
+ cmdline_object_only_file_list.tail
+ = &cmdline_object_only_file_list.head;
+ cmdline_object_only_archive_list.tail
+ = &cmdline_object_only_archive_list.head;
+ cmdline_temp_object_only_list.tail
+ = &cmdline_temp_object_only_list.head;
+}
+
+/* Allocate an item with TYPE and DATA. */
+
+static cmdline_union_type *
+cmdline_list_new (cmdline_enum_type type, void *data)
+{
+ cmdline_union_type *new_opt;
+
+ new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
+ new_opt->header.type = type;
+ switch (type)
+ {
+ default:
+ break;
+ case cmdline_is_file_enum:
+ new_opt->file.filename = (const char *) data;
+ break;
+ case cmdline_is_bfd_enum:
+ new_opt->abfd.abfd = (bfd *) data;
+ break;
+ }
+ return new_opt;
+}
+
+/* Append an item with TYPE and DATA to LIST. */
+
+static void
+cmdline_list_append (cmdline_list_type *list, cmdline_enum_type type,
+ void *data)
+{
+ cmdline_union_type *new_opt = cmdline_list_new (type, data);
+ new_opt->header.next = NULL;
+ *list->tail = new_opt;
+ list->tail = &new_opt->header.next;
+}
+
+static void
+print_cmdline_list (cmdline_union_type *c)
+{
+ for (; c != NULL; c = c->header.next)
+ switch (c->header.type)
+ {
+ default:
+ abort ();
+ case cmdline_is_file_enum:
+ info_msg (" %s", c->file.filename);
+ break;
+ case cmdline_is_bfd_enum:
+ info_msg (" [%B]", c->abfd.abfd);
+ break;
+ }
+
+ info_msg ("\n");
+}
+
+/* Return TRUE if ABFD is on cmdline_object_only_archive_list. */
+
+static bfd_boolean
+cmdline_on_object_only_archive_list_p (bfd *abfd)
+{
+ cmdline_union_type *c, *next;
+ bfd *archive, *obfd, *oarchive;
+ ufile_ptr origin = abfd->origin;
+
+ archive = bfd_my_archive (abfd);
+ for (c = cmdline_object_only_archive_list.head; c != NULL; c = next)
+ {
+ if (c->header.type != cmdline_is_bfd_enum)
+ abort ();
+
+ next = c->header.next;
+ obfd = c->abfd.abfd;
+ oarchive = bfd_my_archive (obfd);
+
+ /* The list is grouped by archive file name and sorted by member
+ origin. */
+ if (strcmp (archive->filename, oarchive->filename) != 0)
+ continue;
+
+ if (origin == obfd->origin)
+ return TRUE;
+ else if (origin < obfd->origin)
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+/* Append an item with TYPE and DATA to cmdline_object_only_file_list
+ or cmdline_object_only_archive_list if needed. */
+
+static void
+cmdline_object_only_list_append (cmdline_enum_type type, void *data)
+{
+ cmdline_union_type *c;
+ cmdline_union_type *new_opt, *next, **prev;
+ bfd *abfd, *archive;
+ bfd *obfd, *oarchive;
+ bfd *nbfd, *narchive;
+ ufile_ptr origin, norigin;
+
+ /* Put it on cmdline_object_only_file_list if it isn't an archive
+ member. */
+ switch (type)
+ {
+ default:
+ abort ();
+ case cmdline_is_bfd_enum:
+ abfd = (bfd *) data;
+ archive = bfd_my_archive (abfd);
+ if (archive)
+ break;
+ case cmdline_is_file_enum:
+ cmdline_list_append (&cmdline_object_only_file_list, type, data);
+ return;
+ }
+
+ /* Put archive member on cmdline_object_only_archive_list and sort
+ the list by archive name and archive member origin. */
+ new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
+ new_opt->header.type = cmdline_is_bfd_enum;
+ new_opt->header.next = NULL;
+ new_opt->abfd.abfd = (bfd *) data;
+
+ c = cmdline_object_only_archive_list.head;
+ if (c == NULL)
+ {
+ cmdline_object_only_archive_list.head = new_opt;
+ cmdline_object_only_archive_list.tail = &new_opt->header.next;
+ return;
+ }
+
+ prev = NULL;
+ origin = abfd->origin;
+ for (; c != NULL; c = next)
+ {
+ if (c->header.type != cmdline_is_bfd_enum)
+ abort ();
+
+ next = c->header.next;
+
+ obfd = c->abfd.abfd;
+ oarchive = bfd_my_archive (obfd);
+
+ if (strcmp (archive->filename, oarchive->filename) == 0)
+ {
+ bfd_boolean after;
+
+ if (origin < obfd->origin)
+ {
+ /* Insert it before the current. */
+ new_opt->header.next = c;
+ if (prev)
+ *prev = new_opt;
+ else
+ cmdline_object_only_archive_list.head = new_opt;
+ return;
+ }
+
+ after = TRUE;
+
+ /* Check origin. */
+ while (next)
+ {
+ if (next->header.type != cmdline_is_bfd_enum)
+ abort ();
+
+ nbfd = next->abfd.abfd;
+ norigin = nbfd->origin;
+ if (origin > norigin)
+ {
+ /* Insert it after NEXT. */
+ break;
+ }
+
+ narchive = bfd_my_archive (nbfd);
+ if (strcmp (archive->filename, narchive->filename) != 0)
+ {
+ /* Insert it befor NEXT. */
+ after = FALSE;
+ break;
+ }
+
+ c = next;
+ next = next->header.next;
+ }
+
+ if (after && next)
+ {
+ c = next;
+ next = next->header.next;
+ }
+
+ if (*cmdline_object_only_archive_list.tail == c->header.next)
+ cmdline_object_only_archive_list.tail
+ = &new_opt->header.next;
+
+ prev = &c->header.next;
+ new_opt->header.next = next;
+ *prev = new_opt;
+ return;
+ }
+
+ prev = &c->header.next;
+ }
+
+ *cmdline_object_only_archive_list.tail = new_opt;
+ cmdline_object_only_archive_list.tail = &new_opt->header.next;
+}
+
+/* Get object-only input files. */
+
+static void
+cmdline_get_object_only_input_files (void)
+{
+ cmdline_union_type *c, *next;
+ bfd *abfd, *archive;
+ bfd *nbfd, *narchive;
+
+ /* Add files first. */
+ for (c = cmdline_object_only_file_list.head;
+ c != NULL; c = c->header.next)
+ switch (c->header.type)
+ {
+ default:
+ abort ();
+ case cmdline_is_file_enum:
+ lang_add_input_file (c->file.filename,
+ lang_input_file_is_file_enum, NULL);
+ break;
+ case cmdline_is_bfd_enum:
+ abfd = c->abfd.abfd;
+ if (bfd_my_archive (abfd))
+ abort ();
+ lang_add_input_file (abfd->filename,
+ lang_input_file_is_file_enum, NULL);
+ break;
+ }
+
+ /* Add archive members next. */
+ for (c = cmdline_object_only_archive_list.head; c != NULL; c = next)
+ {
+ if (c->header.type != cmdline_is_bfd_enum)
+ abort ();
+
+ next = c->header.next;
+
+ abfd = c->abfd.abfd;
+ archive = bfd_my_archive (abfd);
- const char *ofilename = NULL;
++
+ /* Add the first archive of the archive member group. */
+ lang_add_input_file (archive->filename,
+ lang_input_file_is_file_enum, NULL);
+
+ /* Skip the rest members in the archive member group. */
+ do
+ {
+ if (!next)
+ break;
+
+ if (next->header.type != cmdline_is_bfd_enum)
+ abort ();
+
+ next = next->header.next;
+ if (!next)
+ break;
+ nbfd = next->abfd.abfd;
+ narchive = bfd_my_archive (nbfd);
+ }
+ while (strcmp (archive->filename, narchive->filename) == 0);
+ }
+}
+
+struct cmdline_arg
+{
+ bfd *obfd;
+ asymbol **isympp;
+ int status;
+};
+
+/* Create a section in OBFD with the same
+ name and attributes as ISECTION in IBFD. */
+
+static void
+setup_section (bfd *ibfd, sec_ptr isection, void *p)
+{
+ struct cmdline_arg *arg = (struct cmdline_arg *) p;
+ bfd *obfd = arg->obfd;
+ asymbol **isympp = arg->isympp;
+ const char *name = isection->name;
+ sec_ptr osection;
+ const char *err;
+
+ /* Skip the object-only section. */
+ if (ibfd->object_only_section == isection)
+ return;
+
+ /* If we have already failed earlier on, do not keep on generating
+ complaints now. */
+ if (arg->status)
+ return;
+
+ osection = bfd_make_section_anyway_with_flags (obfd, name,
+ isection->flags);
+
+ if (osection == NULL)
+ {
+ err = _("failed to create output section");
+ goto loser;
+ }
+
+ osection->size = isection->size;
+ osection->vma = isection->vma;
+ osection->lma = isection->lma;
+ osection->alignment_power = isection->alignment_power;
+
+ /* Copy merge entity size. */
+ osection->entsize = isection->entsize;
+
+ /* This used to be mangle_section; we do here to avoid using
+ bfd_get_section_by_name since some formats allow multiple
+ sections with the same name. */
+ isection->output_section = osection;
+ isection->output_offset = 0;
+
+ if ((isection->flags & SEC_GROUP) != 0)
+ {
+ asymbol *gsym = bfd_group_signature (isection, isympp);
+
+ if (gsym != NULL)
+ {
+ gsym->flags |= BSF_KEEP;
+ if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+ elf_group_id (isection) = gsym;
+ }
+ }
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input section to the output section. */
+ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
+ {
+ err = _("failed to copy private data");
+ goto loser;
+ }
+
+ /* All went well. */
+ return;
+
+loser:
+ arg->status = 1;
+ einfo (_("%P%F: setup_section: %s: %s\n"), err, name);
+}
+
+/* Copy the data of input section ISECTION of IBFD
+ to an output section with the same name in OBFD.
+ If stripping then don't copy any relocation info. */
+
+static void
+copy_section (bfd *ibfd, sec_ptr isection, void *p)
+{
+ struct cmdline_arg *arg = (struct cmdline_arg *) p;
+ bfd *obfd = arg->obfd;
+ asymbol **isympp = arg->isympp;
+ arelent **relpp;
+ long relcount;
+ sec_ptr osection;
+ bfd_size_type size;
+ long relsize;
+ flagword flags;
+ const char *err;
+
+ /* Skip the object-only section. */
+ if (ibfd->object_only_section == isection)
+ return;
+
+ /* If we have already failed earlier on, do not keep on generating
+ complaints now. */
+ if (arg->status)
+ return;
+
+ flags = bfd_get_section_flags (ibfd, isection);
+ if ((flags & SEC_GROUP) != 0)
+ return;
+
+ osection = isection->output_section;
+ size = bfd_get_section_size (isection);
+
+ if (size == 0 || osection == 0)
+ return;
+
+ relsize = bfd_get_reloc_upper_bound (ibfd, isection);
+
+ if (relsize < 0)
+ {
+ /* Do not complain if the target does not support relocations. */
+ if (relsize == -1
+ && bfd_get_error () == bfd_error_invalid_operation)
+ relsize = 0;
+ else
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+ }
+
+ if (relsize == 0)
+ bfd_set_reloc (obfd, osection, NULL, 0);
+ else
+ {
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
+ if (relcount < 0)
+ {
+ err = _("relocation count is negative");
+ goto loser;
+ }
+
+ bfd_set_reloc (obfd, osection,
+ relcount == 0 ? NULL : relpp, relcount);
+ if (relcount == 0)
+ free (relpp);
+ }
+
+ if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS)
+ {
+ bfd_byte *memhunk = NULL;
+
+ if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+ free (memhunk);
+ }
+
+ /* All went well. */
+ return;
+
+loser:
+ einfo (_("%P%F: copy_section: %s: %s\n"), err, isection->name);
+}
+/* Open the temporary bfd created in the same directory as PATH. */
+
+static bfd *
+cmdline_fopen_temp (const char *path, const char *target,
+ const char *mode)
+{
+#define template "ldXXXXXX"
+ const char *slash = strrchr (path, '/');
+ char *tmpname;
+ size_t len;
+ int fd;
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ {
+ /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
+ char *bslash = strrchr (path, '\\');
+
+ if (slash == NULL || (bslash != NULL && bslash > slash))
+ slash = bslash;
+ if (slash == NULL && path[0] != '\0' && path[1] == ':')
+ slash = path + 1;
+ }
+#endif
+
+ if (slash != (char *) NULL)
+ {
+ len = slash - path;
+ tmpname = (char *) xmalloc (len + sizeof (template) + 2);
+ memcpy (tmpname, path, len);
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ /* If tmpname is "X:", appending a slash will make it a root
+ directory on drive X, which is NOT the same as the current
+ directory on drive X. */
+ if (len == 2 && tmpname[1] == ':')
+ tmpname[len++] = '.';
+#endif
+ tmpname[len++] = '/';
+ }
+ else
+ {
+ tmpname = (char *) xmalloc (sizeof (template));
+ len = 0;
+ }
+
+ memcpy (tmpname + len, template, sizeof (template));
+#undef template
+
+#ifdef HAVE_MKSTEMP
+ fd = mkstemp (tmpname);
+#else
+ tmpname = mktemp (tmpname);
+ if (tmpname == NULL)
+ return NULL;
+ fd = open (tmpname, O_RDWR | O_CREAT | O_EXCL, 0600);
+#endif
+ if (fd == -1)
+ return NULL;
+ return bfd_fopen (tmpname, target, mode, fd);
+}
+
+/* Add the object-only section. */
+
+static void
+cmdline_add_object_only_section (bfd_byte *contents, size_t size)
+{
+ bfd_vma start;
+ flagword flags;
+ enum bfd_architecture iarch;
+ unsigned int imach;
+ long symcount;
+ long symsize;
+ asymbol **isympp = NULL;
+ asymbol **osympp = NULL;
+ bfd *obfd = NULL, *ibfd;
+ const char *err;
+ struct arg
+ {
+ bfd *obfd;
+ asymbol **isympp;
+ int status;
+ } arg;
+ char **matching;
- ofilename = bfd_get_filename (obfd);
++ char *ofilename = NULL;
+ asection *sec;
+
+ ibfd = bfd_openr (output_filename, output_target);
+ if (!ibfd)
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ if (!bfd_check_format_matches (ibfd, bfd_object, &matching))
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ obfd = cmdline_fopen_temp (output_filename, output_target, "w");
+ if (!obfd)
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
-
++ /* To be used after bfd_close (). */
++ ofilename = xstrdup (bfd_get_filename (obfd));
+
+ if (!bfd_set_format (obfd, bfd_object))
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ /* Copy the start address, flags and architecture of input file to
+ output file. */
+ flags = bfd_get_file_flags (ibfd);
+ start = bfd_get_start_address (ibfd);
+ iarch = bfd_get_arch (ibfd);
+ imach = bfd_get_mach (ibfd);
+ if (!bfd_set_start_address (obfd, start)
+ || !bfd_set_file_flags (obfd, flags)
+ || !bfd_set_arch_mach (obfd, iarch, imach))
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
-
++
+ symsize = bfd_get_symtab_upper_bound (ibfd);
+ if (symsize < 0)
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ isympp = (asymbol **) xmalloc (symsize);
+ symcount = bfd_canonicalize_symtab (ibfd, isympp);
+ if (symcount < 0)
+ {
+ err = bfd_errmsg (bfd_get_error ());
+ goto loser;
+ }
+
+ arg.obfd = obfd;
+ arg.isympp = isympp;
+ arg.status = 0;
+
+ /* BFD mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections multiple times. */
+ bfd_map_over_sections (ibfd, setup_section, &arg);
+
+ if (arg.status)
+ {
+ err = _("error setting up sections");
+ goto loser;
+ }
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input section to the output section. */
+ if (! bfd_copy_private_header_data (ibfd, obfd))
+ {
+ err = _("error copying private header data");
+ goto loser;
+ }
+
+ /* Create the object-only section. */
+ sec = bfd_make_section_with_flags (obfd,
+ GNU_OBJECT_ONLY_SECTION_NAME,
+ (SEC_HAS_CONTENTS
+ | SEC_READONLY
+ | SEC_DATA
+ | SEC_LINKER_CREATED));
+ if (sec == NULL)
+ {
+ err = _("can't create object-only section");
+ goto loser;
+ }
+
+ if (! bfd_set_section_size (obfd, sec, size))
+ {
+ err = _("can't set object-only section size");
+ goto loser;
+ }
+
+ if (ibfd->object_only_section)
+ {
+ /* Filter out the object-only section symbol. */
+ long src_count = 0, dst_count = 0;
+ asymbol **from, **to;
+
+ osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
+ from = isympp;
+ to = osympp;
+ for (; src_count < symcount; src_count++)
+ {
+ asymbol *sym = from[src_count];
+ if (bfd_get_section (sym) != ibfd->object_only_section)
+ to[dst_count++] = sym;
+ }
+ to[dst_count] = NULL;
+ symcount = dst_count;
+ bfd_set_symtab (obfd, osympp, symcount);
+ }
+ else
+ bfd_set_symtab (obfd, isympp, symcount);
+
+ /* This has to happen after the symbol table has been set. */
+ bfd_map_over_sections (ibfd, copy_section, &arg);
+
+ if (arg.status)
+ {
+ err = _("error copying sections");
+ goto loser;
+ }
+
+ /* Copy the object-only section to the output. */
+ if (! bfd_set_section_contents (obfd, sec, contents, 0, size))
+ {
+ err = _("error adding object-only section");
+ goto loser;
+ }
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input BFD to the output BFD. This is done last to
+ permit the routine to look at the filtered symbol table, which is
+ important for the ECOFF code at least. */
+ if (! bfd_copy_private_bfd_data (ibfd, obfd))
+ {
+ err = _("error copying private BFD data");
+ goto loser;
+ }
+
+ if (!bfd_close (obfd))
+ {
+ unlink (ofilename);
+ einfo (_("%P%F: failed to finish output with object-only section\n"));
+ }
+
+ /* Must be freed after bfd_close (). */
+ free (isympp);
+ if (osympp)
+ free (osympp);
+
+ if (rename (ofilename, output_filename))
+ {
+ unlink (ofilename);
+ einfo (_("%P%F: failed to rename output with object-only section\n"));
+ }
+
++ free (ofilename);
+ return;
+
+loser:
+ if (isympp)
+ free (isympp);
+ if (osympp)
+ free (osympp);
+ if (obfd)
+ bfd_close (obfd);
+ if (ofilename)
+ unlink (ofilename);
+ einfo (_("%P%F: failed to add object-only section: %s\n"), err);
+}
+
+/* Emit the final output with object-only section. */
+
+void
+cmdline_emit_object_only_section (void)
+{
+ const char *saved_output_filename = output_filename;
+ int fd;
+ size_t size, off;
+ bfd_byte *contents;
+ struct stat st;
+
+ /* Get a temporary object-only file. */
+ output_filename = make_temp_file (".obj-only.o");
+
+ had_output_filename = FALSE;
+ link_info.input_bfds = NULL;
+ link_info.input_bfds_tail = &link_info.input_bfds;
+
+ lang_init (TRUE);
+
+ ld_parse_linker_script ();
+
+ /* Set up the object-only output. */
+ lang_final ();
+
+ /* Open the object-only file for output. */
+ lang_for_each_statement (ldlang_open_output);
+
+ ldemul_create_output_section_statements ();
+
+ if (!bfd_section_already_linked_table_init ())
+ einfo (_("%P%F: Failed to create hash table\n"));
+
+ /* Call cmdline_on_object_only_archive_list_p to check which member
+ should be loaded. */
+ input_flags.whole_archive = TRUE;
+
+ /* Set it to avoid adding more to cmdline lists. */
+ link_info.emitting_gnu_object_only = TRUE;
+
+ /* Get object-only input files. */
+ cmdline_get_object_only_input_files ();
+
+ /* Open object-only input files. */
+ open_input_bfds (statement_list.head, FALSE);
+
+ ldemul_after_open ();
+
+ bfd_section_already_linked_table_free ();
+
+ /* Make sure that we're not mixing architectures. We call this
+ after all the input files have been opened, but before we do any
+ other processing, so that any operations merge_private_bfd_data
+ does on the output file will be known during the rest of the
+ link. */
+ lang_check ();
+
+ /* Size up the common data. */
+ lang_common ();
+
+ /* Update wild statements. */
+ update_wild_statements (statement_list.head);
+
+ /* Run through the contours of the script and attach input sections
+ to the correct output sections. */
+ map_input_to_output_sections (statement_list.head, NULL, NULL);
+
+ /* Find any sections not attached explicitly and handle them. */
+ lang_place_orphans ();
+
+ /* Do anything special before sizing sections. This is where ELF
+ and other back-ends size dynamic sections. */
+ ldemul_before_allocation ();
+
+ /* Size up the sections. */
+ lang_size_sections (NULL, ! RELAXATION_ENABLED);
+
+ /* See if anything special should be done now we know how big
+ everything is. This is where relaxation is done. */
+ ldemul_after_allocation ();
+
+ ldemul_finish ();
+
+ /* Make sure that the section addresses make sense. */
+ if (command_line.check_section_addresses)
+ lang_check_section_addresses ();
+
+ lang_end ();
- /* Remove the temporary object-only file. */
++
+ ldwrite ();
+
+ lang_finish (TRUE);
+
+ if (! bfd_close (link_info.output_bfd))
+ einfo (_("%P%F:%s: final close failed on object-only output: %E\n"),
+ output_filename);
+
+ /* Read in the object-only file. */
+ fd = open (output_filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ einfo (_("%P%F:%s: cannot open object-only output: %E"),
+ output_filename);
+ }
+
+ /* Get the object-only file size. */
+ if (fstat (fd, &st) != 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ einfo (_("%P%F:%s: cannot stat object-only output: %E"),
+ output_filename);
+ }
+
+ size = st.st_size;
+ off = 0;
+ contents = (bfd_byte *) xmalloc (size);
+ while (off != size)
+ {
+ ssize_t got;
+
+ got = read (fd, contents + off, size - off);
+ if (got < 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ einfo (_("%P%F:%s: read failed on object-only output: %E"),
+ output_filename);
+ }
+
+ off += got;
+ }
+
+ close (fd);
+
++ /* Remove the temporary object-only file. */
+ unlink (output_filename);
+
+ output_filename = saved_output_filename;
+
+ cmdline_add_object_only_section (contents, size);
+
+ free (contents);
+}
+
+/* Extract the object-only section. */
+
+static const char *
+cmdline_extract_object_only_section (bfd *abfd)
+{
+ const char *name = bfd_extract_object_only_section (abfd);
+
+ if (name == NULL)
+ einfo (_("%P%F: cannot extract object-only section from %B: %E"),
+ abfd);
+
+ /* It should be removed after it is done. */
+ cmdline_list_append (&cmdline_temp_object_only_list,
+ cmdline_is_file_enum, (void *) name);
+
+ return name;
+}
+
+/* Check and handle the object-only section. */
+
+void
+cmdline_check_object_only_section (bfd *abfd, bfd_boolean lto)
+{
+ const char *filename;
+
+ if (link_info.emitting_gnu_object_only
+ || abfd->format != bfd_object)
+ return;
+
+ if (lto)
+ {
+ /* For LTO link, we only need to extract object-only section
+ from the mixed object, add it to input, and put it on LTO
+ claimed output. */
+ switch (abfd->lto_type)
+ {
+ default:
+ abort ();
+ case lto_mixed_object:
+ filename = cmdline_extract_object_only_section (abfd);
+ lang_add_input_file (filename,
+ lang_input_file_is_file_enum, NULL);
+ break;
+ case lto_non_ir_object:
+ case lto_ir_object:
+ break;
+ }
+ }
+ else if (link_info.relocatable)
+ {
+ /* For non-LTO relocatable link, we need to append non-IR object
+ file and the object file in object-only section to the object
+ only list. */
+ switch (abfd->lto_type)
+ {
+ default:
+ abort ();
+ case lto_mixed_object:
+ filename = cmdline_extract_object_only_section (abfd);
+ cmdline_object_only_list_append (cmdline_is_file_enum,
+ (void *) filename);
+ break;
+ case lto_non_ir_object:
+ cmdline_object_only_list_append (cmdline_is_bfd_enum, abfd);
+ break;
+ case lto_ir_object:
+ break;
+ }
+ }
+}
+
+/* Remove temporary object-only files. */
+
+void
+cmdline_remove_object_only_files (void)
+{
+ cmdline_union_type *c;
+
+#ifdef ENABLE_PLUGINS
+ if (plugin_save_temps)
+ return;
+#endif
+
+ c = cmdline_temp_object_only_list.head;
+ for (; c != NULL; c = c->header.next)
+ switch (c->header.type)
+ {
+ default:
+ abort ();
+ case cmdline_is_file_enum:
+ unlink (c->file.filename);
+ break;
+ }
+}
extern lang_statement_list_type input_file_chain;
extern int lang_statement_iteration;
+ extern struct asneeded_minfo **asneeded_list_tail;
extern void lang_init
- (void);
+ (bfd_boolean);
extern void lang_finish
- (void);
+ (bfd_boolean);
extern lang_memory_region_type * lang_memory_region_lookup
(const char * const, bfd_boolean);
extern void lang_memory_region_alias
#...
Relocation section '.rela.dyn' at offset 0x... contains 1 entries:
Offset +Info +Type +Sym.Value +Sym. Name \+ Addend
--.* R_CRIS_COPY .* __expobj2 \+ 0
++.* R_CRIS_COPY .* __expobj2@TST3 \+ 0
Relocation section '.rela.plt' at offset 0x... contains 1 entries:
Offset +Info +Type +Sym.Value +Sym. Name \+ Addend
--.* R_CRIS_JUMP_SLOT .* expfn2 \+ 0
++.* R_CRIS_JUMP_SLOT .* expfn2@TST3 \+ 0
The decoding of unwind sections for machine type Axis Communications 32-bit embedded processor is not currently supported.
#...
Relocation section '.rela.dyn' at offset 0x... contains 1 entries:
#...
--.* R_CRIS_COPY .* __expobj2 \+ 0
++.* R_CRIS_COPY .* __expobj2@TST3 \+ 0
The decoding of unwind sections for machine type Axis Communications 32-bit embedded processor is not currently supported.
--- /dev/null
--- /dev/null
++void
++sd_get_seats (void)
++{
++}
--- /dev/null
--- /dev/null
++LIBSYSTEMD_209 {
++global:
++ sd_get_seats;
++};
--- /dev/null
--- /dev/null
++void sd_get_seats (void);
++void call_sd_get_seats (void)
++{
++ sd_get_seats ();
++}
--- /dev/null
--- /dev/null
++#...
++.* sd_get_seats@LIBSYSTEMD_209
++#pass
{"Build needed2"
"tmpdir/libneeded2c.o -Wl,--as-needed tmpdir/libneeded2a.so tmpdir/libneeded2b.so" ""
{dummy.c} {} "needed2"}
+ {"Build libpr2404a.so"
+ "-shared" "-fPIC"
+ {pr2404a.c} {} "libpr2404a.so"}
+ {"Build libpr2404b.a"
+ "" ""
+ {pr2404b.c} {} "libpr2404b.a"}
++ {"Build libpr16496a.so"
++ "-shared -Wl,--version-script=pr16496a.map" "-fPIC"
++ {pr16496a.c} {} "libpr16496a.so"}
++ {"Build libpr16496b.a"
++ "" "-fPIC"
++ {pr16496b.c} {} "libpr16496b.a"}
++ {"Build libpr16496b.so"
++ "-shared tmpdir/pr16496b.o tmpdir/libpr16496a.so" ""
++ {dummy.c} {{objdump {-R} pr16496b.od}} "libpr16496b.so"}
}
run_cc_link_tests $build_tests
Relocation section .*
# Ensure there is a dynamic relocation against x
#...
--[0-9a-f]+ +[0-9a-f]+ R_.* +_?x(| \+ 0)
++[0-9a-f]+ +[0-9a-f]+ R_.* +_?x@VERS.0(| \+ 0)
#...
Symbol table '.dynsym' contains [0-9]+ entries:
# And ensure the dynamic symbol table contains at least x@VERS.0
--- /dev/null
-
+#define ASMNAME(cname) ASMNAME2 (__USER_LABEL_PREFIX__, cname)
+#define ASMNAME2(prefix, cname) STRING (prefix) cname
+#define STRING(x) #x
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern void *memcpy (void *, const void *, size_t)
+ __asm (ASMNAME ("my_memcpy"));
+extern void bcopy (const void *, void *, size_t)
+ __asm (ASMNAME ("my_bcopy"));
+extern void *memset (void *, int, size_t)
+ __asm (ASMNAME ("my_memset"));
+extern void bzero (void *, size_t)
+ __asm (ASMNAME ("my_bzero"));
+extern int memcmp (const void *, const void *, size_t);
+
+struct A { char c[32]; } a = { "foobar" };
+char x[64] = "foobar", y[64];
+int i = 39, j = 6, k = 4;
+
+extern int inside_main;
+
+void
+main_test (void)
+{
+ struct A b = a;
+ struct A c = { { 'x' } };
+
+ inside_main = 1;
++
+ if (memcmp (b.c, x, 32) || c.c[0] != 'x' || memcmp (c.c + 1, x + 32, 31))
+ abort ();
+ if (__builtin_memcpy (y, x, i) != y || memcmp (x, y, 64))
+ abort ();
+ if (memcpy (y + 6, x, j) != y + 6
+ || memcmp (x, y, 6) || memcmp (x, y + 6, 58))
+ abort ();
+ if (__builtin_memset (y + 2, 'X', k) != y + 2
+ || memcmp (y, "foXXXXfoobar", 13))
+ abort ();
+ bcopy (y + 1, y + 2, 6);
+ if (memcmp (y, "fooXXXXfobar", 13))
+ abort ();
+ __builtin_bzero (y + 4, 2);
+ if (memcmp (y, "fooX\0\0Xfobar", 13))
+ abort ();
+}