* emultempl/sunos.em (gld${EMULATION_NAME}_find_so): Move

directory searching code into gld${EMULATION_NAME}_search_dir.
	(gld${EMULATION_NAME}_search_dir): New static function, extracted
	from gld${EMULATION_NAME}_find_so.
	(global_needed, global_found): New static variables.
	(gld${EMULATION_NAME}_after_open): New static function.
	(gld${EMULATION_NAME}_search_needed): New static function.
	(gld${EMULATION_NAME}_try_needed): New static function.
	(gld${EMULATION_NAME}_check_needed): New static function.
	(ld_${EMULATION_NAME}_emulation): Use new after_open function.
	* ld.texinfo, ld.1: Mention -rpath-link on SunOS.
This commit is contained in:
Ian Lance Taylor 1995-10-17 22:36:25 +00:00
parent 11fa66365b
commit 235c6a672f
3 changed files with 517 additions and 126 deletions

View File

@ -1,5 +1,17 @@
Tue Oct 17 12:22:05 1995 Ian Lance Taylor <ian@cygnus.com>
* emultempl/sunos.em (gld${EMULATION_NAME}_find_so): Move
directory searching code into gld${EMULATION_NAME}_search_dir.
(gld${EMULATION_NAME}_search_dir): New static function, extracted
from gld${EMULATION_NAME}_find_so.
(global_needed, global_found): New static variables.
(gld${EMULATION_NAME}_after_open): New static function.
(gld${EMULATION_NAME}_search_needed): New static function.
(gld${EMULATION_NAME}_try_needed): New static function.
(gld${EMULATION_NAME}_check_needed): New static function.
(ld_${EMULATION_NAME}_emulation): Use new after_open function.
* ld.texinfo, ld.1: Mention -rpath-link on SunOS.
* Makefile.in (eelf32ppc.c): Depend upon elf32.em, not generic.em.
(eelf32lppc.c): Likewise.
* emulparams/elf32lppc.sh (TEMPLATE_NAME): Define as elf32.

View File

@ -61,8 +61,17 @@ static void gld${EMULATION_NAME}_create_output_section_statements
PARAMS ((void));
static void gld${EMULATION_NAME}_find_so
PARAMS ((lang_input_statement_type *));
static char *gld${EMULATION_NAME}_search_dir
PARAMS ((const char *, const char *, boolean *));
static void gld${EMULATION_NAME}_after_open PARAMS ((void));
static void gld${EMULATION_NAME}_check_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 *, const char *));
static void gld${EMULATION_NAME}_before_allocation PARAMS ((void));
static void gld${EMULATION_NAME}_find_statement_assignment
static void gld${EMULATION_NAME}_find_assignment
PARAMS ((lang_statement_union_type *));
static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *));
static void gld${EMULATION_NAME}_count_need
@ -100,14 +109,8 @@ gld${EMULATION_NAME}_find_so (inp)
lang_input_statement_type *inp;
{
search_dirs_type *search;
const char *filename;
const char *dot;
int force_maj;
unsigned int len;
char *alc;
int max_maj, max_min;
char *found;
boolean found_static;
char *alc;
struct stat st;
if (! inp->search_dirs_flag
@ -117,85 +120,12 @@ gld${EMULATION_NAME}_find_so (inp)
ASSERT (strncmp (inp->local_sym_name, "-l", 2) == 0);
filename = inp->filename;
force_maj = -1;
dot = strchr (filename, '.');
if (dot == NULL)
len = strlen (filename);
else
{
force_maj = atoi (dot + 1);
len = dot - filename;
alc = (char *) xmalloc (len + 1);
strncpy (alc, filename, len);
alc[len] = '\0';
filename = alc;
}
found = NULL;
found_static = false;
max_maj = max_min = 0;
for (search = search_head; search != NULL; search = search->next)
{
DIR *dir;
struct dirent *entry;
dir = opendir (search->name);
if (dir == NULL)
continue;
while ((entry = readdir (dir)) != NULL)
{
int found_maj, found_min;
if (strncmp (entry->d_name, "lib", 3) != 0
|| strncmp (entry->d_name + 3, inp->filename, len) != 0)
continue;
if (dot == NULL
&& strncmp (entry->d_name + 3 + len, ".a", 2) == 0)
{
found_static = true;
continue;
}
if (strncmp (entry->d_name + 3 + len, ".so", 3) != 0)
continue;
/* We've found a .so file. Work out the major and minor
version numbers. */
found_maj = 0;
found_min = 0;
sscanf (entry->d_name + 3 + len, ".so.%d.%d",
&found_maj, &found_min);
if (force_maj != -1 && force_maj != found_maj)
continue;
/* We've found a match for the name we are searching for.
See if this is the version we should use. If the major
and minor versions match, we use the last entry in
alphabetical order; I don't know if this is how SunOS
distinguishes libc.so.1.8 from libc.so.1.8.1, but it
ought to suffice. */
if (found == NULL
|| (found_maj > max_maj)
|| (found_maj == max_maj
&& (found_min > max_min
|| (found_min == max_min
&& strcmp (entry->d_name, found) > 0))))
{
if (found != NULL)
free (found);
found = (char *) xmalloc (strlen (entry->d_name) + 1);
strcpy (found, entry->d_name);
max_maj = found_maj;
max_min = found_min;
}
}
closedir (dir);
boolean found_static;
found = gld${EMULATION_NAME}_search_dir (search->name, inp->filename,
&found_static);
if (found != NULL || found_static)
break;
}
@ -258,6 +188,398 @@ gld${EMULATION_NAME}_find_so (inp)
}
}
/* Search a directory for a .so file. */
static char *
gld${EMULATION_NAME}_search_dir (dirname, filename, found_static)
const char *dirname;
const char *filename;
boolean *found_static;
{
int force_maj, force_min;
const char *dot;
unsigned int len;
char *alc;
char *found;
int max_maj, max_min;
DIR *dir;
struct dirent *entry;
*found_static = false;
force_maj = -1;
force_min = -1;
dot = strchr (filename, '.');
if (dot == NULL)
{
len = strlen (filename);
alc = NULL;
}
else
{
force_maj = atoi (dot + 1);
len = dot - filename;
alc = (char *) xmalloc (len + 1);
strncpy (alc, filename, len);
alc[len] = '\0';
filename = alc;
dot = strchr (dot + 1, '.');
if (dot != NULL)
force_min = atoi (dot + 1);
}
found = NULL;
max_maj = max_min = 0;
dir = opendir (dirname);
if (dir == NULL)
return NULL;
while ((entry = readdir (dir)) != NULL)
{
int found_maj, found_min;
if (strncmp (entry->d_name, "lib", 3) != 0
|| strncmp (entry->d_name + 3, filename, len) != 0)
continue;
if (dot == NULL
&& strcmp (entry->d_name + 3 + len, ".a") == 0)
{
*found_static = true;
continue;
}
if (strncmp (entry->d_name + 3 + len, ".so", 3) != 0)
continue;
/* We've found a .so file. Work out the major and minor
version numbers. */
found_maj = 0;
found_min = 0;
sscanf (entry->d_name + 3 + len, ".so.%d.%d",
&found_maj, &found_min);
if ((force_maj != -1 && force_maj != found_maj)
|| (force_min != -1 && force_min != found_min))
continue;
/* We've found a match for the name we are searching for. See
if this is the version we should use. If the major and minor
versions match, we use the last entry in alphabetical order;
I don't know if this is how SunOS distinguishes libc.so.1.8
from libc.so.1.8.1, but it ought to suffice. */
if (found == NULL
|| (found_maj > max_maj)
|| (found_maj == max_maj
&& (found_min > max_min
|| (found_min == max_min
&& strcmp (entry->d_name, found) > 0))))
{
if (found != NULL)
free (found);
found = (char *) xmalloc (strlen (entry->d_name) + 1);
strcpy (found, entry->d_name);
max_maj = found_maj;
max_min = found_min;
}
}
closedir (dir);
if (alc != NULL)
free (alc);
return found;
}
/* These variables are required to pass information back and forth
between after_open and check_needed. */
static struct bfd_link_needed_list *global_needed;
static boolean global_found;
/* This is called after all the input files have been opened. */
static void
gld${EMULATION_NAME}_after_open ()
{
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 ld_need entries in dynamic
objects included in the link. 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_sunos_get_needed_list (output_bfd, &link_info);
for (l = needed; l != NULL; l = l->next)
{
struct bfd_link_needed_list *ll;
const char *lname;
const char *lib_path;
search_dirs_type *search;
lname = l->name;
/* If we've already seen this file, skip it. */
for (ll = needed; ll != l; ll = ll->next)
if (strcmp (ll->name, lname) == 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;
if (strncmp (lname, "-l", 2) != 0)
{
bfd *abfd;
abfd = bfd_openr (lname, bfd_get_target (output_bfd));
if (abfd != NULL)
{
if (! bfd_check_format (abfd, bfd_object))
{
(void) bfd_close (abfd);
abfd = NULL;
}
}
if (abfd != NULL)
{
if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
{
(void) bfd_close (abfd);
abfd = NULL;
}
}
if (abfd != NULL)
{
/* We've found the needed dynamic object. */
if (! bfd_link_add_symbols (abfd, &link_info))
einfo ("%F%B: could not read symbols: %E\n", abfd);
}
else
{
einfo ("%P: warning: %s, needed by %B, not found\n",
lname, l->by);
}
continue;
}
lname += 2;
/* 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 or -L, then the environment variable
LD_LIBRARY_PATH (native only), then (if rpath was used) the
linker script LIB_SEARCH_DIRS. */
if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
lname))
continue;
if (command_line.rpath != NULL)
{
if (gld${EMULATION_NAME}_search_needed (command_line.rpath, lname))
continue;
}
else
{
for (search = search_head; search != NULL; search = search->next)
if (gld${EMULATION_NAME}_try_needed (search->name, lname))
break;
if (search != NULL)
continue;
}
EOF
if [ "x${host_alias}" = "x${target_alias}" ] ; then
cat >>e${EMULATION_NAME}.c <<EOF
lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
if (gld${EMULATION_NAME}_search_needed (lib_path, lname))
continue;
EOF
fi
cat >>e${EMULATION_NAME}.c <<EOF
if (command_line.rpath != NULL)
{
for (search = search_head; search != NULL; search = search->next)
{
if (search->cmdline)
continue;
if (gld${EMULATION_NAME}_try_needed (search->name, lname))
break;
}
if (search != NULL)
continue;
}
einfo ("%P: warning: %s, needed by %B, not found\n",
l->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;
if (path == NULL || *path == '\0')
return false;
while (1)
{
const char *dir;
char *dircopy;
s = strchr (path, ':');
if (s == NULL)
{
dircopy = NULL;
dir = path;
}
else
{
dircopy = (char *) xmalloc (s - path + 1);
memcpy (dircopy, path, s - path);
dircopy[s - path] = '\0';
dir = dircopy;
}
if (gld${EMULATION_NAME}_try_needed (dir, name))
return true;
if (dircopy != NULL)
free (dircopy);
if (s == NULL)
break;
path = s + 1;
}
return false;
}
/* This function is called for each possible directory for a needed
dynamic object. */
static boolean
gld${EMULATION_NAME}_try_needed (dir, name)
const char *dir;
const char *name;
{
char *file;
char *alc;
boolean ignore;
bfd *abfd;
file = gld${EMULATION_NAME}_search_dir (dir, name, &ignore);
if (file == NULL)
return false;
alc = (char *) xmalloc (strlen (dir) + strlen (file) + 2);
sprintf (alc, "%s/%s", dir, file);
free (file);
abfd = bfd_openr (alc, 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 the needed dynamic object. */
/* 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 we have already included a needed object in the link. This
does not have to be precise, as it does no harm to include a
dynamic object more than once. */
static void
gld${EMULATION_NAME}_check_needed (s)
lang_input_statement_type *s;
{
if (s->filename == NULL)
return;
if (strncmp (global_needed->name, "-l", 2) != 0)
{
if (strcmp (s->filename, global_needed->name) == 0)
global_found = true;
}
else
{
const char *sname, *lname;
const char *sdot, *ldot;
int lmaj, lmin, smaj, smin;
lname = global_needed->name + 2;
sname = strrchr (s->filename, '/');
if (sname == NULL)
sname = s->filename;
else
++sname;
if (strncmp (sname, "lib", 3) != 0)
return;
sname += 3;
ldot = strchr (lname, '.');
if (ldot == NULL)
ldot = lname + strlen (lname);
sdot = strstr (sname, ".so.");
if (sdot == NULL)
return;
if (sdot - sname != ldot - lname
|| strncmp (lname, sname, sdot - sname) != 0)
return;
lmaj = lmin = -1;
sscanf (ldot, ".%d.%d", &lmaj, &lmin);
smaj = smin = -1;
sscanf (sdot, ".so.%d.%d", &smaj, &smin);
if ((smaj != lmaj && smaj != -1 && lmaj != -1)
|| (smin != lmin && smin != -1 && lmin != -1))
return;
global_found = true;
}
}
/* We need to use static variables to pass information around the call
to lang_for_each_statement. Ick. */
static const char *find_assign;
static boolean found_assign;
/* We need to use static variables to pass information around the call
to lang_for_each_input_file. Ick. */
@ -278,11 +600,48 @@ static bfd_byte *need_pnames;
static void
gld${EMULATION_NAME}_before_allocation ()
{
struct bfd_link_hash_entry *h = NULL;
struct bfd_link_hash_entry *hdyn = NULL;
asection *sneed;
asection *srules;
asection *sdyn;
/* The SunOS native linker creates a shared library whenever there
are any undefined symbols in a link, unless -e is used. This is
pretty weird, but we are compatible. */
if (! link_info.shared && ! link_info.relocateable && ! entry_from_cmdline)
{
struct bfd_link_hash_entry *h;
for (h = link_info.hash->undefs; h != NULL; h = h->next)
{
if (h->type == bfd_link_hash_undefined
&& h->u.undef.abfd != NULL
&& (h->u.undef.abfd->flags & DYNAMIC) == 0
&& strcmp (h->root.string, "__DYNAMIC") != 0)
{
find_assign = h->root.string;
found_assign = false;
lang_for_each_statement (gld${EMULATION_NAME}_find_assignment);
if (! found_assign)
{
link_info.shared = true;
break;
}
}
}
}
if (link_info.shared)
{
lang_output_section_statement_type *os;
/* Set the .text section to start at 0x20, not 0x2020. FIXME:
This is too magical. */
os = lang_output_section_statement_lookup (".text");
if (os->addr_tree == NULL)
os->addr_tree = exp_intop (0x20);
}
/* We need to create a __DYNAMIC symbol. We don't do this in the
linker script because we want to set the value to the start of
the dynamic section if there is one, or to zero if there isn't
@ -291,9 +650,9 @@ gld${EMULATION_NAME}_before_allocation ()
afterward. */
if (! link_info.relocateable)
{
h = bfd_link_hash_lookup (link_info.hash, "__DYNAMIC", true, false,
false);
if (h == NULL)
hdyn = bfd_link_hash_lookup (link_info.hash, "__DYNAMIC", true, false,
false);
if (hdyn == NULL)
einfo ("%P%F: bfd_link_hash_lookup: %E\n");
if (! bfd_sunos_record_link_assignment (output_bfd, &link_info,
"__DYNAMIC"))
@ -303,7 +662,7 @@ gld${EMULATION_NAME}_before_allocation ()
/* If we are going to make any variable assignments, we need to let
the backend linker know about them in case the variables are
referred to by dynamic objects. */
lang_for_each_statement (gld${EMULATION_NAME}_find_statement_assignment);
lang_for_each_statement (gld${EMULATION_NAME}_find_assignment);
/* Let the backend linker work out the sizes of any sections
required by dynamic linking. */
@ -339,31 +698,41 @@ gld${EMULATION_NAME}_before_allocation ()
if (srules != NULL)
{
unsigned int size;
search_dirs_type *search;
/* Set up the .rules section. This is just a PATH like string
of the -L arguments given on the command line. */
size = 0;
for (search = search_head; search != NULL; search = search->next)
if (search->cmdline)
size += strlen (search->name) + 1;
srules->_raw_size = size;
if (size > 0)
of the -L arguments given on the command line. We permit the
user to specify the directories using the -rpath command line
option. */
if (command_line.rpath)
{
char *p;
srules->_raw_size = strlen (command_line.rpath);
srules->contents = (bfd_byte *) command_line.rpath;
}
else
{
unsigned int size;
search_dirs_type *search;
srules->contents = (bfd_byte *) xmalloc (size);
p = (char *) srules->contents;
*p = '\0';
size = 0;
for (search = search_head; search != NULL; search = search->next)
if (search->cmdline)
size += strlen (search->name) + 1;
srules->_raw_size = size;
if (size > 0)
{
if (search->cmdline)
char *p;
srules->contents = (bfd_byte *) xmalloc (size);
p = (char *) srules->contents;
*p = '\0';
for (search = search_head; search != NULL; search = search->next)
{
if (p != (char *) srules->contents)
*p++ = ':';
strcpy (p, search->name);
p += strlen (p);
if (search->cmdline)
{
if (p != (char *) srules->contents)
*p++ = ':';
strcpy (p, search->name);
p += strlen (p);
}
}
}
}
@ -374,25 +743,28 @@ gld${EMULATION_NAME}_before_allocation ()
we are doing one. */
if (! link_info.relocateable)
{
h->type = bfd_link_hash_defined;
h->u.def.value = 0;
hdyn->type = bfd_link_hash_defined;
hdyn->u.def.value = 0;
if (sdyn != NULL)
h->u.def.section = sdyn;
hdyn->u.def.section = sdyn;
else
h->u.def.section = bfd_abs_section_ptr;
hdyn->u.def.section = bfd_abs_section_ptr;
}
}
/* This is called by the before_allocation routine via
lang_for_each_statement. It locates any assignment statements, and
tells the backend linker about them, in case they are assignments
to symbols which are referred to by dynamic objects. */
lang_for_each_statement. It does one of two things: if the
variable find_assign is set, it sets found_assign if it finds an
assignment to that variable; otherwise it tells the backend linker
about all assignment statements, in case they are assignments to
symbols which are referred to by dynamic objects. */
static void
gld${EMULATION_NAME}_find_statement_assignment (s)
gld${EMULATION_NAME}_find_assignment (s)
lang_statement_union_type *s;
{
if (s->header.type == lang_assignment_statement_enum)
if (s->header.type == lang_assignment_statement_enum
&& (find_assign == NULL || ! found_assign))
gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp);
}
@ -405,6 +777,13 @@ gld${EMULATION_NAME}_find_exp_assignment (exp)
switch (exp->type.node_class)
{
case etree_assign:
if (find_assign != NULL)
{
if (strcmp (find_assign, exp->assign.dst) == 0)
found_assign = true;
return;
}
if (strcmp (exp->assign.dst, ".") != 0)
{
if (! bfd_sunos_record_link_assignment (output_bfd, &link_info,
@ -540,8 +919,6 @@ cat >>e${EMULATION_NAME}.c <<EOF
return `sed "$sc" ldscripts/${EMULATION_NAME}.xbn`;
else if (!config.magic_demand_paged)
return `sed "$sc" ldscripts/${EMULATION_NAME}.xn`;
else if (link_info.shared)
return `sed "$sc" ldscripts/${EMULATION_NAME}.xs`;
else
return `sed "$sc" ldscripts/${EMULATION_NAME}.x`;
}
@ -562,8 +939,6 @@ cat >>e${EMULATION_NAME}.c <<EOF
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";
}
@ -579,7 +954,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,

12
ld/ld.1
View File

@ -729,8 +729,8 @@ options which may be on NFS mounted filesystems.
.TP
.B \-rpath\-link\ \fIdirectory
When using ELF, one shared library may require another. This happens
when an
When using ELF or SunOS, one shared library may require another. This
happens when an
.B ld\ \-shared
link includes a shared library as one of the input files.
@ -757,8 +757,12 @@ Omits all symbol information from the output file.
.TP
.B \-shared
Create a shared library. This is currently only supported on ELF
platforms.
Create a shared library. This is currently only supported on ELF and
SunOS platforms (on SunOS it is not required, as the linker will
automatically create a shared library when there are undefined symbols
and the
.B \-e
option is not used).
.TP
.B \-sort\-common