X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Femultempl%2Felf32.em;h=71e34b5abc0039ccbcb17c49f8fe6ffa81c98f67;hb=6cc7365e2b682389efdaf16431189f7762805bc3;hp=0f4ee72a1856a191d7a4edc25d062cc7a1cea480;hpb=ae02b41c5074a72e3822d8208f5e636fafde81ee;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 0f4ee72a18..71e34b5abc 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -4,7 +4,7 @@ cat >e${EMULATION_NAME}.c < ELF support by Ian Lance Taylor @@ -22,7 +22,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define TARGET_IS_${EMULATION_NAME} @@ -34,7 +34,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bfdlink.h" #include "ld.h" -#include "config.h" #include "ldmain.h" #include "ldemul.h" #include "ldfile.h" @@ -45,7 +44,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ static void gld${EMULATION_NAME}_before_parse PARAMS ((void)); static boolean gld${EMULATION_NAME}_open_dynamic_archive - PARAMS ((const char *, lang_input_statement_type *)); + 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 *)); +static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *)); static void gld${EMULATION_NAME}_before_allocation PARAMS ((void)); static void gld${EMULATION_NAME}_find_statement_assignment PARAMS ((lang_statement_union_type *)); @@ -59,7 +66,7 @@ static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); static void gld${EMULATION_NAME}_before_parse() { - ldfile_output_architecture = bfd_arch_${ARCH}; + ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; config.dynamic_link = ${DYNAMIC_LINK-true}; } @@ -67,16 +74,33 @@ gld${EMULATION_NAME}_before_parse() dynamic libraries have an extension of .so. */ static boolean -gld${EMULATION_NAME}_open_dynamic_archive (arch, entry) +gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry) const char *arch; + search_dirs_type *search; lang_input_statement_type *entry; { const char *filename; + char *string; + + if (! entry->is_archive) + return false; filename = entry->filename; - if (! ldfile_open_file_search (arch, entry, "lib", ".so")) - return false; + string = (char *) xmalloc (strlen (search->name) + + strlen (filename) + + strlen (arch) + + sizeof "/lib.so"); + + sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); + + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return false; + } + + 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 @@ -107,12 +131,411 @@ gld${EMULATION_NAME}_open_dynamic_archive (arch, entry) return true; } +EOF +if [ "x${host}" = "x${target}" ] ; then +cat >>e${EMULATION_NAME}.c <= 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; + } + } + } + + if (len > 0 && b[len - 1] == ':') + --len; + + if (len > 0) + b[len] = '\0'; + else + { + free (b); + b = NULL; + } + + fclose (f); + + ld_so_conf = b; + } + + initialized = true; + } + + if (ld_so_conf == NULL) + return false; + + return gld${EMULATION_NAME}_search_needed (ld_so_conf, name); +} + +EOF +fi +cat >>e${EMULATION_NAME}.c <next) + { + struct bfd_link_needed_list *ll; + const char *lib_path; + size_t len; + search_dirs_type *search; + + /* 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; + + /* 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; + + /* 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. */ + if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, + l->name)) + continue; + if (gld${EMULATION_NAME}_search_needed (command_line.rpath, l->name)) + continue; + 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)) + continue; + } +EOF +if [ "x${host}" = "x${target}" ] ; then +cat >>e${EMULATION_NAME}.c <name)) + continue; +EOF +fi +cat >>e${EMULATION_NAME}.c <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)) + break; + free (filename); + } + if (search != NULL) + continue; +EOF +if [ "x${host}" = "x${target}" ] ; then +cat >>e${EMULATION_NAME}.c <name)) + continue; +EOF +fi +cat >>e${EMULATION_NAME}.c <name, l->by); + } +} + +/* Search for a needed file in a path. */ + +static boolean +gld${EMULATION_NAME}_search_needed (path, name) + const char *path; + const char *name; +{ + const char *s; + size_t len; + + if (path == NULL || *path == '\0') + return false; + len = strlen (name); + while (1) + { + char *filename, *sset; + + s = strchr (path, ':'); + if (s == NULL) + s = path + strlen (path); + + 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); + + if (gld${EMULATION_NAME}_try_needed (filename)) + return true; + + free (filename); + + if (*s == '\0') + break; + path = s + 1; + } + + return false; +} + +/* This function is called for each possible name for a dynamic object + named by a DT_NEEDED entry. */ + +static boolean +gld${EMULATION_NAME}_try_needed (name) + const char *name; +{ + bfd *abfd; + + 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; + } + + /* 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); + + return true; +} + +/* See if an input file matches a DT_NEEDED entry by name. */ + +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) + { + global_found = true; + return; + } + + if (s->the_bfd != NULL) + { + const char *soname; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname != NULL + && strcmp (soname, global_needed->name) == 0) + { + global_found = true; + return; + } + } + + if (s->search_dirs_flag + && s->filename != NULL + && strchr (global_needed->name, '/') == NULL) + { + const char *f; + + f = strrchr (s->filename, '/'); + if (f != NULL + && strcmp (f + 1, global_needed->name) == 0) + { + global_found = true; + return; + } + } +} + +/* See if an input file matches a DT_NEEDED entry by running stat on + the file. */ + +static void +gld${EMULATION_NAME}_stat_needed (s) + lang_input_statement_type *s; +{ + struct stat st; + const char *suffix; + const char *soname; + const char *f; + + if (global_found) + return; + if (s->the_bfd == NULL) + return; + + if (bfd_stat (s->the_bfd, &st) != 0) + { + einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); + return; + } + + if (st.st_dev == global_stat.st_dev + && st.st_ino == global_stat.st_ino) + { + global_found = true; + return; + } + + /* 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); +} + /* This is called after the sections have been attached to output sections, but before any sizes or addresses have been set. */ 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 @@ -122,9 +545,12 @@ gld${EMULATION_NAME}_before_allocation () /* 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_elf32_size_dynamic_sections (output_bfd, command_line.soname, - command_line.rpath, + rpath, command_line.export_dynamic, &link_info, &sinterp)) @@ -164,7 +590,10 @@ gld${EMULATION_NAME}_before_allocation () 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); + ret = link_info.callbacks->warning (&link_info, msg, + (const char *) NULL, + is->the_bfd, (asection *) NULL, + (bfd_vma) 0); ASSERT (ret); free (msg); @@ -173,6 +602,37 @@ gld${EMULATION_NAME}_before_allocation () s->_raw_size = 0; } } + +#if defined (TARGET_IS_elf32bmip) || defined (TARGET_IS_elf32lmip) + /* For MIPS ELF the .reginfo section requires special handling. + Each input section is 24 bytes, and the final output section must + also be 24 bytes. We handle this by clobbering all but the first + input section size to 0. The .reginfo section is handled + specially by the backend code anyhow. */ + { + boolean found = false; + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *s; + + if (is->just_syms_flag) + continue; + + s = bfd_get_section_by_name (is->the_bfd, ".reginfo"); + if (s == NULL) + continue; + + if (! found) + { + found = true; + continue; + } + + s->_raw_size = 0; + s->_cooked_size = 0; + } + } +#endif } /* This is called by the before_allocation routine via @@ -194,13 +654,31 @@ static void gld${EMULATION_NAME}_find_exp_assignment (exp) etree_type *exp; { + struct bfd_link_hash_entry *h; + 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_elf32_record_link_assignment (output_bfd, &link_info, - exp->assign.dst)) + if (! (bfd_elf32_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); } @@ -213,7 +691,7 @@ gld${EMULATION_NAME}_find_exp_assignment (exp) break; case etree_trinary: - gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + 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); break; @@ -235,6 +713,7 @@ static lang_output_section_statement_type *hold_use; static lang_output_section_statement_type *hold_text; static lang_output_section_statement_type *hold_data; static lang_output_section_statement_type *hold_bss; +static lang_output_section_statement_type *hold_rel; /*ARGSUSED*/ static boolean @@ -265,8 +744,21 @@ gld${EMULATION_NAME}_place_orphan (file, s) 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 flags. */ + section name and section flags. */ place = NULL; if ((s->flags & SEC_HAS_CONTENTS) == 0 && hold_bss != NULL) @@ -274,37 +766,29 @@ gld${EMULATION_NAME}_place_orphan (file, s) 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_READONLY) != 0 && hold_text != NULL) place = hold_text; if (place == NULL) return false; - secname = bfd_get_section_name (s->owner, s); - - /* When generating an object which is to be dynamically linked, we - do not support orphaned reloc sections. This is because all the - reloc sections must be contiguous in order to generate correct - DT_REL entries. When this case arises, you can just add the - appropriate reloc sections to the linker script. Note that the - .rel.plt section must always be the last reloc section. FIXME: - This should simply be handled correctly here. */ - ASSERT (strncmp (secname, ".rel", 4) != 0 - || bfd_get_section_by_name (output_bfd, ".dynamic") == NULL); - /* Create the section in the output file, and put it in the right - place. This shuffling to make the output file look neater, and - also means that the BFD backend does not have to sort the - sections in order by address. */ + place. This shuffling is to make the output file look neater. */ snew = bfd_make_section (output_bfd, secname); if (snew == NULL) einfo ("%P%F: output format %s cannot represent section called %s\n", output_bfd->xvec->name, secname); - for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) - ; - *pps = snew->next; - snew->next = place->bfd_section->next; - place->bfd_section->next = snew; + if (place->bfd_section != NULL) + { + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + ; + *pps = snew->next; + snew->next = place->bfd_section->next; + place->bfd_section->next = snew; + } /* Start building a list of statements for this section. */ old = stat_ptr; @@ -382,6 +866,9 @@ gld${EMULATION_NAME}_place_section (s) hold_data = os; else if (strcmp (os->name, ".bss") == 0) hold_bss = os; + else if (hold_rel == NULL + && strncmp (os->name, ".rel", 4) == 0) + hold_rel = os; } static char * @@ -451,7 +938,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = syslib_default, hll_default, after_parse_default, - after_open_default, + gld${EMULATION_NAME}_after_open, after_allocation_default, set_output_arch_default, ldemul_default_target,