/* This file is is generated by a shell script. DO NOT EDIT! */
/* 32 bit ELF emulation code for ${EMULATION_NAME}
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 93, 94, 95, 1996 Free Software Foundation, Inc.
Written by Steve Chamberlain <sac@cygnus.com>
ELF support by Ian Lance Taylor <ian@cygnus.com>
#include "ldlang.h"
#include "ldgram.h"
-#ifdef TARGET_IS_i386lelf
-#ifdef HAVE_DIRENT_H
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-# include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-# include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-# include <ndir.h>
-# endif
-#endif
-#endif
-
static void gld${EMULATION_NAME}_before_parse PARAMS ((void));
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 *));
static boolean gld${EMULATION_NAME}_try_needed PARAMS ((const char *));
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};
}
-#ifndef TARGET_IS_i386lelf
-
/* Try to open a dynamic archive. This is where we know that ELF
dynamic libraries have an extension of .so. */
return true;
}
-#else /* TARGET_IS_i386lelf */
-
-/* Linux deviates from the SVR4 standard in that its archives use
- version numbers in the file name. I think this is bogus, but
- H.J. Lu insists that it be done this way. */
-
-static int libcmp PARAMS ((const char *, const char *));
-
-/* Choose between two library names. This is like a string
- comparison, except that numbers are compared by value. */
-
-static int
-libcmp (p1, p2)
- const char *p1;
- const char *p2;
-{
- while (*p1 != '\0')
- {
- if (isdigit (*p1) && isdigit (*p2))
- {
- unsigned long v1, v2;
-
- v1 = strtoul (p1, (char **) &p1, 10);
- v2 = strtoul (p2, (char **) &p2, 10);
- if (v1 < v2)
- return -1;
- else if (v1 > v2)
- return 1;
- }
- else if (*p1 < *p2)
- return -1;
- else if (*p1 > *p2)
- return 1;
- else
- {
- ++p1;
- ++p2;
- }
- }
-
- if (*p2 != '\0')
- return -1;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+cat >>e${EMULATION_NAME}.c <<EOF
- return 0;
-}
+/* 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. */
-/* Search for the library to open. */
+static boolean gld${EMULATION_NAME}_check_ld_so_conf PARAMS ((const char *));
-/*ARGSUSED*/
static boolean
-gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
- const char *arch;
- search_dirs_type *search;
- lang_input_statement_type *entry;
+gld${EMULATION_NAME}_check_ld_so_conf (name)
+ const char *name;
{
- size_t len;
- char *found;
- DIR *dir;
- struct dirent *ent;
- char *string;
-
- len = strlen (entry->filename);
+ static boolean initialized;
+ static char *ld_so_conf;
- found = NULL;
-
- dir = opendir (search->name);
- if (dir == NULL)
- return false;
-
- while ((ent = readdir (dir)) != NULL)
+ if (! initialized)
{
- if (strncmp (ent->d_name, "lib", 3) != 0
- || strncmp (ent->d_name + 3, entry->filename, len) != 0
- || strncmp (ent->d_name + len + 3, ".so", 3) != 0)
- continue;
+ FILE *f;
- if (found != NULL)
+ f = fopen ("/etc/ld.so.conf", FOPEN_RT);
+ if (f != NULL)
{
- if (libcmp (ent->d_name + len + 6, found + len + 6) < 0)
- continue;
- free (found);
+ char *b;
+ size_t len, alloc;
+ int c;
+
+ len = 0;
+ alloc = 100;
+ b = (char *) xmalloc (alloc);
+
+ 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;
+ }
+ }
+ }
+
+ if (len > 0 && b[len - 1] == ':')
+ --len;
+
+ if (len > 0)
+ b[len] = '\0';
+ else
+ {
+ free (b);
+ b = NULL;
+ }
+
+ fclose (f);
+
+ ld_so_conf = b;
}
- found = (char *) xmalloc (strlen (ent->d_name) + 1);
- strcpy (found, ent->d_name);
+ initialized = true;
}
- closedir (dir);
-
- if (found == NULL)
+ if (ld_so_conf == NULL)
return false;
- string = (char *) xmalloc (strlen (search->name) + strlen (found) + 2);
- sprintf (string, "%s/%s", search->name, found);
- if (! ldfile_try_open_bfd (string, entry))
- {
- free (found);
- return false;
- }
-
- entry->filename = string;
-
- if (bfd_check_format (entry->the_bfd, bfd_object)
- && (entry->the_bfd->flags & DYNAMIC) != 0)
- {
- ASSERT (entry->is_archive && entry->search_dirs_flag);
- bfd_elf_set_dt_needed_name (entry->the_bfd, found);
- }
-
- return true;
-
+ return gld${EMULATION_NAME}_search_needed (ld_so_conf, name);
}
-#endif /* TARGET_IS_i386lelf */
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
/* These variables are required to pass information back and forth
- between after_open and check_needed. */
+ between after_open and check_needed and stat_needed. */
-static struct bfd_elf_link_needed_list *global_needed;
+static struct bfd_link_needed_list *global_needed;
+static struct stat global_stat;
static boolean global_found;
/* This is called after all the input files have been opened. */
static void
gld${EMULATION_NAME}_after_open ()
{
- struct bfd_elf_link_needed_list *needed, *l;
+ struct bfd_link_needed_list *needed, *l;
+
+ /* 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).
needed = bfd_elf_get_needed_list (output_bfd, &link_info);
for (l = needed; l != NULL; l = l->next)
{
- struct bfd_elf_link_needed_list *ll;
+ struct bfd_link_needed_list *ll;
const char *lib_path;
size_t len;
search_dirs_type *search;
/* 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,
- then the environment variable LD_LIBRARY_PATH, then the
- linker script LIB_SEARCH_DIRS. We do not search using the -L
- arguments. */
+ 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 <<EOF
lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
if (gld${EMULATION_NAME}_search_needed (lib_path, l->name))
continue;
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
len = strlen (l->name);
for (search = search_head; search != NULL; search = search->next)
{
}
if (search != NULL)
continue;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+cat >>e${EMULATION_NAME}.c <<EOF
+ if (gld${EMULATION_NAME}_check_ld_so_conf (l->name))
+ continue;
+EOF
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
einfo ("%P: warning: %s, needed by %B, not found\n",
l->name, l->by);
/* 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, "");
return true;
}
-/* See if an input file matches a DT_NEEDED entry. */
+/* 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;
- else if (s->search_dirs_flag
- && s->filename != NULL
- && strchr (global_needed->name, '/') == NULL)
+ {
+ 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;
+ {
+ 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
/* 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))
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, is->the_bfd,
- (asection *) NULL, (bfd_vma) 0);
+ ret = link_info.callbacks->warning (&link_info, msg,
+ (const char *) NULL,
+ is->the_bfd, (asection *) NULL,
+ (bfd_vma) 0);
ASSERT (ret);
free (msg);
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;