summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/binutils/ld/emultempl
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2000-10-20 12:25:21 +0000
committerMarc Espie <espie@cvs.openbsd.org>2000-10-20 12:25:21 +0000
commit805ccd92b3b85dddd509fc07950b118368d38e0c (patch)
tree378944978c64aedc717de91cf4b7dad7d3eabc1a /gnu/usr.bin/binutils/ld/emultempl
parentf932f29c05da31be7462b924a875114c1889eb30 (diff)
Add support for major/minor version numbers.
Testing by Dale. Ok'd deraadt@
Diffstat (limited to 'gnu/usr.bin/binutils/ld/emultempl')
-rw-r--r--gnu/usr.bin/binutils/ld/emultempl/elf32.em162
1 files changed, 162 insertions, 0 deletions
diff --git a/gnu/usr.bin/binutils/ld/emultempl/elf32.em b/gnu/usr.bin/binutils/ld/emultempl/elf32.em
index 2913ecf1bcb..d629d9a245b 100644
--- a/gnu/usr.bin/binutils/ld/emultempl/elf32.em
+++ b/gnu/usr.bin/binutils/ld/emultempl/elf32.em
@@ -69,6 +69,155 @@ static void gld${EMULATION_NAME}_place_section
PARAMS ((lang_statement_union_type *));
static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile));
+EOF
+case ${target} in
+ *-*-openbsd*)
+ cat >>e${EMULATION_NAME}.c <<EOF
+#include <sys/types.h>
+#include <dirent.h>
+
+/* Search a directory for a .so file. */
+
+static char *
+gld${EMULATION_NAME}_search_dir (dirname, filename)
+ const char *dirname;
+ const char *filename;
+{
+ 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;
+ unsigned int dirnamelen;
+ char *full_path;
+ int statval;
+ struct stat st;
+
+ 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;
+ dirnamelen = strlen (dirname);
+
+ while ((entry = readdir (dir)) != NULL)
+ {
+ const char *s;
+ char *eptr, *eptr1;
+ int found_maj, found_min;
+
+ if (strncmp (entry->d_name, "lib", 3) != 0
+ || strncmp (entry->d_name + 3, filename, len) != 0)
+ continue;
+
+ /* We accept libfoo.so without a version number, even though the
+ native linker does not. This is more convenient for packages
+ which just generate .so files for shared libraries, as on ELF
+ systems. */
+ if (strncmp (entry->d_name + 3 + len, ".so", 3) != 0)
+ continue;
+
+ if (entry->d_name[6 + len] == '\0')
+ ;
+ else if (entry->d_name[6 + len] == '.'
+ && isdigit ((unsigned char) entry->d_name[7 + len]))
+ ;
+ else
+ continue;
+
+ for (s = entry->d_name + 6 + len; *s != '\0'; s++)
+ if (*s != '.' && ! isdigit ((unsigned char) *s))
+ break;
+ if (*s != '\0')
+ continue;
+
+ /* We've found a .so file. Work out the major and minor
+ version numbers. */
+ found_maj = -1;
+ found_min = -1;
+
+ /* do allow libN.so */
+ if (entry->d_name[6 + len] == '.') {
+ found_maj = strtoul (entry->d_name + 7 + len, &eptr, 10);
+
+ /* do not support libN.so. or libN.so.X */
+ if (*eptr != '.' || ((entry->d_name + 3 + len) == eptr))
+ continue;
+
+ found_min = strtoul (eptr+1, &eptr1, 10);
+
+ /* do not support libN.so.X. or libN.so.X.Y.[anything] */
+ if (*eptr1 != '\0' || (eptr+1 == eptr1))
+ continue;
+ }
+
+ if ((force_maj != -1 && force_maj != found_maj)
+ || (force_min != -1 && force_min != found_min))
+ continue;
+
+ /* Make sure the file really exists (ignore broken symlinks). */
+ full_path = xmalloc (dirnamelen + 1 + strlen (entry->d_name) + 1);
+ sprintf (full_path, "%s/%s", dirname, entry->d_name);
+ statval = stat (full_path, &st);
+ free (full_path);
+ if (statval != 0)
+ continue;
+
+ /* We've found a match for the name we are searching for. See
+ if this is the version we should use. */
+ if (found == NULL
+ || (found_maj > max_maj)
+ || (found_maj == max_maj
+ && (found_min > max_min)))
+ {
+ if (found != NULL)
+ free (found);
+ found = (char *) xmalloc (dirnamelen + strlen (entry->d_name) + 2);
+ sprintf (found, "%s/%s", dirname, entry->d_name);
+ max_maj = found_maj;
+ max_min = found_min;
+ }
+ }
+
+ closedir (dir);
+
+ if (alc != NULL)
+ free (alc);
+
+ return found;
+}
+
+EOF
+ ;;
+esac
+cat >>e${EMULATION_NAME}.c <<EOF
static void
gld${EMULATION_NAME}_before_parse()
{
@@ -95,6 +244,15 @@ gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
filename = entry->filename;
+EOF
+case ${target} in
+ *-*-openbsd*)
+ cat >>e${EMULATION_NAME}.c <<EOF
+ string = gld${EMULATION_NAME}_search_dir(search->name, filename);
+EOF
+ ;;
+ *)
+ cat >>e${EMULATION_NAME}.c <<EOF
/* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
is defined, but it does not seem worth the headache to optimize
away those two bytes of space. */
@@ -108,6 +266,10 @@ gld${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);
+EOF
+ ;;
+esac
+cat >>e${EMULATION_NAME}.c <<EOF
#ifdef EXTRA_SHLIB_EXTENSION
/* Try the .so extension first. If that fails build a new filename
using EXTRA_SHLIB_EXTENSION. */