bfd_boolean bfd_fill_in_gnu_debuglink_section
(bfd *abfd, struct bfd_section *sect, const char *filename);
+ char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir);
+
+const char *bfd_extract_object_only_section
+ (bfd *abfd);
+
/* Extracted from libbfd.c. */
/* Byte swapping macros for user section data. */
represent variables; this can cause confusion in principle, but
any such confusion would seem to indicate an erroneous program or
shared library. We also permit a common symbol in a regular
- object to override a weak symbol in a shared object. A common
- symbol in executable also overrides a symbol in a shared object.
- object to override a weak symbol in a shared object. */
++ object to override a weak symbol in a shared object.
+
+ We let a definition in a dynamic object override the old secondary
+ symbol. */
if (newdyn
&& newdef
+ && !oldsecondary
&& (olddef
|| (h->root.type == bfd_link_hash_common
- && (newweak
- || newfunc
- || (!olddyn && bfd_link_executable (info))))))
+ && (newweak || newfunc))))
{
*override = TRUE;
newdef = FALSE;
#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
+#if BFD_SUPPORTS_PLUGINS
++#include "plugin-api.h"
+#include "plugin.h"
+#endif
/* IMPORT from targets.c. */
extern const size_t _bfd_target_vector_entries;
return TRUE;
}
- file = real_fopen (name, FOPEN_WB);
+ /*
+ INTERNAL_FUNCTION
+ get_build_id
+
+ SYNOPSIS
+ struct bfd_build_id * get_build_id (bfd *abfd);
+
+ DESCRIPTION
+ Finds the build-id associated with @var{abfd}. If the build-id is
+ extracted from the note section then a build-id structure is built
+ for it, using memory allocated to @var{abfd}, and this is then
+ attached to the @var{abfd}.
+
+ RETURNS
+ Returns a pointer to the build-id structure if a build-id could be
+ found. If no build-id is found NULL is returned and error code is
+ set.
+ */
+
+ static struct bfd_build_id *
+ get_build_id (bfd *abfd)
+ {
+ struct bfd_build_id *build_id;
+ Elf_Internal_Note inote;
+ Elf_External_Note *enote;
+ bfd_byte *contents;
+ asection *sect;
+ bfd_size_type size;
+
+ BFD_ASSERT (abfd);
+
+ if (abfd->build_id && abfd->build_id->size > 0)
+ /* Save some time by using the already computed build-id. */
+ return (struct bfd_build_id *) abfd->build_id;
+
+ sect = bfd_get_section_by_name (abfd, ".note.gnu.build-id");
+ if (sect == NULL)
+ {
+ bfd_set_error (bfd_error_no_debug_section);
+ return NULL;
+ }
+
+ size = bfd_get_section_size (sect);
+ /* FIXME: Should we support smaller build-id notes ? */
+ if (size < 0x24)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ if (!bfd_malloc_and_get_section (abfd, sect, & contents))
+ {
+ if (contents != NULL)
+ free (contents);
+ return NULL;
+ }
+
+ /* FIXME: Paranoia - allow for compressed build-id sections.
+ Maybe we should complain if this size is different from
+ the one obtained above... */
+ size = bfd_get_section_size (sect);
+ if (size < sizeof (Elf_External_Note))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ free (contents);
+ return NULL;
+ }
+
+ enote = (Elf_External_Note *) contents;
+ inote.type = H_GET_32 (abfd, enote->type);
+ inote.namesz = H_GET_32 (abfd, enote->namesz);
+ inote.namedata = enote->name;
+ inote.descsz = H_GET_32 (abfd, enote->descsz);
+ inote.descdata = inote.namedata + BFD_ALIGN (inote.namesz, 4);
+ /* FIXME: Should we check for extra notes in this section ? */
+
+ if (inote.descsz == 0
+ || inote.type != NT_GNU_BUILD_ID
+ || inote.namesz != 4 /* sizeof "GNU" */
+ || strncmp (inote.namedata, "GNU", 4) != 0
+ || size < (12 + BFD_ALIGN (inote.namesz, 4) + inote.descsz))
+ {
+ free (contents);
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) + inote.descsz);
+ if (build_id == NULL)
+ {
+ free (contents);
+ return NULL;
+ }
+
+ build_id->size = inote.descsz;
+ memcpy (build_id->data, inote.descdata, inote.descsz);
+ abfd->build_id = build_id;
+ free (contents);
+
+ return build_id;
+ }
+
+ /*
+ INTERNAL_FUNCTION
+ get_build_id_name
+
+ SYNOPSIS
+ char * get_build_id_name (bfd *abfd, void *build_id_out_p)
+
+ DESCRIPTION
+ Searches @var{abfd} for a build-id, and then constructs a pathname
+ from it. The path is computed as .build-id/NN/NN+NN.debug where
+ NNNN+NN is the build-id value as a hexadecimal string.
+
+ RETURNS
+ Returns the constructed filename or NULL upon error.
+ It is the caller's responsibility to free the memory used to hold the
+ filename.
+ If a filename is returned then the @var{build_id_out_p}
+ parameter (which points to a @code{struct bfd_build_id}
+ pointer) is set to a pointer to the build_id structure.
+ */
+
+ static char *
+ get_build_id_name (bfd *abfd, void *build_id_out_p)
+ {
+ struct bfd_build_id **build_id_out = build_id_out_p;
+ struct bfd_build_id *build_id;
+ char *name;
+ char *n;
+ bfd_size_type s;
+ bfd_byte *d;
+
+ if (abfd == NULL || abfd->filename == NULL || build_id_out == NULL)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return NULL;
+ }
+
+ build_id = get_build_id (abfd);
+ if (build_id == NULL)
+ return NULL;
+
+ /* Compute the debug pathname corresponding to the build-id. */
+ name = bfd_malloc (strlen (".build-id/") + build_id->size * 2 + 2 + strlen (".debug"));
+ if (name == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+ n = name;
+ d = build_id->data;
+ s = build_id->size;
+
+ n += sprintf (n, ".build-id/");
+ n += sprintf (n, "%02x", (unsigned) *d++); s--;
+ n += sprintf (n, "/");
+ while (s--)
+ n += sprintf (n, "%02x", (unsigned) *d++);
+ n += sprintf (n, ".debug");
+
+ *build_id_out = build_id;
+ return name;
+ }
+
+ /*
+ INTERNAL_FUNCTION
+ check_build_id_file
+
+ SYNOPSIS
+ bfd_boolean check_build_id_file (char *name, void *buildid_p);
+
+ DESCRIPTION
+ Checks to see if @var{name} is a readable file and if its build-id
+ matches @var{buildid}.
+
+ RETURNS
+ Returns TRUE if the file exists, is readable, and contains a
+ build-id which matches the build-id pointed at by
+ @var{build_id_p} (which is really a @code{struct bfd_build_id **}).
+ */
+
+ static bfd_boolean
+ check_build_id_file (const char *name, void *buildid_p)
+ {
+ struct bfd_build_id *orig_build_id;
+ struct bfd_build_id *build_id;
+ bfd * file;
+ bfd_boolean result;
+
+ BFD_ASSERT (name);
+ BFD_ASSERT (buildid_p);
+
+ file = bfd_openr (name, NULL);
+ if (file == NULL)
+ return FALSE;
+
+ /* If the file is an archive, process all of its elements. */
+ if (! bfd_check_format (file, bfd_object))
+ {
+ bfd_close (file);
+ return FALSE;
+ }
+
+ build_id = get_build_id (file);
+ if (build_id == NULL)
+ {
+ bfd_close (file);
+ return FALSE;
+ }
+
+ orig_build_id = *(struct bfd_build_id **) buildid_p;
+
+ result = build_id->size == orig_build_id->size
+ && memcmp (build_id->data, orig_build_id->data, build_id->size) == 0;
+
+ (void) bfd_close (file);
+
+ return result;
+ }
+
+ /*
+ FUNCTION
+ bfd_follow_build_id_debuglink
+
+ SYNOPSIS
+ char *bfd_follow_build_id_debuglink (bfd *abfd, const char *dir);
+
+ DESCRIPTION
+ Takes @var{abfd} and searches it for a .note.gnu.build-id section.
+ If this section is found, it extracts the value of the NT_GNU_BUILD_ID
+ note, which should be a hexadecimal value @var{NNNN+NN} (for
+ 32+ hex digits). It then searches the filesystem for a file named
+ @var{.build-id/NN/NN+NN.debug} in a set of standard locations,
+ including the directory tree rooted at @var{dir}. The filename
+ of the first matching file to be found is returned. A matching
+ file should contain a .note.gnu.build-id section with the same
+ @var{NNNN+NN} note as @var{abfd}, although this check is currently
+ not implemented.
+
+ If @var{dir} is NULL, the search will take place starting at
+ the current directory.
+
+ RETURNS
+ <<NULL>> on any errors or failure to locate the debug file,
+ otherwise a pointer to a heap-allocated string containing the
+ filename. The caller is responsible for freeing this string.
+ */
+
+ char *
+ bfd_follow_build_id_debuglink (bfd *abfd, const char *dir)
+ {
+ struct bfd_build_id *build_id;
+
+ return find_separate_debug_file (abfd, dir, FALSE,
+ get_build_id_name,
+ check_build_id_file, &build_id);
+ }
++
+/*
+FUNCTION
+ bfd_extract_object_only_section
+
+SYNOPSIS
+ const char *bfd_extract_object_only_section
+ (bfd *abfd);
+
+DESCRIPTION
+
+ Takes a @var{ABFD} and extract the .gnu_object_only section into
+ a temporary file.
+
+RETURNS
+ The name of the temporary file is returned if all is ok.
+ Otherwise <<NULL>> is returned and bfd_error is set.
+*/
+
+const char *
+bfd_extract_object_only_section (bfd *abfd)
+{
+ asection *sec = abfd->object_only_section;
+ const char *name;
+ FILE *file;
+ bfd_byte *memhunk = NULL;
+ size_t off, size;
+ bfd_error_type err;
+
+ /* Get a temporary object-only file. */
+ name = make_temp_file (".obj-only.o");
+
+ /* Open the object-only file. */
++ file = _bfd_real_fopen (name, FOPEN_WB);
+ if (!bfd_get_full_section_contents (abfd, sec, &memhunk))
+ {
+ err = bfd_get_error ();
+
+loser:
+ free (memhunk);
+ fclose (file);
+ unlink (name);
+ bfd_set_error (err);
+ return NULL;
+ }
+
+ off = 0;
+ size = sec->size;
+ while (off != size)
+ {
+ size_t written, nwrite = size - off;
+
+ written = fwrite (memhunk + off, 1, nwrite, file);
+ if (written < nwrite && ferror (file))
+ {
+ err = bfd_error_system_call;
+ goto loser;
+ }
+
+ off += written;
+ }
+
+ free (memhunk);
+ fclose (file);
+ return name;
+}
return LDPS_OK;
}
- = BFD_FAKE_SECTION (bfd_plugin_fake_text_section, 0, 0, ".text", 0);
+static asection bfd_plugin_fake_text_section
- = BFD_FAKE_SECTION (bfd_plugin_fake_common_section, SEC_IS_COMMON, 0,
- NULL, 0);
++ = BFD_FAKE_SECTION (bfd_plugin_fake_text_section, NULL, ".text", 0, 0);
+static asection bfd_plugin_fake_common_section
++ = BFD_FAKE_SECTION (bfd_plugin_fake_common_section, NULL, NULL,
++ 0, SEC_IS_COMMON);
+
+/* 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_error_handler)
+ (_("%s: failed to open to extract object only section: %s"),
+ abfd->filename, bfd_errmsg (bfd_get_error ()));
+ goto error_return;
+ }
+ else if (!bfd_check_format (nbfd, bfd_object))
+ {
+ /* There is no object only section if it isn't a bfd_object
+ file. */
+error_return:
+ 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,
int
S_FORCE_RELOC (symbolS *s, int strict)
{
+ segT sec;
if (LOCAL_SYMBOL_CHECK (s))
- return ((struct local_symbol *) s)->lsy_section == undefined_section;
-
- return ((strict
+ sec = ((struct local_symbol *) s)->lsy_section;
+ else
+ {
+ if ((strict
- && ((s->bsym->flags & BSF_WEAK) != 0
+ && ((s->bsym->flags & (BSF_WEAK | BSF_SECONDARY)) != 0
|| (EXTERN_FORCE_RELOC
&& (s->bsym->flags & BSF_GLOBAL) != 0)))
- || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0
- || s->bsym->section == undefined_section
- || bfd_is_com_section (s->bsym->section));
+ || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0)
+ return TRUE;
+ sec = s->bsym->section;
+ }
+ return bfd_is_und_section (sec) || bfd_is_com_section (sec);
}
int
--- /dev/null
-check_fold icf_safe_pie_test.map "_ZN1AD2Ev" "_ZN1AC2Ev"
+ #!/bin/sh
+
+ # icf_safe_pie_test.sh -- test --icf=safe -pie
+
+ # Copyright (C) 2009-2017 Free Software Foundation, Inc.
+ # Written by Sriraman Tallam <tmsriram@google.com>.
+ # Modified by Rahul Chaudhry <rahulchaudhry@google.com>.
+
+ # This file is part of gold.
+
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation; either version 3 of the License, or
+ # (at your option) any later version.
+
+ # This program is distributed in the hope that it will be useful,
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ # GNU General Public License for more details.
+
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ # MA 02110-1301, USA.
+
+ # The goal of this program is to verify if --icf=safe works with
+ # -pie as expected. File icf_safe_test.cc is in this test. This
+ # program checks if only ctors and dtors are folded, except for
+ # the architectures which use relocation types and instruction
+ # opcodes to detect if function pointers are taken.
+
+ set -e
+
+ check_nofold()
+ {
+ func_addr_1=`grep $2 $1 | awk '{print $1}'`
+ func_addr_2=`grep $3 $1 | awk '{print $1}'`
+ if [ $func_addr_1 = $func_addr_2 ]
+ then
+ echo "Safe Identical Code Folding folded" $2 "and" $3
+ exit 1
+ fi
+ }
+
+ check_fold()
+ {
+ awk "
+ BEGIN { discard = 0; }
+ /^Discarded input/ { discard = 1; }
+ /^Memory map/ { discard = 0; }
+ /.*\\.text\\..*($2|$3).*/ { act[discard] = act[discard] \" \" \$0; }
+ END {
+ # printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\";
+ if (length(act[0]) == 0 || length(act[1]) == 0)
+ {
+ printf \"Safe Identical Code Folding did not fold $2 and $3\\n\"
+ exit 1;
+ }
+ }" $1
+ }
+
+ arch_specific_safe_fold()
+ {
+ if grep -q -e "Advanced Micro Devices X86-64" -e "Intel 80386" -e "ARM" -e "TILE" -e "PowerPC" -e "AArch64" -e "IBM S/390" $2;
+ then
+ check_fold $3 $4 $5
+ else
+ check_nofold $1 $4 $5
+ fi
+ }
+
+ arch_specific_safe_fold icf_safe_pie_test_1.stdout icf_safe_pie_test_2.stdout \
+ icf_safe_pie_test.map "kept_func_1" "kept_func_2"
++if grep -q _ZN1A[CD]2Ev icf_safe_pie_test_1.stdout
++then
++ check_fold icf_safe_pie_test.map "_ZN1AD2Ev" "_ZN1AC2Ev"
++fi
+ check_nofold icf_safe_pie_test_1.stdout "kept_func_3" "kept_func_1"
+ check_nofold icf_safe_pie_test_1.stdout "kept_func_3" "kept_func_2"
/.*\\.text\\..*($2|$3).*/ { act[discard] = act[discard] \" \" \$0; }
END {
# printf \"kept\" act[0] \"\\nfolded\" act[1] \"\\n\";
-- if (length(act[0]) == 0 || length(act[1]) == 0)
++ # Since one or both symbols can be folded here, it is an error only
++ # if no symbol is folded.
++ if (length(act[1]) == 0)
{
printf \"Safe Identical Code Folding did not fold $2 and $3\\n\"
exit 1;
arch_specific_safe_fold icf_safe_test_1.stdout icf_safe_test_2.stdout \
icf_safe_test.map "kept_func_1" "kept_func_2"
--check_fold icf_safe_test.map "_ZN1AD2Ev" "_ZN1AC2Ev"
++if grep -q _ZN1A[CD]2Ev icf_safe_test_1.stdout
++then
++ check_fold icf_safe_test.map "_ZN1AD2Ev" "_ZN1AC2Ev"
++fi
check_nofold icf_safe_test_1.stdout "kept_func_3" "kept_func_1"
check_nofold icf_safe_test_1.stdout "kept_func_3" "kept_func_2"
in a linker script. */
unsigned int linker_def : 1;
+ /* Symbol defined in a linker script. */
+ unsigned int ldscript_def : 1;
+
+ /* Set if it is a secondary symbol. */
+ unsigned int secondary : 1;
+
/* A union of information depending upon the type. */
union
{
}
}
- finish_default ();
+ gld${EMULATION_NAME}_finish ();
- if (thumb_entry_symbol)
+ if (params.thumb_entry_symbol)
{
- h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol,
+ h = bfd_link_hash_lookup (link_info.hash, params.thumb_entry_symbol,
FALSE, FALSE, TRUE);
}
else
if (msg != NULL)
free (msg);
- ppc64_elf_restore_symbols (&link_info);
- finish_default ();
+ gld${EMULATION_NAME}_finish ();
}
leave no trace. */
default_bfd_assert_handler = bfd_set_assert_handler (ld_bfd_assert_handler);
+ /* Also hook the bfd error/warning handler for --fatal-warnings. */
+ default_bfd_error_handler = bfd_set_error_handler (ld_bfd_error_handler);
+
xatexit (ld_cleanup);
+ /* Remove temporary object-only files. */
+ xatexit (cmdline_remove_object_only_files);
+
/* Set up the sysroot directory. */
ld_sysroot = get_sysroot (argc, argv);
if (*ld_sysroot)
fprintf (file, _("\
-z nocommon Generate common symbols with STT_OBJECT type\n"));
fprintf (file, _("\
- -z stacksize=SIZE Set size of stack segment\n"));
+ -z nosecondary Convert secondary symbols to weak symbols\n"));
+ fprintf (file, _("\
+ -z stack-size=SIZE Set size of stack segment\n"));
fprintf (file, _("\
-z text Treat DT_TEXTREL in shared object as error\n"));
fprintf (file, _("\