X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ld%2Femultempl%2Felf32.em;h=682f5e53934f641b1a8fe13af7adf1a2fec4821b;hb=677e5a92b1e998e33fbe216f4cbb52cc88b74bca;hp=19d98fedbd06dcb5ad18156aa5a63ab6994c90da;hpb=e13629bc072285a3df8c99c5ae377601fa190043;p=external%2Fbinutils.git diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 19d98fe..682f5e5 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -8,39 +8,44 @@ if [ -z "$MACHINE" ]; then else OUTPUT_ARCH=${ARCH}:${MACHINE} fi -cat >e${EMULATION_NAME}.c < ELF support by Ian Lance Taylor -This file is part of GLD, the Gnu Linker. + 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 2 of the License, or -(at your option) any later version. + 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. + 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. */ + 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. */ #define TARGET_IS_${EMULATION_NAME} -#include "config.h" -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" +#include "filenames.h" #include "safe-ctype.h" #include "getopt.h" +#include "md5.h" +#include "sha1.h" +#include #include "bfdlink.h" @@ -54,21 +59,21 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #include #include "elf/common.h" #include "elf-bfd.h" +#include "filenames.h" /* Declare functions used by various EXTRA_EM_FILEs. */ static void gld${EMULATION_NAME}_before_parse (void); static void gld${EMULATION_NAME}_after_open (void); static void gld${EMULATION_NAME}_before_allocation (void); -static bfd_boolean gld${EMULATION_NAME}_place_orphan (asection *s); -static void gld${EMULATION_NAME}_layout_sections_again (void); -static void gld${EMULATION_NAME}_finish (void) ATTRIBUTE_UNUSED; - +static void gld${EMULATION_NAME}_after_allocation (void); +static lang_output_section_statement_type *gld${EMULATION_NAME}_place_orphan + (asection *, const char *, int); EOF if [ "x${USE_LIBPATH}" = xyes ] ; then case ${target} in - *-*-linux-* | *-*-k*bsd*-*) - cat >>e${EMULATION_NAME}.c < #endif @@ -79,8 +84,9 @@ fi # Import any needed special functions and/or overrides. # +source_em ${srcdir}/emultempl/elf-generic.em if test -n "$EXTRA_EM_FILE" ; then -. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em + source_em ${srcdir}/emultempl/${EXTRA_EM_FILE}.em fi # Functions in this file can be overridden by setting the LDEMUL_* shell @@ -90,50 +96,52 @@ fi # as presumably it is called from the overriding function. # if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then -cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <as_needed) - class = DYN_AS_NEEDED; + if (entry->flags.add_DT_NEEDED_for_regular) + link_class = DYN_AS_NEEDED; /* Tell the ELF linker that we don't want the output file to have a DT_NEEDED entry for any dynamic library in DT_NEEDED tags from this file at all. */ - if (!entry->add_needed) - class |= DYN_NO_ADD_NEEDED; + if (!entry->flags.add_DT_NEEDED_for_dynamic) + link_class |= DYN_NO_ADD_NEEDED; - if (entry->just_syms_flag + if (entry->flags.just_syms && (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) != 0) einfo (_("%P%F: --just-symbols may not be used on DSO: %B\n"), entry->the_bfd); - if (!class + if (link_class == 0 || (bfd_get_file_flags (entry->the_bfd) & DYNAMIC) == 0) return FALSE; - bfd_elf_set_dyn_lib_class (entry->the_bfd, class); + bfd_elf_set_dyn_lib_class (entry->the_bfd, + (enum dynamic_lib_link_class) link_class); /* Continue on with normal load_symbols processing. */ return FALSE; @@ -141,7 +149,7 @@ gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry) EOF fi -cat >>e${EMULATION_NAME}.c <name) == 0) + if (filename_cmp (soname, l->name) == 0) { /* Probably can't happen, but it's an easy check. */ continue; @@ -205,7 +220,7 @@ gld${EMULATION_NAME}_vercheck (lang_input_statement_type *s) suffix += sizeof ".so." - 1; - if (strncmp (soname, l->name, suffix - l->name) == 0) + if (filename_ncmp (soname, 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 @@ -280,7 +295,7 @@ gld${EMULATION_NAME}_stat_needed (lang_input_statement_type *s) if (soname == NULL) soname = lbasename (s->filename); - if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0) + if (filename_ncmp (soname, 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, soname); } @@ -302,11 +317,15 @@ gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, bfd *abfd; const char *name = needed->name; const char *soname; - int class; + int link_class; - abfd = bfd_openr (name, bfd_get_target (output_bfd)); + abfd = bfd_openr (name, bfd_get_target (link_info.output_bfd)); if (abfd == NULL) return FALSE; + + /* Linker needs to decompress sections. */ + abfd->flags |= BFD_DECOMPRESS; + if (! bfd_check_format (abfd, bfd_object)) { bfd_close (abfd); @@ -319,7 +338,7 @@ gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, } /* For DT_NEEDED, they have to match. */ - if (abfd->xvec != output_bfd->xvec) + if (abfd->xvec != link_info.output_bfd->xvec) { bfd_close (abfd); return FALSE; @@ -332,14 +351,14 @@ gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, if (! force) { - struct bfd_link_needed_list *needed; + struct bfd_link_needed_list *needs; - if (! bfd_elf_get_bfd_needed_list (abfd, &needed)) + if (! bfd_elf_get_bfd_needed_list (abfd, &needs)) einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); - if (needed != NULL) + if (needs != NULL) { - global_vercheck_needed = needed; + global_vercheck_needed = needs; global_vercheck_failed = FALSE; lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); if (global_vercheck_failed) @@ -359,13 +378,13 @@ gld${EMULATION_NAME}_try_needed (struct dt_needed *needed, EOF case ${target} in - *-*-linux-* | *-*-k*bsd*-*) - cat >>e${EMULATION_NAME}.c <next) - if (strncmp (l->name, "libc.so", 7) == 0) + for (l = needs; l != NULL; l = l->next) + if (CONST_STRNEQ (l->name, "libc.so")) break; if (l == NULL) { @@ -377,7 +396,7 @@ case ${target} in EOF ;; esac -cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <filename); - if (trace_file_tries) + if (verbose) info_msg (_("found %s at %s\n"), soname, name); global_found = NULL; @@ -415,20 +434,20 @@ cat >>e${EMULATION_NAME}.c <by != NULL && (bfd_elf_get_dyn_lib_class (needed->by) & DYN_NO_ADD_NEEDED) != 0) - class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; + link_class |= DYN_NO_NEEDED | DYN_NO_ADD_NEEDED; - bfd_elf_set_dyn_lib_class (abfd, class); + bfd_elf_set_dyn_lib_class (abfd, (enum dynamic_lib_link_class) link_class); /* 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); + einfo ("%F%B: error adding symbols: %E\n", abfd); return TRUE; } @@ -459,10 +478,21 @@ gld${EMULATION_NAME}_search_needed (const char *path, { char *filename, *sset; - s = strchr (path, ':'); + s = strchr (path, config.rpath_separator); if (s == NULL) s = path + strlen (path); +#if HAVE_DOS_BASED_FILE_SYSTEM + /* Assume a match on the second char is part of drive specifier. */ + else if (config.rpath_separator == ':' + && s == path + 1 + && ISALPHA (*path)) + { + s = strchr (s + 1, config.rpath_separator); + if (s == NULL) + s = path + strlen (path); + } +#endif filename = (char *) xmalloc (s - path + len + 2); if (s == path) sset = filename; @@ -490,9 +520,10 @@ gld${EMULATION_NAME}_search_needed (const char *path, EOF if [ "x${USE_LIBPATH}" = xyes ] ; then - cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c < @@ -541,7 +572,8 @@ EOF #endif static bfd_boolean -gld${EMULATION_NAME}_check_ld_elf_hints (const char *name, int force) +gld${EMULATION_NAME}_check_ld_elf_hints (const struct bfd_link_needed_list *l, + int force) { static bfd_boolean initialized; static char *ld_elf_hints; @@ -552,7 +584,7 @@ gld${EMULATION_NAME}_check_ld_elf_hints (const char *name, int force) FILE *f; char *tmppath; - tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, NULL); + tmppath = concat (ld_sysroot, _PATH_ELF_HINTS, (const char *) NULL); f = fopen (tmppath, FOPEN_RB); free (tmppath); if (f != NULL) @@ -584,17 +616,16 @@ gld${EMULATION_NAME}_check_ld_elf_hints (const char *name, int force) if (ld_elf_hints == NULL) return FALSE; - needed.by = NULL; - needed.name = name; - return gld${EMULATION_NAME}_search_needed (ld_elf_hints, & needed, - force); + needed.by = l->by; + needed.name = l->name; + return gld${EMULATION_NAME}_search_needed (ld_elf_hints, &needed, force); } EOF # FreeBSD ;; - *-*-linux-* | *-*-k*bsd*-*) - cat >>e${EMULATION_NAME}.c <alloc += p - dir + 256; info->path = xrealloc (info->path, info->alloc); } - info->path[info->len++] = ':'; + info->path[info->len++] = config.rpath_separator; } memcpy (info->path + info->len, dir, p - dir); info->len += p - dir; @@ -759,7 +790,8 @@ gld${EMULATION_NAME}_parse_ld_so_conf } static bfd_boolean -gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) +gld${EMULATION_NAME}_check_ld_so_conf (const struct bfd_link_needed_list *l, + int force) { static bfd_boolean initialized; static char *ld_so_conf; @@ -772,11 +804,13 @@ gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) info.path = NULL; info.len = info.alloc = 0; - tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", NULL); + tmppath = concat (ld_sysroot, "${prefix}/etc/ld.so.conf", + (const char *) NULL); if (!gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath)) { free (tmppath); - tmppath = concat (ld_sysroot, "/etc/ld.so.conf", NULL); + tmppath = concat (ld_sysroot, "/etc/ld.so.conf", + (const char *) NULL); gld${EMULATION_NAME}_parse_ld_so_conf (&info, tmppath); } free (tmppath); @@ -794,8 +828,8 @@ gld${EMULATION_NAME}_check_ld_so_conf (const char *name, int force) return FALSE; - needed.by = NULL; - needed.name = name; + needed.by = l->by; + needed.name = l->name; return gld${EMULATION_NAME}_search_needed (ld_so_conf, &needed, force); } @@ -804,7 +838,7 @@ EOF ;; esac fi -cat >>e${EMULATION_NAME}.c <the_bfd) & DYN_AS_NEEDED) != 0) return; - if (strcmp (s->filename, global_needed->name) == 0) + if (filename_cmp (s->filename, global_needed->name) == 0) { global_found = s; return; } - if (s->search_dirs_flag) + if (s->flags.search_dirs) { const char *f = strrchr (s->filename, '/'); if (f != NULL - && strcmp (f + 1, global_needed->name) == 0) + && filename_cmp (f + 1, global_needed->name) == 0) { global_found = s; return; @@ -846,7 +880,7 @@ gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) soname = bfd_elf_get_dt_soname (s->the_bfd); if (soname != NULL - && strcmp (soname, global_needed->name) == 0) + && filename_cmp (soname, global_needed->name) == 0) { global_found = s; return; @@ -856,7 +890,194 @@ gld${EMULATION_NAME}_check_needed (lang_input_statement_type *s) EOF if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then -cat >>e${EMULATION_NAME}.c <o->build_id.style; + asec = t->o->build_id.sec; + if (bfd_is_abs_section (asec->output_section)) + { + einfo (_("%P: warning: .note.gnu.build-id section discarded," + " --build-id ignored.\n")); + return TRUE; + } + i_shdr = &elf_section_data (asec->output_section)->this_hdr; + + if (i_shdr->contents == NULL) + { + if (asec->contents == NULL) + asec->contents = (unsigned char *) xmalloc (asec->size); + contents = asec->contents; + } + else + contents = i_shdr->contents + asec->output_offset; + + e_note = (Elf_External_Note *) contents; + size = offsetof (Elf_External_Note, name[sizeof "GNU"]); + size = (size + 3) & -(bfd_size_type) 4; + id_bits = contents + size; + size = asec->size - size; + + bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz); + bfd_h_put_32 (abfd, size, &e_note->descsz); + bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type); + memcpy (e_note->name, "GNU", sizeof "GNU"); + + if (strcmp (style, "md5") == 0) + { + struct md5_ctx ctx; + + md5_init_ctx (&ctx); + if (!bed->s->checksum_contents (abfd, (sum_fn) &md5_process_bytes, &ctx)) + return FALSE; + md5_finish_ctx (&ctx, id_bits); + } + else if (strcmp (style, "sha1") == 0) + { + struct sha1_ctx ctx; + + sha1_init_ctx (&ctx); + if (!bed->s->checksum_contents (abfd, (sum_fn) &sha1_process_bytes, &ctx)) + return FALSE; + sha1_finish_ctx (&ctx, id_bits); + } + else if (strcmp (style, "uuid") == 0) + { + int n; + int fd = open ("/dev/urandom", O_RDONLY); + if (fd < 0) + return FALSE; + n = read (fd, id_bits, size); + close (fd); + if (n < (int) size) + return FALSE; + } + else if (strncmp (style, "0x", 2) == 0) + { + /* ID is in string form (hex). Convert to bits. */ + const char *id = style + 2; + size_t n = 0; + do + { + if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) + { + id_bits[n] = read_hex (*id++) << 4; + id_bits[n++] |= read_hex (*id++); + } + else if (*id == '-' || *id == ':') + ++id; + else + abort (); /* Should have been validated earlier. */ + } while (*id != '\0'); + } + else + abort (); /* Should have been validated earlier. */ + + position = i_shdr->sh_offset + asec->output_offset; + size = asec->size; + return (bfd_seek (abfd, position, SEEK_SET) == 0 + && bfd_bwrite (contents, size, abfd) == size); +} + +/* Make .note.gnu.build-id section, and set up elf_tdata->build_id. */ + +static bfd_boolean +setup_build_id (bfd *ibfd) +{ + asection *s; + bfd_size_type size; + flagword flags; + + size = id_note_section_size (ibfd); + if (size == 0) + { + einfo ("%P: warning: unrecognized --build-id style ignored.\n"); + return FALSE; + } + + flags = (SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA); + s = bfd_make_section_with_flags (ibfd, ".note.gnu.build-id", flags); + if (s != NULL && bfd_set_section_alignment (ibfd, s, 2)) + { + struct elf_obj_tdata *t = elf_tdata (link_info.output_bfd); + t->o->build_id.after_write_object_contents = &write_build_id; + t->o->build_id.style = emit_note_gnu_build_id; + t->o->build_id.sec = s; + elf_section_type (s) = SHT_NOTE; + s->size = size; + return TRUE; + } + + einfo ("%P: warning: Cannot create .note.gnu.build-id section," + " --build-id ignored.\n"); + return FALSE; +} /* This is called after all the input files have been opened. */ @@ -864,11 +1085,80 @@ static void gld${EMULATION_NAME}_after_open (void) { struct bfd_link_needed_list *needed, *l; + struct elf_link_hash_table *htab; - /* We only need to worry about this when doing a final link. */ - if (link_info.relocatable || !link_info.executable) + after_open_default (); + + htab = elf_hash_table (&link_info); + if (!is_elf_hash_table (htab)) + return; + + if (emit_note_gnu_build_id != NULL) + { + bfd *abfd; + + /* Find an ELF input. */ + for (abfd = link_info.input_bfds; + abfd != (bfd *) NULL; abfd = abfd->link_next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + break; + + /* PR 10555: If there are no ELF input files do not try to + create a .note.gnu-build-id section. */ + if (abfd == NULL + || !setup_build_id (abfd)) + { + free ((char *) emit_note_gnu_build_id); + emit_note_gnu_build_id = NULL; + } + } + + if (link_info.relocatable) return; + if (link_info.eh_frame_hdr + && !link_info.traditional_format) + { + bfd *abfd, *elfbfd = NULL; + bfd_boolean warn_eh_frame = FALSE; + asection *s; + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + elfbfd = abfd; + if (!warn_eh_frame) + { + s = bfd_get_section_by_name (abfd, ".eh_frame"); + while (s != NULL + && (s->size <= 8 + || bfd_is_abs_section (s->output_section))) + s = bfd_get_next_section_by_name (s); + warn_eh_frame = s != NULL; + } + if (elfbfd && warn_eh_frame) + break; + } + if (elfbfd) + { + const struct elf_backend_data *bed; + + bed = get_elf_backend_data (elfbfd); + s = bfd_make_section_with_flags (elfbfd, ".eh_frame_hdr", + bed->dynamic_sec_flags + | SEC_READONLY); + if (s != NULL + && bfd_set_section_alignment (elfbfd, s, 2)) + { + htab->eh_info.hdr_sec = s; + warn_eh_frame = FALSE; + } + } + if (warn_eh_frame) + einfo ("%P: warning: Cannot create .eh_frame_hdr section," + " --eh-frame-hdr ignored.\n"); + } + /* 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 @@ -878,7 +1168,7 @@ gld${EMULATION_NAME}_after_open (void) 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); + needed = bfd_elf_get_needed_list (link_info.output_bfd, &link_info); for (l = needed; l != NULL; l = l->next) { struct bfd_link_needed_list *ll; @@ -891,6 +1181,13 @@ gld${EMULATION_NAME}_after_open (void) && (bfd_elf_get_dyn_lib_class (l->by) & DYN_AS_NEEDED) != 0) continue; + /* Skip the lib if --no-copy-dt-needed-entries and + --allow-shlib-undefined is in effect. */ + if (l->by != NULL + && link_info.unresolved_syms_in_shared_libs == RM_IGNORE + && (bfd_elf_get_dyn_lib_class (l->by) & DYN_NO_ADD_NEEDED) != 0) + continue; + /* If we've already seen this file, skip it. */ for (ll = needed; ll != l; ll = ll->next) if ((ll->by == NULL @@ -912,7 +1209,7 @@ gld${EMULATION_NAME}_after_open (void) n.by = l->by; n.name = l->name; nn.by = l->by; - if (trace_file_tries) + if (verbose) info_msg (_("%s needed by %B\n"), l->name, l->by); /* As-needed libs specified on the command line (or linker script) @@ -941,31 +1238,31 @@ gld${EMULATION_NAME}_after_open (void) search_dirs_type *search; EOF if [ "x${NATIVE}" = xyes ] ; then -cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <next) { char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name); @@ -1000,24 +1297,24 @@ fi if [ "x${USE_LIBPATH}" = xyes ] ; then case ${target} in *-*-freebsd* | *-*-dragonfly*) - cat >>e${EMULATION_NAME}.c <name, force)) + fragment <>e${EMULATION_NAME}.c <name, force)) + *-*-linux-* | *-*-k*bsd*-* | *-*-gnu*) + fragment <>e${EMULATION_NAME}.c <name); for (search = search_head; search != NULL; search = search->next) { @@ -1035,7 +1332,7 @@ cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <type.node_class) { case etree_provide: + case etree_provided: provide = TRUE; /* Fall thru */ case etree_assign: @@ -1073,7 +1371,8 @@ gld${EMULATION_NAME}_find_exp_assignment (etree_type *exp) will do no harm. */ if (strcmp (exp->assign.dst, ".") != 0) { - if (!bfd_elf_record_link_assignment (output_bfd, &link_info, + if (!bfd_elf_record_link_assignment (link_info.output_bfd, + &link_info, exp->assign.dst, provide, exp->assign.hidden)) einfo ("%P%F: failed to record assignment to %s: %E\n", @@ -1130,7 +1429,47 @@ if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; else ELF_INTERPRETER_SET_DEFAULT= fi -cat >>e${EMULATION_NAME}.c <type == bfd_link_elf_hash_table) - _bfd_elf_tls_setup (output_bfd, &link_info); - - /* 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); + if (is_elf_hash_table (link_info.hash)) + { + _bfd_elf_tls_setup (link_info.output_bfd, &link_info); + + /* Make __ehdr_start hidden if it has been referenced, to + prevent the symbol from being dynamic. */ + if (!bfd_elf_record_link_assignment (link_info.output_bfd, &link_info, + "__ehdr_start", TRUE, TRUE)) + einfo ("%P%F: failed to record assignment to %s: %E\n", + "__ehdr_start"); + + /* 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"); + + for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + const char *audit_libs = elf_dt_audit (abfd); + + /* If the input bfd contains an audit entry, we need to add it as + a dep audit entry. */ + if (audit_libs && *audit_libs != '\0') + { + char *cp = xstrdup (audit_libs); + do + { + int more = 0; + char *cp2 = strchr (cp, config.rpath_separator); + + if (cp2) + { + *cp2 = '\0'; + more = 1; + } + + if (cp != NULL && *cp != '\0') + gld${EMULATION_NAME}_append_to_separated_string (&depaudit, cp); + + cp = more ? ++cp2 : NULL; + } + while (cp != NULL); + } + } + if (! (bfd_elf_size_dynamic_sections - (output_bfd, command_line.soname, rpath, - command_line.filter_shlib, + (link_info.output_bfd, command_line.soname, rpath, + command_line.filter_shlib, audit, depaudit, (const char * const *) command_line.auxiliary_filters, - &link_info, &sinterp, lang_elf_version_info))) + &link_info, &sinterp))) einfo ("%P%F: failed to set dynamic section sizes: %E\n"); ${ELF_INTERPRETER_SET_DEFAULT} @@ -1180,12 +1560,10 @@ ${ELF_INTERPRETER_SET_DEFAULT} { asection *s; bfd_size_type sz; - bfd_size_type prefix_len; char *msg; bfd_boolean ret; - const char * gnu_warning_prefix = _("warning: "); - if (is->just_syms_flag) + if (is->flags.just_syms) continue; s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); @@ -1193,14 +1571,12 @@ ${ELF_INTERPRETER_SET_DEFAULT} continue; sz = s->size; - prefix_len = strlen (gnu_warning_prefix); - msg = xmalloc ((size_t) (prefix_len + sz + 1)); - strcpy (msg, gnu_warning_prefix); - if (! bfd_get_section_contents (is->the_bfd, s, msg + prefix_len, + msg = (char *) 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[prefix_len + sz] = '\0'; + msg[sz] = '\0'; ret = link_info.callbacks->warning (&link_info, msg, (const char *) NULL, is->the_bfd, (asection *) NULL, @@ -1208,19 +1584,26 @@ ${ELF_INTERPRETER_SET_DEFAULT} ASSERT (ret); free (msg); - /* Clobber the section size, so that we don't waste copying the - warning into the output file. */ + /* Clobber the section size, so that we don't waste space + copying the warning into the output file. If we've already + sized the output section, adjust its size. The adjustment + is on rawsize because targets that size sections early will + have called lang_reset_memory_regions after sizing. */ + if (s->output_section != NULL + && s->output_section->rawsize >= s->size) + s->output_section->rawsize -= s->size; + s->size = 0; - /* Also set SEC_EXCLUDE, so that symbols defined in the warning - section don't get copied to the output. */ - s->flags |= SEC_EXCLUDE; + /* Also set SEC_EXCLUDE, so that local symbols defined in the + warning section don't get copied to the output. */ + s->flags |= SEC_EXCLUDE | SEC_KEEP; } } before_allocation_default (); - if (!bfd_elf_size_dynsym_hash_dynstr (output_bfd, &link_info)) + if (!bfd_elf_size_dynsym_hash_dynstr (link_info.output_bfd, &link_info)) einfo ("%P%F: failed to set dynamic section sizes: %E\n"); } @@ -1228,7 +1611,7 @@ EOF fi if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then -cat >>e${EMULATION_NAME}.c <is_archive) + if (! entry->flags.maybe_archive) return FALSE; filename = entry->filename; @@ -1263,8 +1646,9 @@ gld${EMULATION_NAME}_open_dynamic_archive /* Try the .so extension first. If that fails build a new filename using EXTRA_SHLIB_EXTENSION. */ if (! ldfile_try_open_bfd (string, entry)) - sprintf (string, "%s/lib%s%s%s", search->name, - filename, arch, EXTRA_SHLIB_EXTENSION); + { + sprintf (string, "%s/lib%s%s%s", search->name, + filename, arch, EXTRA_SHLIB_EXTENSION); #endif if (! ldfile_try_open_bfd (string, entry)) @@ -1272,6 +1656,9 @@ gld${EMULATION_NAME}_open_dynamic_archive free (string); return FALSE; } +#ifdef EXTRA_SHLIB_EXTENSION + } +#endif entry->filename = string; @@ -1291,7 +1678,7 @@ gld${EMULATION_NAME}_open_dynamic_archive if (bfd_check_format (entry->the_bfd, bfd_object) && (entry->the_bfd->flags & DYNAMIC) != 0) { - ASSERT (entry->is_archive && entry->search_dirs_flag); + ASSERT (entry->flags.maybe_archive && entry->flags.search_dirs); /* Rather than duplicating the logic above. Just use the filename we recorded earlier. */ @@ -1307,7 +1694,7 @@ EOF fi if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then -cat >>e${EMULATION_NAME}.c <name[4] == 'a'; @@ -1325,8 +1713,8 @@ output_rel_find (asection *sec, int isdyn) lookup != NULL; lookup = lookup->next) { - if (lookup->constraint != -1 - && strncmp (".rel", lookup->name, 4) == 0) + if (lookup->constraint >= 0 + && CONST_STRNEQ (lookup->name, ".rel")) { int lookrela = lookup->name[4] == 'a'; @@ -1351,7 +1739,11 @@ output_rel_find (asection *sec, int isdyn) last = lookup; if (lookup->bfd_section != NULL && (lookup->bfd_section->flags & SEC_ALLOC) != 0) - last_alloc = lookup; + { + last_alloc = lookup; + if ((lookup->bfd_section->flags & SEC_READONLY) != 0) + last_ro_alloc = lookup; + } } if (last_rel_alloc) @@ -1360,6 +1752,9 @@ output_rel_find (asection *sec, int isdyn) if (last_rel) return last_rel; + if (last_ro_alloc) + return last_ro_alloc; + if (last_alloc) return last_alloc; @@ -1369,8 +1764,10 @@ output_rel_find (asection *sec, int isdyn) /* Place an orphan section. We use this to put random SHF_ALLOC sections in the right segment. */ -static bfd_boolean -gld${EMULATION_NAME}_place_orphan (asection *s) +static lang_output_section_statement_type * +gld${EMULATION_NAME}_place_orphan (asection *s, + const char *secname, + int constraint) { static struct orphan_save hold[] = { @@ -1394,7 +1791,10 @@ gld${EMULATION_NAME}_place_orphan (asection *s) 0, 0, 0, 0 }, { ".sdata", SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_SMALL_DATA, - 0, 0, 0, 0 } + 0, 0, 0, 0 }, + { ".comment", + SEC_HAS_CONTENTS, + 0, 0, 0, 0 }, }; enum orphan_save_index { @@ -1404,19 +1804,18 @@ gld${EMULATION_NAME}_place_orphan (asection *s) orphan_bss, orphan_rel, orphan_interp, - orphan_sdata + orphan_sdata, + orphan_nonalloc }; static int orphan_init_done = 0; struct orphan_save *place; - const char *secname; lang_output_section_statement_type *after; lang_output_section_statement_type *os; + lang_output_section_statement_type *match_by_name = NULL; int isdyn = 0; int iself = s->owner->xvec->flavour == bfd_target_elf_flavour; unsigned int sh_type = iself ? elf_section_type (s) : SHT_NULL; - secname = bfd_get_section_name (s->owner, s); - if (! link_info.relocatable && link_info.combreloc && (s->flags & SEC_ALLOC)) @@ -1435,40 +1834,58 @@ gld${EMULATION_NAME}_place_orphan (asection *s) default: break; } - else if (strncmp (secname, ".rel", 4) == 0) + else if (CONST_STRNEQ (secname, ".rel")) { secname = secname[4] == 'a' ? ".rela.dyn" : ".rel.dyn"; isdyn = 1; } } - if (isdyn || (!config.unique_orphan_sections && !unique_section_p (s))) + /* Look through the script to see where to place this section. */ + if (constraint == 0) + for (os = lang_output_section_find (secname); + os != NULL; + os = next_matching_output_section_statement (os, 0)) + { + /* If we don't match an existing output section, tell + lang_insert_orphan to create a new output section. */ + constraint = SPECIAL; + + if (os->bfd_section != NULL + && (os->bfd_section->flags == 0 + || (_bfd_elf_match_sections_by_type (link_info.output_bfd, + os->bfd_section, + s->owner, s) + && ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0))) + { + /* We already have an output section statement with this + name, and its bfd section has compatible flags. + If the section already exists but does not have any flags + set, then it has been created by the linker, probably as a + result of a --section-start command line switch. */ + lang_add_section (&os->children, s, NULL, os); + return os; + } + + /* Save unused output sections in case we can match them + against orphans later. */ + if (os->bfd_section == NULL) + match_by_name = os; + } + + /* If we didn't match an active output section, see if we matched an + unused one and use that. */ + if (match_by_name) { - /* Look through the script to see where to place this section. */ - os = lang_output_section_find (secname); - - if (os != NULL - && (os->bfd_section == NULL - || os->bfd_section->flags == 0 - || (_bfd_elf_match_sections_by_type (output_bfd, - os->bfd_section, - s->owner, s) - && ((s->flags ^ os->bfd_section->flags) - & (SEC_LOAD | SEC_ALLOC)) == 0))) - { - /* We already have an output section statement with this - name, and its bfd section, if any, has compatible flags. - If the section already exists but does not have any flags - set, then it has been created by the linker, probably as a - result of a --section-start command line switch. */ - lang_add_section (&os->children, s, os); - return TRUE; - } + lang_add_section (&match_by_name->children, s, NULL, match_by_name); + return match_by_name; } if (!orphan_init_done) { struct orphan_save *ho; + for (ho = hold; ho < hold + sizeof (hold) / sizeof (hold[0]); ++ho) if (ho->name != NULL) { @@ -1483,12 +1900,12 @@ gld${EMULATION_NAME}_place_orphan (asection *s) sections into the .text section to get them out of the way. */ if (link_info.executable && ! link_info.relocatable - && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 + && CONST_STRNEQ (s->name, ".gnu.warning.") && hold[orphan_text].os != NULL) { - lang_add_section (&hold[orphan_text].os->children, s, - hold[orphan_text].os); - return TRUE; + os = hold[orphan_text].os; + lang_add_section (&os->children, s, NULL, os); + return os; } /* Decide which segment the section should go in based on the @@ -1498,20 +1915,22 @@ gld${EMULATION_NAME}_place_orphan (asection *s) in the first page. */ place = NULL; - if ((s->flags & SEC_ALLOC) == 0) + if ((s->flags & (SEC_ALLOC | SEC_DEBUGGING)) == 0) + place = &hold[orphan_nonalloc]; + else if ((s->flags & SEC_ALLOC) == 0) ; else if ((s->flags & SEC_LOAD) != 0 && ((iself && sh_type == SHT_NOTE) - || (!iself && strncmp (secname, ".note", 5) == 0))) + || (!iself && CONST_STRNEQ (secname, ".note")))) place = &hold[orphan_interp]; - else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + else if ((s->flags & (SEC_LOAD | SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) == 0) place = &hold[orphan_bss]; else if ((s->flags & SEC_SMALL_DATA) != 0) place = &hold[orphan_sdata]; else if ((s->flags & SEC_READONLY) == 0) place = &hold[orphan_data]; else if (((iself && (sh_type == SHT_RELA || sh_type == SHT_REL)) - || (!iself && strncmp (secname, ".rel", 4) == 0)) + || (!iself && CONST_STRNEQ (secname, ".rel"))) && (s->flags & SEC_LOAD) != 0) place = &hold[orphan_rel]; else if ((s->flags & SEC_CODE) == 0) @@ -1538,55 +1957,26 @@ gld${EMULATION_NAME}_place_orphan (asection *s) after = &lang_output_section_statement.head->output_section_statement; } - /* 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 allocatable characteristics. */ - if (bfd_get_section_by_name (output_bfd, secname) != NULL) - { - static int count = 1; - secname = bfd_get_unique_section_name (output_bfd, secname, &count); - if (secname == NULL) - einfo ("%F%P: place_orphan failed: %E\n"); - } - - lang_insert_orphan (s, secname, after, place, NULL, NULL); - - return TRUE; + return lang_insert_orphan (s, secname, constraint, after, place, NULL, NULL); } EOF fi -if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then -cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c echo ' && link_info.relro' >> e${EMULATION_NAME}.c -echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c echo ' ; else if (link_info.pie && link_info.combreloc) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c @@ -1631,7 +2021,7 @@ if test -n "$GENERATE_SHLIB_SCRIPT" ; then if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then echo ' ; else if (link_info.shared && link_info.combreloc' >> e${EMULATION_NAME}.c echo ' && link_info.relro' >> e${EMULATION_NAME}.c -echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c @@ -1641,7 +2031,7 @@ sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c fi if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then echo ' ; else if (link_info.combreloc && link_info.relro' >> e${EMULATION_NAME}.c -echo ' && (link_info.flags & DT_BIND_NOW)) return' >> e${EMULATION_NAME}.c +echo ' && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c @@ -1653,7 +2043,7 @@ echo '; }' >> e${EMULATION_NAME}.c else # Scripts read from the filesystem. -cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <