# This shell script emits a C file. -*- C -*-
-# It does some substitutions.
-ELFSIZE=32
-cat >e${EMULATION_NAME}.c <<EOF
-/* This file is is generated by a shell script. DO NOT EDIT! */
-
-/* emulate the original gld for the given ${EMULATION_NAME}
- Copyright (C) 1991, 93, 96, 97, 98, 1999 Free Software Foundation, Inc.
- Written by Steve Chamberlain steve@cygnus.com
-
-This file is part of GLD, the Gnu Linker.
-
-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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#define TARGET_IS_${EMULATION_NAME}
-
-#include "bfd.h"
-#include "sysdep.h"
-
-#include <ctype.h>
-
-#include "bfdlink.h"
-#include "getopt.h"
-
-#include "ld.h"
-#include "ldmain.h"
-#include "ldemul.h"
-#include "ldfile.h"
-#include "ldmisc.h"
-
-#include "ldexp.h"
-#include "ldlang.h"
-#include "ldgram.h"
-
-static boolean gld${EMULATION_NAME}_open_dynamic_archive
- PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
-static void gld${EMULATION_NAME}_after_open PARAMS ((void));
-static void gld${EMULATION_NAME}_check_needed
- PARAMS ((lang_input_statement_type *));
-static void gld${EMULATION_NAME}_stat_needed
- PARAMS ((lang_input_statement_type *));
-static boolean gld${EMULATION_NAME}_search_needed
- PARAMS ((const char *, const char *, int));
-static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *, int));
-static void gld${EMULATION_NAME}_vercheck
- PARAMS ((lang_input_statement_type *));
-static void gld${EMULATION_NAME}_find_statement_assignment
- PARAMS ((lang_statement_union_type *));
-static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
-static boolean gld${EMULATION_NAME}_place_orphan
- PARAMS ((lang_input_statement_type *, asection *));
-static void gld${EMULATION_NAME}_place_section
- PARAMS ((lang_statement_union_type *));
-static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
-static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
-static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
-static int gld${EMULATION_NAME}_parse_args PARAMS((int, char **));
-static void gld${EMULATION_NAME}_list_options PARAMS ((FILE *));
-static void gld${EMULATION_NAME}_finish PARAMS ((void));
-
-\f
-static int no_pipeline_knowledge = 0;
-static char * thumb_entry_symbol = NULL;
-
-#define OPTION_THUMB_ENTRY 301
+# Copyright (C) 1991-2016 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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.
+#
+
+# This file is sourced from elf32.em, and defines extra arm-elf
+# specific routines.
+#
+test -z "$TARGET2_TYPE" && TARGET2_TYPE="rel"
+fragment <<EOF
+
+#include "ldctor.h"
+#include "elf/arm.h"
-static struct option longopts[] =
-{
- { "no-pipeline-knowledge", no_argument, NULL, 'p'},
- { "thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY},
- { NULL, no_argument, NULL, 0 }
-};
+static char * thumb_entry_symbol = NULL;
+static int byteswap_code = 0;
+static int target1_is_rel = 0${TARGET1_IS_REL};
+static char * target2_type = "${TARGET2_TYPE}";
+static int fix_v4bx = 0;
+static int use_blx = 0;
+static bfd_arm_vfp11_fix vfp11_denorm_fix = BFD_ARM_VFP11_FIX_DEFAULT;
+static bfd_arm_stm32l4xx_fix stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_NONE;
+static int fix_cortex_a8 = -1;
+static int no_enum_size_warning = 0;
+static int no_wchar_size_warning = 0;
+static int pic_veneer = 0;
+static int merge_exidx_entries = -1;
+static int fix_arm1176 = 1;
static void
-gld${EMULATION_NAME}_list_options (file)
- FILE * file;
-{
- fprintf (file, _(" -p --no-pipeline-knowledge Stop the linker knowing about the pipeline length\n"));
- fprintf (file, _(" --thumb-entry=<sym> Set the entry point to be Thumb symbol <sym>\n"));
-}
-
-static int
-gld${EMULATION_NAME}_parse_args (argc, argv)
- int argc;
- char ** argv;
+gld${EMULATION_NAME}_before_parse (void)
{
- int longind;
- int optc;
- int prevoptind = optind;
- int prevopterr = opterr;
- int wanterror;
- static int lastoptind = -1;
-
- if (lastoptind != optind)
- opterr = 0;
-
- wanterror = opterr;
- lastoptind = optind;
-
- optc = getopt_long_only (argc, argv, "-p", longopts, & longind);
- opterr = prevopterr;
-
- switch (optc)
- {
- default:
- if (wanterror)
- xexit (1);
- optind = prevoptind;
- return 0;
-
- case 'p':
- no_pipeline_knowledge = 1;
- break;
-
- case OPTION_THUMB_ENTRY:
- thumb_entry_symbol = optarg;
- break;
- }
-
- return 1;
+#ifndef TARGET_ /* I.e., if not generic. */
+ ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown);
+#endif /* not TARGET_ */
+ input_flags.dynamic = ${DYNAMIC_LINK-TRUE};
+ config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`;
+ config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo TRUE ; else echo FALSE ; fi`;
}
-\f
static void
-gld${EMULATION_NAME}_before_parse ()
+gld${EMULATION_NAME}_set_symbols (void)
{
-#ifndef TARGET_ /* I.e., if not generic. */
- ldfile_set_output_arch ("`echo ${ARCH}`");
-#endif /* not TARGET_ */
- config.dynamic_link = ${DYNAMIC_LINK-true};
- config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+ /* PR 19106: The section resizing code in gldarmelf_after_allocation
+ is effectively the same as relaxation, so prevent early memory
+ region checks which produce bogus error messages.
+ Note - this test has nothing to do with symbols. It is just here
+ because this is the first emulation routine that is called after
+ the command line has been parsed. */
+ if (!bfd_link_relocatable (&link_info))
+ TARGET_ENABLE_RELAXATION;
}
-/* Try to open a dynamic archive. This is where we know that ELF
- dynamic libraries have an extension of .so. */
-
-static boolean
-gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
- const char *arch;
- search_dirs_type *search;
- lang_input_statement_type *entry;
+static void
+arm_elf_before_allocation (void)
{
- const char *filename;
- char *string;
+ bfd_elf32_arm_set_byteswap_code (&link_info, byteswap_code);
- if (! entry->is_archive)
- return false;
+ /* Choose type of VFP11 erratum fix, or warn if specified fix is unnecessary
+ due to architecture version. */
+ bfd_elf32_arm_set_vfp11_fix (link_info.output_bfd, &link_info);
- filename = entry->filename;
+ /* Choose type of STM32L4XX erratum fix, or warn if specified fix is
+ unnecessary due to architecture version. */
+ bfd_elf32_arm_set_stm32l4xx_fix (link_info.output_bfd, &link_info);
- string = (char *) xmalloc (strlen (search->name)
- + strlen (filename)
- + strlen (arch)
- + sizeof "/lib.so");
+ /* Auto-select Cortex-A8 erratum fix if it wasn't explicitly specified. */
+ bfd_elf32_arm_set_cortex_a8_fix (link_info.output_bfd, &link_info);
- sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
+ /* Ensure the output sections of veneers needing a dedicated one is not
+ removed. */
+ bfd_elf32_arm_keep_private_stub_output_sections (&link_info);
- if (! ldfile_try_open_bfd (string, entry))
+ /* We should be able to set the size of the interworking stub section. We
+ can't do it until later if we have dynamic sections, though. */
+ if (elf_hash_table (&link_info)->dynobj == NULL)
{
- free (string);
- return false;
- }
+ /* Here we rummage through the found bfds to collect glue information. */
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ /* Initialise mapping tables for code/data. */
+ bfd_elf32_arm_init_maps (is->the_bfd);
+
+ if (!bfd_elf32_arm_process_before_allocation (is->the_bfd,
+ &link_info)
+ || !bfd_elf32_arm_vfp11_erratum_scan (is->the_bfd, &link_info)
+ || !bfd_elf32_arm_stm32l4xx_erratum_scan (is->the_bfd,
+ &link_info))
+ /* xgettext:c-format */
+ einfo (_("Errors encountered processing file %s"), is->filename);
+ }
- entry->filename = string;
-
- /* We have found a dynamic object to include in the link. The ELF
- backend linker will create a DT_NEEDED entry in the .dynamic
- section naming this file. If this file includes a DT_SONAME
- entry, it will be used. Otherwise, the ELF linker will just use
- the name of the file. For an archive found by searching, like
- this one, the DT_NEEDED entry should consist of just the name of
- the file, without the path information used to find it. Note
- that we only need to do this if we have a dynamic object; an
- archive will never be referenced by a DT_NEEDED entry.
-
- FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
- very pretty. I haven't been able to think of anything that is
- pretty, though. */
- if (bfd_check_format (entry->the_bfd, bfd_object)
- && (entry->the_bfd->flags & DYNAMIC) != 0)
- {
- char *needed_name;
-
- ASSERT (entry->is_archive && entry->search_dirs_flag);
- needed_name = (char *) xmalloc (strlen (filename)
- + strlen (arch)
- + sizeof "lib.so");
- sprintf (needed_name, "lib%s%s.so", filename, arch);
- bfd_elf_set_dt_needed_name (entry->the_bfd, needed_name);
+ /* We have seen it all. Allocate it, and carry on. */
+ bfd_elf32_arm_allocate_interworking_sections (& link_info);
}
- return true;
+ /* Call the standard elf routine. */
+ gld${EMULATION_NAME}_before_allocation ();
}
-EOF
-if [ "x${host}" = "x${target}" ] ; then
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
-
-/* For a native linker, check the file /etc/ld.so.conf for directories
- in which we may find shared libraries. /etc/ld.so.conf is really
- only meaningful on Linux, but we check it on other systems anyhow. */
-
-static boolean gld${EMULATION_NAME}_check_ld_so_conf
- PARAMS ((const char *, int));
-
-static boolean
-gld${EMULATION_NAME}_check_ld_so_conf (name, force)
- const char *name;
- int force;
+/* Fake input file for stubs. */
+static lang_input_statement_type *stub_file;
+
+/* Whether we need to call gldarm_layout_sections_again. */
+static int need_laying_out = 0;
+
+/* Maximum size of a group of input sections that can be handled by
+ one stub section. A value of +/-1 indicates the bfd back-end
+ should use a suitable default size. */
+static bfd_signed_vma group_size = 1;
+
+struct hook_stub_info
{
- static boolean initialized;
- static char *ld_so_conf;
+ lang_statement_list_type add;
+ asection *input_section;
+};
- if (! initialized)
- {
- FILE *f;
+/* Traverse the linker tree to find the spot where the stub goes. */
+
+static bfd_boolean
+hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
+{
+ lang_statement_union_type *l;
+ bfd_boolean ret;
- f = fopen ("/etc/ld.so.conf", FOPEN_RT);
- if (f != NULL)
+ for (; (l = *lp) != NULL; lp = &l->header.next)
+ {
+ switch (l->header.type)
{
- char *b;
- size_t len, alloc;
- int c;
+ case lang_constructors_statement_enum:
+ ret = hook_in_stub (info, &constructor_list.head);
+ if (ret)
+ return ret;
+ break;
- len = 0;
- alloc = 100;
- b = (char *) xmalloc (alloc);
+ case lang_output_section_statement_enum:
+ ret = hook_in_stub (info,
+ &l->output_section_statement.children.head);
+ if (ret)
+ return ret;
+ break;
- while ((c = getc (f)) != EOF)
- {
- if (len + 1 >= alloc)
- {
- alloc *= 2;
- b = (char *) xrealloc (b, alloc);
- }
- if (c != ':'
- && c != ' '
- && c != '\t'
- && c != '\n'
- && c != ',')
- {
- b[len] = c;
- ++len;
- }
- else
- {
- if (len > 0 && b[len - 1] != ':')
- {
- b[len] = ':';
- ++len;
- }
- }
- }
+ case lang_wild_statement_enum:
+ ret = hook_in_stub (info, &l->wild_statement.children.head);
+ if (ret)
+ return ret;
+ break;
- if (len > 0 && b[len - 1] == ':')
- --len;
+ case lang_group_statement_enum:
+ ret = hook_in_stub (info, &l->group_statement.children.head);
+ if (ret)
+ return ret;
+ break;
- if (len > 0)
- b[len] = '\0';
- else
+ case lang_input_section_enum:
+ if (l->input_section.section == info->input_section)
{
- free (b);
- b = NULL;
+ /* We've found our section. Insert the stub immediately
+ after its associated input section. */
+ *(info->add.tail) = l->header.next;
+ l->header.next = info->add.head;
+ return TRUE;
}
+ break;
- fclose (f);
+ case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ case lang_input_statement_enum:
+ case lang_assignment_statement_enum:
+ case lang_padding_statement_enum:
+ case lang_address_statement_enum:
+ case lang_fill_statement_enum:
+ break;
- ld_so_conf = b;
+ default:
+ FAIL ();
+ break;
}
-
- initialized = true;
}
-
- if (ld_so_conf == NULL)
- return false;
-
- return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force);
+ return FALSE;
}
-EOF
- ;;
- esac
-fi
-cat >>e${EMULATION_NAME}.c <<EOF
-/* These variables are required to pass information back and forth
- between after_open and check_needed and stat_needed and vercheck. */
+/* Call-back for elf32_arm_size_stubs. */
-static struct bfd_link_needed_list *global_needed;
-static struct stat global_stat;
-static boolean global_found;
-static struct bfd_link_needed_list *global_vercheck_needed;
-static boolean global_vercheck_failed;
+/* Create a new stub section, and arrange for it to be linked
+ immediately after INPUT_SECTION. */
-static void
-gld${EMULATION_NAME}_after_open ()
+static asection *
+elf32_arm_add_stub_section (const char * stub_sec_name,
+ asection * output_section,
+ asection * after_input_section,
+ unsigned int alignment_power)
{
- struct bfd_link_needed_list *needed, *l;
+ asection *stub_sec;
+ flagword flags;
+ lang_output_section_statement_type *os;
+ struct hook_stub_info info;
- if (strstr (bfd_get_target (output_bfd), "arm") == NULL)
- {
- /* The arm backend needs special fields in the output hash structure.
- These will only be created if the output format is an arm format,
- hence we do not support linking and changing output formats at the
- same time. Use a link followed by objcopy to change output formats. */
- einfo ("%F%X%P: error: cannot change output format whilst linking ARM binaries\n");
- return;
- }
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+ | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
+ stub_sec = bfd_make_section_anyway_with_flags (stub_file->the_bfd,
+ stub_sec_name, flags);
+ if (stub_sec == NULL)
+ goto err_ret;
- {
- LANG_FOR_EACH_INPUT_STATEMENT (is)
- {
- /* The interworking bfd must be the last one to be processed */
- if (!is->next)
- bfd_elf32_arm_get_bfd_for_interworking (is->the_bfd, & link_info);
- }
- }
+ bfd_set_section_alignment (stub_file->the_bfd, stub_sec, alignment_power);
- /* We only need to worry about this when doing a final link. */
- if (link_info.relocateable || link_info.shared)
- return;
-
- /* Get the list of files which appear in DT_NEEDED entries in
- dynamic objects included in the link (often there will be none).
- For each such file, we want to track down the corresponding
- library, and include the symbol table in the link. This is what
- the runtime dynamic linker will do. Tracking the files down here
- permits one dynamic object to include another without requiring
- special action by the person doing the link. Note that the
- needed list can actually grow while we are stepping through this
- loop. */
- needed = bfd_elf_get_needed_list (output_bfd, &link_info);
- for (l = needed; l != NULL; l = l->next)
- {
- struct bfd_link_needed_list *ll;
- int force;
+ os = lang_output_section_get (output_section);
- /* If we've already seen this file, skip it. */
- for (ll = needed; ll != l; ll = ll->next)
- if (strcmp (ll->name, l->name) == 0)
- break;
- if (ll != l)
- continue;
+ info.input_section = after_input_section;
+ lang_list_init (&info.add);
+ lang_add_section (&info.add, stub_sec, NULL, os);
- /* See if this file was included in the link explicitly. */
- global_needed = l;
- global_found = false;
- lang_for_each_input_file (gld${EMULATION_NAME}_check_needed);
- if (global_found)
- continue;
+ if (info.add.head == NULL)
+ goto err_ret;
- /* We need to find this file and include the symbol table. We
- want to search for the file in the same way that the dynamic
- linker will search. That means that we want to use
- rpath_link, rpath, then the environment variable
- LD_LIBRARY_PATH (native only), then the linker script
- LIB_SEARCH_DIRS. We do not search using the -L arguments.
-
- We search twice. The first time, we skip objects which may
- introduce version mismatches. The second time, we force
- their use. See gld${EMULATION_NAME}_vercheck comment. */
- for (force = 0; force < 2; force++)
- {
- const char *lib_path;
- size_t len;
- search_dirs_type *search;
-
- if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
- l->name, force))
- break;
- if (gld${EMULATION_NAME}_search_needed (command_line.rpath,
- l->name, force))
- break;
- if (command_line.rpath_link == NULL
- && command_line.rpath == NULL)
- {
- lib_path = (const char *) getenv ("LD_RUN_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->name,
- force))
- break;
- }
-EOF
-if [ "x${host}" = "x${target}" ] ; then
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
- lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
- if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
- break;
-EOF
- ;;
- esac
-fi
-cat >>e${EMULATION_NAME}.c <<EOF
- len = strlen (l->name);
- for (search = search_head; search != NULL; search = search->next)
- {
- char *filename;
-
- if (search->cmdline)
- continue;
- filename = (char *) xmalloc (strlen (search->name) + len + 2);
- sprintf (filename, "%s/%s", search->name, l->name);
- if (gld${EMULATION_NAME}_try_needed (filename, force))
- break;
- free (filename);
- }
- if (search != NULL)
- break;
-EOF
-if [ "x${host}" = "x${target}" ] ; then
- case " ${EMULATION_LIBPATH} " in
- *" ${EMULATION_NAME} "*)
-cat >>e${EMULATION_NAME}.c <<EOF
- if (gld${EMULATION_NAME}_check_ld_so_conf (l->name, force))
- break;
-EOF
- ;;
- esac
-fi
-cat >>e${EMULATION_NAME}.c <<EOF
- }
+ if (after_input_section == NULL)
+ {
+ lang_statement_union_type **lp = &os->children.head;
+ lang_statement_union_type *l, *lprev = NULL;
- if (force < 2)
- continue;
+ for (; (l = *lp) != NULL; lp = &l->header.next, lprev = l);
+
+ if (lprev)
+ lprev->header.next = info.add.head;
+ else
+ os->children.head = info.add.head;
- einfo ("%P: warning: %s, needed by %B, not found (try using --rpath)\n",
- l->name, l->by);
+ return stub_sec;
+ }
+ else
+ {
+ if (hook_in_stub (&info, &os->children.head))
+ return stub_sec;
}
+
+ err_ret:
+ einfo ("%X%P: can not make stub section: %E\n");
+ return NULL;
}
-/* Search for a needed file in a path. */
+/* Another call-back for elf_arm_size_stubs. */
-static boolean
-gld${EMULATION_NAME}_search_needed (path, name, force)
- const char *path;
- const char *name;
- int force;
+static void
+gldarm_layout_sections_again (void)
{
- const char *s;
- size_t len;
+ /* If we have changed sizes of the stub sections, then we need
+ to recalculate all the section offsets. This may mean we need to
+ add even more stubs. */
+ gld${EMULATION_NAME}_map_segments (TRUE);
+ need_laying_out = -1;
+}
- if (path == NULL || *path == '\0')
- return false;
- len = strlen (name);
- while (1)
+static void
+build_section_lists (lang_statement_union_type *statement)
+{
+ if (statement->header.type == lang_input_section_enum)
{
- char *filename, *sset;
+ asection *i = statement->input_section.section;
- s = strchr (path, ':');
- if (s == NULL)
- s = path + strlen (path);
+ if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
+ && (i->flags & SEC_EXCLUDE) == 0
+ && i->output_section != NULL
+ && i->output_section->owner == link_info.output_bfd)
+ elf32_arm_next_input_section (& link_info, i);
+ }
+}
- filename = (char *) xmalloc (s - path + len + 2);
- if (s == path)
- sset = filename;
- else
- {
- memcpy (filename, path, s - path);
- filename[s - path] = '/';
- sset = filename + (s - path) + 1;
- }
- strcpy (sset, name);
+static int
+compare_output_sec_vma (const void *a, const void *b)
+{
+ asection *asec = *(asection **) a, *bsec = *(asection **) b;
+ asection *aout = asec->output_section, *bout = bsec->output_section;
+ bfd_vma avma, bvma;
- if (gld${EMULATION_NAME}_try_needed (filename, force))
- return true;
+ /* If there's no output section for some reason, compare equal. */
+ if (!aout || !bout)
+ return 0;
- free (filename);
+ avma = aout->vma + asec->output_offset;
+ bvma = bout->vma + bsec->output_offset;
- if (*s == '\0')
- break;
- path = s + 1;
- }
+ if (avma > bvma)
+ return 1;
+ else if (avma < bvma)
+ return -1;
- return false;
+ return 0;
}
-/* This function is called for each possible name for a dynamic object
- named by a DT_NEEDED entry. The FORCE parameter indicates whether
- to skip the check for a conflicting version. */
-
-static boolean
-gld${EMULATION_NAME}_try_needed (name, force)
- const char *name;
- int force;
+static void
+gld${EMULATION_NAME}_after_allocation (void)
{
- bfd *abfd;
+ int ret;
- abfd = bfd_openr (name, bfd_get_target (output_bfd));
- if (abfd == NULL)
- return false;
- if (! bfd_check_format (abfd, bfd_object))
- {
- (void) bfd_close (abfd);
- return false;
- }
- if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
- {
- (void) bfd_close (abfd);
- return false;
- }
+ /* Build a sorted list of input text sections, then use that to process
+ the unwind table index. */
+ unsigned int list_size = 10;
+ asection **sec_list = (asection **)
+ xmalloc (list_size * sizeof (asection *));
+ unsigned int sec_count = 0;
- /* Check whether this object would include any conflicting library
- versions. If FORCE is set, then we skip this check; we use this
- the second time around, if we couldn't find any compatible
- instance of the shared library. */
-
- if (! force)
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
{
- struct bfd_link_needed_list *needed;
+ bfd *abfd = is->the_bfd;
+ asection *sec;
- if (! bfd_elf_get_bfd_needed_list (abfd, &needed))
- einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ continue;
- if (needed != NULL)
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
{
- global_vercheck_needed = needed;
- global_vercheck_failed = false;
- lang_for_each_input_file (gld${EMULATION_NAME}_vercheck);
- if (global_vercheck_failed)
+ asection *out_sec = sec->output_section;
+
+ if (out_sec
+ && elf_section_data (sec)
+ && elf_section_type (sec) == SHT_PROGBITS
+ && (elf_section_flags (sec) & SHF_EXECINSTR) != 0
+ && (sec->flags & SEC_EXCLUDE) == 0
+ && sec->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
+ && out_sec != bfd_abs_section_ptr)
{
- (void) bfd_close (abfd);
- /* Return false to force the caller to move on to try
- another file on the search path. */
- return false;
- }
-
- /* But wait! It gets much worse. On Linux, if a shared
- library does not use libc at all, we are supposed to skip
- it the first time around in case we encounter a shared
- library later on with the same name which does use the
- version of libc that we want. This is much too horrible
- to use on any system other than Linux. */
-
-EOF
-case ${target} in
- *-*-linux-gnu*)
- cat >>e${EMULATION_NAME}.c <<EOF
- {
- struct bfd_link_needed_list *l;
-
- for (l = needed; l != NULL; l = l->next)
- if (strncmp (l->name, "libc.so", 7) == 0)
- break;
- if (l == NULL)
- {
- (void) bfd_close (abfd);
- return false;
- }
- }
+ if (sec_count == list_size)
+ {
+ list_size *= 2;
+ sec_list = (asection **)
+ xrealloc (sec_list, list_size * sizeof (asection *));
+ }
-EOF
- ;;
-esac
-cat >>e${EMULATION_NAME}.c <<EOF
+ sec_list[sec_count++] = sec;
+ }
}
}
- /* We've found a dynamic object matching the DT_NEEDED entry. */
-
- /* We have already checked that there is no other input file of the
- same name. We must now check again that we are not including the
- same file twice. We need to do this because on many systems
- libc.so is a symlink to, e.g., libc.so.1. The SONAME entry will
- reference libc.so.1. If we have already included libc.so, we
- don't want to include libc.so.1 if they are the same file, and we
- can only check that using stat. */
-
- if (bfd_stat (abfd, &global_stat) != 0)
- einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
- global_found = false;
- lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
- if (global_found)
- {
- /* Return true to indicate that we found the file, even though
- we aren't going to do anything with it. */
- return true;
- }
-
- /* Tell the ELF backend that don't want the output file to have a
- DT_NEEDED entry for this file. */
- bfd_elf_set_dt_needed_name (abfd, "");
-
- /* Add this file into the symbol table. */
- if (! bfd_link_add_symbols (abfd, &link_info))
- einfo ("%F%B: could not read symbols: %E\n", abfd);
+ qsort (sec_list, sec_count, sizeof (asection *), &compare_output_sec_vma);
- return true;
-}
+ if (elf32_arm_fix_exidx_coverage (sec_list, sec_count, &link_info,
+ merge_exidx_entries))
+ need_laying_out = 1;
-/* See if an input file matches a DT_NEEDED entry by name. */
+ free (sec_list);
-static void
-gld${EMULATION_NAME}_check_needed (s)
- lang_input_statement_type *s;
-{
- if (global_found)
- return;
-
- if (s->filename != NULL
- && strcmp (s->filename, global_needed->name) == 0)
+ /* bfd_elf32_discard_info just plays with debugging sections,
+ ie. doesn't affect any code, so we can delay resizing the
+ sections. It's likely we'll resize everything in the process of
+ adding stubs. */
+ ret = bfd_elf_discard_info (link_info.output_bfd, & link_info);
+ if (ret < 0)
{
- global_found = true;
+ einfo ("%X%P: .eh_frame/.stab edit: %E\n");
return;
}
+ else if (ret > 0)
+ need_laying_out = 1;
- if (s->the_bfd != NULL)
+ /* If generating a relocatable output file, then we don't
+ have to examine the relocs. */
+ if (stub_file != NULL && !bfd_link_relocatable (&link_info))
{
- const char *soname;
-
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname != NULL
- && strcmp (soname, global_needed->name) == 0)
+ ret = elf32_arm_setup_section_lists (link_info.output_bfd, &link_info);
+ if (ret != 0)
{
- global_found = true;
- return;
- }
- }
-
- if (s->search_dirs_flag
- && s->filename != NULL
- && strchr (global_needed->name, '/') == NULL)
- {
- const char *f;
+ if (ret < 0)
+ {
+ einfo ("%X%P: could not compute sections lists for stub generation: %E\n");
+ return;
+ }
- f = strrchr (s->filename, '/');
- if (f != NULL
- && strcmp (f + 1, global_needed->name) == 0)
- {
- global_found = true;
- return;
+ lang_for_each_statement (build_section_lists);
+
+ /* Call into the BFD backend to do the real work. */
+ if (! elf32_arm_size_stubs (link_info.output_bfd,
+ stub_file->the_bfd,
+ & link_info,
+ group_size,
+ & elf32_arm_add_stub_section,
+ & gldarm_layout_sections_again))
+ {
+ einfo ("%X%P: cannot size stub section: %E\n");
+ return;
+ }
}
}
-}
-/* See if an input file matches a DT_NEEDED entry by running stat on
- the file. */
+ if (need_laying_out != -1)
+ gld${EMULATION_NAME}_map_segments (need_laying_out);
+}
static void
-gld${EMULATION_NAME}_stat_needed (s)
- lang_input_statement_type *s;
+gld${EMULATION_NAME}_finish (void)
{
- struct stat st;
- const char *suffix;
- const char *soname;
- const char *f;
+ struct bfd_link_hash_entry * h;
- if (global_found)
- return;
- if (s->the_bfd == NULL)
- return;
+ {
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ /* Figure out where VFP11 erratum veneers (and the labels returning
+ from same) have been placed. */
+ bfd_elf32_arm_vfp11_fix_veneer_locations (is->the_bfd, &link_info);
- if (bfd_stat (s->the_bfd, &st) != 0)
+ /* Figure out where STM32L4XX erratum veneers (and the labels returning
+ from them) have been placed. */
+ bfd_elf32_arm_stm32l4xx_fix_veneer_locations (is->the_bfd, &link_info);
+ }
+ }
+
+ if (!bfd_link_relocatable (&link_info))
{
- einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
- return;
+ /* Now build the linker stubs. */
+ if (stub_file->the_bfd->sections != NULL)
+ {
+ if (! elf32_arm_build_stubs (& link_info))
+ einfo ("%X%P: can not build stubs: %E\n");
+ }
}
- if (st.st_dev == global_stat.st_dev
- && st.st_ino == global_stat.st_ino)
+ finish_default ();
+
+ if (thumb_entry_symbol)
{
- global_found = true;
- return;
+ h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol,
+ FALSE, FALSE, TRUE);
}
-
- /* We issue a warning if it looks like we are including two
- different versions of the same shared library. For example,
- there may be a problem if -lc picks up libc.so.6 but some other
- shared library has a DT_NEEDED entry of libc.so.5. This is a
- hueristic test, and it will only work if the name looks like
- NAME.so.VERSION. FIXME: Depending on file names is error-prone.
- If we really want to issue warnings about mixing version numbers
- of shared libraries, we need to find a better way. */
-
- if (strchr (global_needed->name, '/') != NULL)
- return;
- suffix = strstr (global_needed->name, ".so.");
- if (suffix == NULL)
- return;
- suffix += sizeof ".so." - 1;
-
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname == NULL)
- soname = s->filename;
-
- f = strrchr (soname, '/');
- if (f != NULL)
- ++f;
else
- f = soname;
-
- if (strncmp (f, global_needed->name, suffix - global_needed->name) == 0)
- einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
- global_needed->name, global_needed->by, f);
-}
-
-/* On Linux, it's possible to have different versions of the same
- shared library linked against different versions of libc. The
- dynamic linker somehow tags which libc version to use in
- /etc/ld.so.cache, and, based on the libc that it sees in the
- executable, chooses which version of the shared library to use.
+ {
+ struct elf_link_hash_entry * eh;
- We try to do a similar check here by checking whether this shared
- library needs any other shared libraries which may conflict with
- libraries we have already included in the link. If it does, we
- skip it, and try to find another shared library farther on down the
- link path.
+ if (!entry_symbol.name)
+ return;
- This is called via lang_for_each_input_file.
- GLOBAL_VERCHECK_NEEDED is the list of objects needed by the object
- which we ar checking. This sets GLOBAL_VERCHECK_FAILED if we find
- a conflicting version. */
+ h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
+ FALSE, FALSE, TRUE);
+ eh = (struct elf_link_hash_entry *)h;
+ if (!h || ARM_GET_SYM_BRANCH_TYPE (eh->target_internal)
+ != ST_BRANCH_TO_THUMB)
+ return;
+ }
-static void
-gld${EMULATION_NAME}_vercheck (s)
- lang_input_statement_type *s;
-{
- const char *soname, *f;
- struct bfd_link_needed_list *l;
-
- if (global_vercheck_failed)
- return;
- if (s->the_bfd == NULL
- || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
- return;
-
- soname = bfd_elf_get_dt_soname (s->the_bfd);
- if (soname == NULL)
- soname = bfd_get_filename (s->the_bfd);
-
- f = strrchr (soname, '/');
- if (f != NULL)
- ++f;
- else
- f = soname;
- for (l = global_vercheck_needed; l != NULL; l = l->next)
+ if (h != (struct bfd_link_hash_entry *) NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak)
+ && h->u.def.section->output_section != NULL)
{
- const char *suffix;
+ static char buffer[32];
+ bfd_vma val;
- if (strcmp (f, l->name) == 0)
- {
- /* Probably can't happen, but it's an easy check. */
- continue;
- }
+ /* Special procesing is required for a Thumb entry symbol. The
+ bottom bit of its address must be set. */
+ val = (h->u.def.value
+ + bfd_get_section_vma (link_info.output_bfd,
+ h->u.def.section->output_section)
+ + h->u.def.section->output_offset);
- if (strchr (l->name, '/') != NULL)
- continue;
+ val |= 1;
- suffix = strstr (l->name, ".so.");
- if (suffix == NULL)
- continue;
+ /* Now convert this value into a string and store it in entry_symbol
+ where the lang_finish() function will pick it up. */
+ buffer[0] = '0';
+ buffer[1] = 'x';
- suffix += sizeof ".so." - 1;
+ sprintf_vma (buffer + 2, val);
- if (strncmp (f, l->name, suffix - l->name) == 0)
- {
- /* Here we know that S is a dynamic object FOO.SO.VER1, and
- the object we are considering needs a dynamic object
- FOO.SO.VER2, and VER1 and VER2 are different. This
- appears to be a version mismatch, so we tell the caller
- to try a different version of this library. */
- global_vercheck_failed = true;
- return;
- }
+ if (thumb_entry_symbol != NULL && entry_symbol.name != NULL
+ && entry_from_cmdline)
+ einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"),
+ thumb_entry_symbol, entry_symbol.name);
+ entry_symbol.name = buffer;
}
+ else
+ einfo (_("%P: warning: cannot find thumb start symbol %s\n"),
+ thumb_entry_symbol);
}
-/* Place an orphan section. We use this to put random SHF_ALLOC
- sections in the right segment. */
-
-static asection *hold_section;
-static lang_output_section_statement_type *hold_use;
-static lang_output_section_statement_type *hold_text;
-static lang_output_section_statement_type *hold_rodata;
-static lang_output_section_statement_type *hold_data;
-static lang_output_section_statement_type *hold_bss;
-static lang_output_section_statement_type *hold_rel;
-static lang_output_section_statement_type *hold_interp;
-
-/*ARGSUSED*/
-static boolean
-gld${EMULATION_NAME}_place_orphan (file, s)
- lang_input_statement_type *file;
- asection *s;
+/* This is a convenient point to tell BFD about target specific flags.
+ After the output has been created, but before inputs are read. */
+static void
+arm_elf_create_output_section_statements (void)
{
- lang_output_section_statement_type *place;
- asection *snew, **pps;
- lang_statement_list_type *old;
- lang_statement_list_type add;
- etree_type *address;
- const char *secname, *ps;
- const char *outsecname;
- lang_output_section_statement_type *os;
-
- if ((s->flags & SEC_ALLOC) == 0)
- return false;
-
- /* Look through the script to see where to place this section. */
- hold_section = s;
- hold_use = NULL;
- lang_for_each_statement (gld${EMULATION_NAME}_place_section);
-
- if (hold_use != NULL)
- {
- /* We have already placed a section with this name. */
- wild_doit (&hold_use->children, s, hold_use, file);
- return true;
- }
-
- secname = bfd_get_section_name (s->owner, s);
-
- /* If this is a final link, then always put .gnu.warning.SYMBOL
- sections into the .text section to get them out of the way. */
- if (! link_info.shared
- && ! link_info.relocateable
- && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0
- && hold_text != NULL)
- {
- wild_doit (&hold_text->children, s, hold_text, file);
- return true;
- }
-
- /* Decide which segment the section should go in based on the
- section name and section flags. We put loadable .note sections
- right after the .interp section, so that the PT_NOTE segment is
- stored right after the program headers where the OS can read it
- in the first page. */
- place = NULL;
- if (s->flags & SEC_EXCLUDE)
- return false;
- else if ((s->flags & SEC_LOAD) != 0
- && strncmp (secname, ".note", 4) == 0
- && hold_interp != NULL)
- place = hold_interp;
- else if ((s->flags & SEC_HAS_CONTENTS) == 0
- && hold_bss != NULL)
- place = hold_bss;
- else if ((s->flags & SEC_READONLY) == 0
- && hold_data != NULL)
- place = hold_data;
- else if (strncmp (secname, ".rel", 4) == 0
- && hold_rel != NULL)
- place = hold_rel;
- else if ((s->flags & SEC_CODE) == 0
- && (s->flags & SEC_READONLY) != 0
- && hold_rodata != NULL)
- place = hold_rodata;
- else if ((s->flags & SEC_READONLY) != 0
- && hold_text != NULL)
- place = hold_text;
- if (place == NULL)
- return false;
-
- /* Choose a unique name for the section. This will be needed if the
- same section name appears in the input file with different
- loadable or allocateable characteristics. */
- outsecname = secname;
- if (bfd_get_section_by_name (output_bfd, outsecname) != NULL)
+ if (strstr (bfd_get_target (link_info.output_bfd), "arm") == NULL)
{
- unsigned int len;
- char *newname;
- unsigned int i;
-
- len = strlen (outsecname);
- newname = xmalloc (len + 5);
- strcpy (newname, outsecname);
- i = 0;
- do
- {
- sprintf (newname + len, "%d", i);
- ++i;
- }
- while (bfd_get_section_by_name (output_bfd, newname) != NULL);
-
- outsecname = newname;
+ /* The arm backend needs special fields in the output hash structure.
+ These will only be created if the output format is an arm format,
+ hence we do not support linking and changing output formats at the
+ same time. Use a link followed by objcopy to change output formats. */
+ einfo ("%F%X%P: error: Cannot change output format whilst linking ARM binaries.\n");
+ return;
}
- /* Create the section in the output file, and put it in the right
- place. This shuffling is to make the output file look neater. */
- snew = bfd_make_section (output_bfd, outsecname);
- if (snew == NULL)
- einfo ("%P%F: output format %s cannot represent section called %s\n",
- output_bfd->xvec->name, outsecname);
- if (place->bfd_section != NULL)
+ bfd_elf32_arm_set_target_relocs (link_info.output_bfd, &link_info,
+ target1_is_rel,
+ target2_type, fix_v4bx, use_blx,
+ vfp11_denorm_fix, stm32l4xx_fix,
+ no_enum_size_warning,
+ no_wchar_size_warning,
+ pic_veneer, fix_cortex_a8,
+ fix_arm1176);
+
+ stub_file = lang_add_input_file ("linker stubs",
+ lang_input_file_is_fake_enum,
+ NULL);
+ stub_file->the_bfd = bfd_create ("linker stubs", link_info.output_bfd);
+ if (stub_file->the_bfd == NULL
+ || ! bfd_set_arch_mach (stub_file->the_bfd,
+ bfd_get_arch (link_info.output_bfd),
+ bfd_get_mach (link_info.output_bfd)))
{
- for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next)
- ;
- *pps = snew->next;
- snew->next = place->bfd_section->next;
- place->bfd_section->next = snew;
+ einfo ("%X%P: can not create BFD %E\n");
+ return;
}
- /* Start building a list of statements for this section. */
- old = stat_ptr;
- stat_ptr = &add;
- lang_list_init (stat_ptr);
+ stub_file->the_bfd->flags |= BFD_LINKER_CREATED;
+ ldlang_add_file (stub_file);
- /* If the name of the section is representable in C, then create
- symbols to mark the start and the end of the section. */
- for (ps = outsecname; *ps != '\0'; ps++)
- if (! isalnum ((unsigned char) *ps) && *ps != '_')
- break;
- if (*ps == '\0' && config.build_constructors)
- {
- char *symname;
-
- symname = (char *) xmalloc (ps - outsecname + sizeof "__start_");
- sprintf (symname, "__start_%s", outsecname);
- lang_add_assignment (exp_assop ('=', symname,
- exp_unop (ALIGN_K,
- exp_intop ((bfd_vma) 1
- << s->alignment_power))));
- }
-
- if (! link_info.relocateable)
- address = NULL;
- else
- address = exp_intop ((bfd_vma) 0);
-
- lang_enter_output_section_statement (outsecname, address, 0,
- (bfd_vma) 0,
- (etree_type *) NULL,
- (etree_type *) NULL,
- (etree_type *) NULL);
-
- os = lang_output_section_statement_lookup (outsecname);
- wild_doit (&os->children, s, os, file);
-
- lang_leave_output_section_statement
- ((bfd_vma) 0, "*default*", (struct lang_output_section_phdr_list *) NULL,
- "*default*");
- stat_ptr = &add;
-
- if (*ps == '\0' && config.build_constructors)
- {
- char *symname;
-
- symname = (char *) xmalloc (ps - outsecname + sizeof "__stop_");
- sprintf (symname, "__stop_%s", outsecname);
- lang_add_assignment (exp_assop ('=', symname,
- exp_nameop (NAME, ".")));
- }
+ /* Also use the stub file for stubs placed in a single output section. */
+ bfd_elf32_arm_add_glue_sections_to_bfd (stub_file->the_bfd, &link_info);
+ bfd_elf32_arm_get_bfd_for_interworking (stub_file->the_bfd, &link_info);
+}
- /* Now stick the new statement list right after PLACE. */
- *add.tail = place->header.next;
- place->header.next = add.head;
+/* Avoid processing the fake stub_file in vercheck, stat_needed and
+ check_needed routines. */
- stat_ptr = old;
+static void (*real_func) (lang_input_statement_type *);
- return true;
+static void arm_for_each_input_file_wrapper (lang_input_statement_type *l)
+{
+ if (l != stub_file)
+ (*real_func) (l);
}
static void
-gld${EMULATION_NAME}_place_section (s)
- lang_statement_union_type *s;
+arm_lang_for_each_input_file (void (*func) (lang_input_statement_type *))
{
- lang_output_section_statement_type *os;
-
- if (s->header.type != lang_output_section_statement_enum)
- return;
-
- os = &s->output_section_statement;
-
- if (strcmp (os->name, hold_section->name) == 0
- && os->bfd_section != NULL
- && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC))
- == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC))))
- hold_use = os;
-
- if (strcmp (os->name, ".text") == 0)
- hold_text = os;
- else if (strcmp (os->name, ".rodata") == 0)
- hold_rodata = os;
- else if (strcmp (os->name, ".data") == 0)
- hold_data = os;
- else if (strcmp (os->name, ".bss") == 0)
- hold_bss = os;
- else if (hold_rel == NULL
- && os->bfd_section != NULL
- && (os->bfd_section->flags & SEC_ALLOC) != 0
- && strncmp (os->name, ".rel", 4) == 0)
- hold_rel = os;
- else if (strcmp (os->name, ".interp") == 0)
- hold_interp = os;
+ real_func = func;
+ lang_for_each_input_file (&arm_for_each_input_file_wrapper);
}
-/* Look through an expression for an assignment statement. */
+#define lang_for_each_input_file arm_lang_for_each_input_file
-static void
-gld${EMULATION_NAME}_find_exp_assignment (exp)
- etree_type *exp;
-{
- struct bfd_link_hash_entry *h;
+EOF
- switch (exp->type.node_class)
- {
- case etree_provide:
- h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst,
- false, false, false);
- if (h == NULL)
- break;
-
- /* We call record_link_assignment even if the symbol is defined.
- This is because if it is defined by a dynamic object, we
- actually want to use the value defined by the linker script,
- not the value from the dynamic object (because we are setting
- symbols like etext). If the symbol is defined by a regular
- object, then, as it happens, calling record_link_assignment
- will do no harm. */
-
- /* Fall through. */
- case etree_assign:
- if (strcmp (exp->assign.dst, ".") != 0)
- {
- if (! (bfd_elf${ELFSIZE}_record_link_assignment
- (output_bfd, &link_info, exp->assign.dst,
- exp->type.node_class == etree_provide ? true : false)))
- einfo ("%P%F: failed to record assignment to %s: %E\n",
- exp->assign.dst);
- }
- gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src);
+# Define some shell vars to insert bits of code into the standard elf
+# parse_args and list_options functions.
+#
+PARSE_AND_LIST_PROLOGUE='
+#define OPTION_THUMB_ENTRY 301
+#define OPTION_BE8 302
+#define OPTION_TARGET1_REL 303
+#define OPTION_TARGET1_ABS 304
+#define OPTION_TARGET2 305
+#define OPTION_FIX_V4BX 306
+#define OPTION_USE_BLX 307
+#define OPTION_VFP11_DENORM_FIX 308
+#define OPTION_NO_ENUM_SIZE_WARNING 309
+#define OPTION_PIC_VENEER 310
+#define OPTION_FIX_V4BX_INTERWORKING 311
+#define OPTION_STUBGROUP_SIZE 312
+#define OPTION_NO_WCHAR_SIZE_WARNING 313
+#define OPTION_FIX_CORTEX_A8 314
+#define OPTION_NO_FIX_CORTEX_A8 315
+#define OPTION_NO_MERGE_EXIDX_ENTRIES 316
+#define OPTION_FIX_ARM1176 317
+#define OPTION_NO_FIX_ARM1176 318
+#define OPTION_LONG_PLT 319
+#define OPTION_STM32L4XX_FIX 320
+'
+
+PARSE_AND_LIST_SHORTOPTS=p
+
+PARSE_AND_LIST_LONGOPTS='
+ { "no-pipeline-knowledge", no_argument, NULL, '\'p\''},
+ { "thumb-entry", required_argument, NULL, OPTION_THUMB_ENTRY},
+ { "be8", no_argument, NULL, OPTION_BE8},
+ { "target1-rel", no_argument, NULL, OPTION_TARGET1_REL},
+ { "target1-abs", no_argument, NULL, OPTION_TARGET1_ABS},
+ { "target2", required_argument, NULL, OPTION_TARGET2},
+ { "fix-v4bx", no_argument, NULL, OPTION_FIX_V4BX},
+ { "fix-v4bx-interworking", no_argument, NULL, OPTION_FIX_V4BX_INTERWORKING},
+ { "use-blx", no_argument, NULL, OPTION_USE_BLX},
+ { "vfp11-denorm-fix", required_argument, NULL, OPTION_VFP11_DENORM_FIX},
+ { "fix-stm32l4xx-629360", optional_argument, NULL, OPTION_STM32L4XX_FIX},
+ { "no-enum-size-warning", no_argument, NULL, OPTION_NO_ENUM_SIZE_WARNING},
+ { "pic-veneer", no_argument, NULL, OPTION_PIC_VENEER},
+ { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
+ { "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING},
+ { "fix-cortex-a8", no_argument, NULL, OPTION_FIX_CORTEX_A8 },
+ { "no-fix-cortex-a8", no_argument, NULL, OPTION_NO_FIX_CORTEX_A8 },
+ { "no-merge-exidx-entries", no_argument, NULL, OPTION_NO_MERGE_EXIDX_ENTRIES },
+ { "fix-arm1176", no_argument, NULL, OPTION_FIX_ARM1176 },
+ { "no-fix-arm1176", no_argument, NULL, OPTION_NO_FIX_ARM1176 },
+ { "long-plt", no_argument, NULL, OPTION_LONG_PLT },
+'
+
+PARSE_AND_LIST_OPTIONS='
+ fprintf (file, _(" --thumb-entry=<sym> Set the entry point to be Thumb symbol <sym>\n"));
+ fprintf (file, _(" --be8 Output BE8 format image\n"));
+ fprintf (file, _(" --target1-rel Interpret R_ARM_TARGET1 as R_ARM_REL32\n"));
+ fprintf (file, _(" --target1-abs Interpret R_ARM_TARGET1 as R_ARM_ABS32\n"));
+ fprintf (file, _(" --target2=<type> Specify definition of R_ARM_TARGET2\n"));
+ fprintf (file, _(" --fix-v4bx Rewrite BX rn as MOV pc, rn for ARMv4\n"));
+ fprintf (file, _(" --fix-v4bx-interworking Rewrite BX rn branch to ARMv4 interworking veneer\n"));
+ fprintf (file, _(" --use-blx Enable use of BLX instructions\n"));
+ fprintf (file, _(" --vfp11-denorm-fix Specify how to fix VFP11 denorm erratum\n"));
+ fprintf (file, _(" --fix-stm32l4xx-629360 Specify how to fix STM32L4XX 629360 erratum\n"));
+ fprintf (file, _(" --no-enum-size-warning Don'\''t warn about objects with incompatible\n"
+ " enum sizes\n"));
+ fprintf (file, _(" --no-wchar-size-warning Don'\''t warn about objects with incompatible\n"
+ " wchar_t sizes\n"));
+ fprintf (file, _(" --pic-veneer Always generate PIC interworking veneers\n"));
+ fprintf (file, _(" --long-plt Generate long .plt entries\n"
+ " to handle large .plt/.got displacements\n"));
+ fprintf (file, _("\
+ --stub-group-size=N Maximum size of a group of input sections that\n\
+ can be handled by one stub section. A negative\n\
+ value locates all stubs after their branches\n\
+ (with a group size of -N), while a positive\n\
+ value allows two groups of input sections, one\n\
+ before, and one after each stub section.\n\
+ Values of +/-1 indicate the linker should\n\
+ choose suitable defaults.\n"));
+ fprintf (file, _(" --[no-]fix-cortex-a8 Disable/enable Cortex-A8 Thumb-2 branch erratum fix\n"));
+ fprintf (file, _(" --no-merge-exidx-entries Disable merging exidx entries\n"));
+ fprintf (file, _(" --[no-]fix-arm1176 Disable/enable ARM1176 BLX immediate erratum fix\n"));
+'
+
+PARSE_AND_LIST_ARGS_CASES='
+ case '\'p\'':
+ /* Only here for backwards compatibility. */
break;
- case etree_binary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs);
- gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs);
+ case OPTION_THUMB_ENTRY:
+ thumb_entry_symbol = optarg;
break;
- case etree_trinary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond);
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs);
- gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs);
+ case OPTION_BE8:
+ byteswap_code = 1;
break;
- case etree_unary:
- gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child);
+ case OPTION_TARGET1_REL:
+ target1_is_rel = 1;
break;
- default:
+ case OPTION_TARGET1_ABS:
+ target1_is_rel = 0;
break;
- }
-}
-
-/* This is called by the before_allocation routine via
- lang_for_each_statement. It locates any assignment statements, and
- tells the ELF backend about them, in case they are assignments to
- symbols which are referred to by dynamic objects. */
-static void
-gld${EMULATION_NAME}_find_statement_assignment (s)
- lang_statement_union_type *s;
-{
- if (s->header.type == lang_assignment_statement_enum)
- gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
-}
-
-/* This is called after the sections have been attached to output
- sections, but before any sizes or addresses have been set. */
+ case OPTION_TARGET2:
+ target2_type = optarg;
+ break;
-static void
-gld${EMULATION_NAME}_before_allocation ()
-{
- const char *rpath;
- asection *sinterp;
-
- /* If we are going to make any variable assignments, we need to let
- the ELF backend know about them in case the variables are
- referred to by dynamic objects. */
- lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
-
- /* Let the ELF backend work out the sizes of any sections required
- by dynamic linking. */
- rpath = command_line.rpath;
- if (rpath == NULL)
- rpath = (const char *) getenv ("LD_RUN_PATH");
- if (! (bfd_elf${ELFSIZE}_size_dynamic_sections
- (output_bfd, command_line.soname, rpath,
- command_line.export_dynamic, command_line.filter_shlib,
- (const char * const *) command_line.auxiliary_filters,
- &link_info, &sinterp, lang_elf_version_info)))
- einfo ("%P%F: failed to set dynamic section sizes: %E\n");
-
- /* Let the user override the dynamic linker we are using. */
- if (command_line.interpreter != NULL
- && sinterp != NULL)
- {
- sinterp->contents = (bfd_byte *) command_line.interpreter;
- sinterp->_raw_size = strlen (command_line.interpreter) + 1;
- }
+ case OPTION_FIX_V4BX:
+ fix_v4bx = 1;
+ break;
- /* Look for any sections named .gnu.warning. As a GNU extensions,
- we treat such sections as containing warning messages. We print
- out the warning message, and then zero out the section size so
- that it does not get copied into the output file. */
+ case OPTION_FIX_V4BX_INTERWORKING:
+ fix_v4bx = 2;
+ break;
- {
- LANG_FOR_EACH_INPUT_STATEMENT (is)
- {
- asection *s;
- bfd_size_type sz;
- char *msg;
- boolean ret;
-
- if (is->just_syms_flag)
- continue;
-
- s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning");
- if (s == NULL)
- continue;
-
- sz = bfd_section_size (is->the_bfd, s);
- msg = xmalloc ((size_t) sz + 1);
- if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz))
- einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n",
- is->the_bfd);
- msg[sz] = '\0';
- ret = link_info.callbacks->warning (&link_info, msg,
- (const char *) NULL,
- is->the_bfd, (asection *) NULL,
- (bfd_vma) 0);
- ASSERT (ret);
- free (msg);
-
- /* Clobber the section size, so that we don't waste copying the
- warning into the output file. */
- s->_raw_size = 0;
- }
- }
+ case OPTION_USE_BLX:
+ use_blx = 1;
+ break;
- /* we should be able to set the size of the interworking stub section */
+ case OPTION_VFP11_DENORM_FIX:
+ if (strcmp (optarg, "none") == 0)
+ vfp11_denorm_fix = BFD_ARM_VFP11_FIX_NONE;
+ else if (strcmp (optarg, "scalar") == 0)
+ vfp11_denorm_fix = BFD_ARM_VFP11_FIX_SCALAR;
+ else if (strcmp (optarg, "vector") == 0)
+ vfp11_denorm_fix = BFD_ARM_VFP11_FIX_VECTOR;
+ else
+ einfo (_("Unrecognized VFP11 fix type '\''%s'\''.\n"), optarg);
+ break;
- /* Here we rummage through the found bfds to collect glue information */
- /* FIXME: should this be based on a command line option? krk@cygnus.com */
- {
- LANG_FOR_EACH_INPUT_STATEMENT (is)
- {
- if (!bfd_elf32_arm_process_before_allocation (is->the_bfd, & link_info,
- no_pipeline_knowledge))
- {
- /* xgettext:c-format */
- einfo (_("Errors encountered processing file %s"), is->filename);
- }
- }
- }
+ case OPTION_STM32L4XX_FIX:
+ if (!optarg)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_DEFAULT;
+ else if (strcmp (optarg, "none") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_NONE;
+ else if (strcmp (optarg, "default") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_DEFAULT;
+ else if (strcmp (optarg, "all") == 0)
+ stm32l4xx_fix = BFD_ARM_STM32L4XX_FIX_ALL;
+ else
+ einfo (_("Unrecognized STM32L4XX fix type '\''%s'\''.\n"), optarg);
+ break;
- /* We have seen it all. Allocate it, and carry on */
- bfd_elf32_arm_allocate_interworking_sections (& link_info);
-}
+ case OPTION_NO_ENUM_SIZE_WARNING:
+ no_enum_size_warning = 1;
+ break;
-static void
-gld${EMULATION_NAME}_finish PARAMS((void))
-{
- struct bfd_link_hash_entry * h;
+ case OPTION_NO_WCHAR_SIZE_WARNING:
+ no_wchar_size_warning = 1;
+ break;
- if (thumb_entry_symbol == NULL)
- return;
-
- h = bfd_link_hash_lookup (link_info.hash, thumb_entry_symbol, false, false, true);
+ case OPTION_PIC_VENEER:
+ pic_veneer = 1;
+ break;
- if (h != (struct bfd_link_hash_entry *) NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- && h->u.def.section->output_section != NULL)
- {
- static char buffer[32];
- bfd_vma val;
-
- /* Special procesing is required for a Thumb entry symbol. The
- bottom bit of its address must be set. */
- val = (h->u.def.value
- + bfd_get_section_vma (output_bfd,
- h->u.def.section->output_section)
- + h->u.def.section->output_offset);
-
- val |= 1;
+ case OPTION_STUBGROUP_SIZE:
+ {
+ const char *end;
- /* Now convert this value into a string and store it in entry_symbol
- where the lang_finish() function will pick it up. */
- buffer[0] = '0';
- buffer[1] = 'x';
-
- sprintf_vma (buffer + 2, val);
+ group_size = bfd_scan_vma (optarg, &end, 0);
+ if (*end)
+ einfo (_("%P%F: invalid number `%s'\''\n"), optarg);
+ }
+ break;
- if (entry_symbol != NULL && entry_from_cmdline)
- einfo (_("%P: warning: '--thumb-entry %s' is overriding '-e %s'\n"),
- thumb_entry_symbol, entry_symbol);
- entry_symbol = buffer;
- }
- else
- einfo (_("%P: warning: connot find thumb start symbol %s\n"), thumb_entry_symbol);
-}
+ case OPTION_FIX_CORTEX_A8:
+ fix_cortex_a8 = 1;
+ break;
-static char *
-gld${EMULATION_NAME}_get_script (isfile)
- int *isfile;
-EOF
+ case OPTION_NO_FIX_CORTEX_A8:
+ fix_cortex_a8 = 0;
+ break;
-if test -n "$COMPILE_IN"
-then
-# Scripts compiled in.
+ case OPTION_NO_MERGE_EXIDX_ENTRIES:
+ merge_exidx_entries = 0;
+ break;
-# sed commands to quote an ld script as a C string.
-sc="-f stringify.sed"
+ case OPTION_FIX_ARM1176:
+ fix_arm1176 = 1;
+ break;
-cat >>e${EMULATION_NAME}.c <<EOF
-{
- *isfile = 0;
+ case OPTION_NO_FIX_ARM1176:
+ fix_arm1176 = 0;
+ break;
- if (link_info.relocateable == true && config.build_constructors == true)
- return
-EOF
-sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c
-echo ' ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c
-echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c
-echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c
-if test -n "$GENERATE_SHLIB_SCRIPT" ; then
- echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c
- sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
-fi
-echo ' ; else return' >> e${EMULATION_NAME}.c
-sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
-echo '; }' >> e${EMULATION_NAME}.c
-
-else
-# Scripts read from the filesystem.
-
-cat >>e${EMULATION_NAME}.c <<EOF
-{
- *isfile = 1;
-
- if (link_info.relocateable == true && config.build_constructors == true)
- return "ldscripts/${EMULATION_NAME}.xu";
- else if (link_info.relocateable == true)
- return "ldscripts/${EMULATION_NAME}.xr";
- else if (!config.text_read_only)
- return "ldscripts/${EMULATION_NAME}.xbn";
- else if (!config.magic_demand_paged)
- return "ldscripts/${EMULATION_NAME}.xn";
- else if (link_info.shared)
- return "ldscripts/${EMULATION_NAME}.xs";
- else
- return "ldscripts/${EMULATION_NAME}.x";
-}
-EOF
+ case OPTION_LONG_PLT:
+ bfd_elf32_arm_use_long_plt ();
+ break;
+'
-fi
+# We have our own before_allocation etc. functions, but they call
+# the standard routines, so give them a different name.
+LDEMUL_BEFORE_ALLOCATION=arm_elf_before_allocation
+LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=arm_elf_create_output_section_statements
-cat >>e${EMULATION_NAME}.c <<EOF
+# Replace the elf before_parse function with our own.
+LDEMUL_BEFORE_PARSE=gld"${EMULATION_NAME}"_before_parse
+LDEMUL_SET_SYMBOLS=gld"${EMULATION_NAME}"_set_symbols
-struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
-{
- gld${EMULATION_NAME}_before_parse,
- syslib_default,
- hll_default,
- after_parse_default,
- gld${EMULATION_NAME}_after_open,
- after_allocation_default,
- set_output_arch_default,
- ldemul_default_target,
- gld${EMULATION_NAME}_before_allocation,
- gld${EMULATION_NAME}_get_script,
- "${EMULATION_NAME}",
- "${OUTPUT_FORMAT}",
- gld${EMULATION_NAME}_finish,
- NULL, /* create output section statements */
- gld${EMULATION_NAME}_open_dynamic_archive,
- gld${EMULATION_NAME}_place_orphan,
- NULL, /* set symbols */
- gld${EMULATION_NAME}_parse_args,
- NULL, /* unrecognized file */
- gld${EMULATION_NAME}_list_options,
- NULL /* recognized file */
-};
-EOF
+# Call the extra arm-elf function
+LDEMUL_FINISH=gld${EMULATION_NAME}_finish