This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Use .note.ABI-tag in DSOs (take 2)


On Mon, Mar 05, 2001 at 11:30:40AM -0800, H . J . Lu wrote:
> On Mon, Mar 05, 2001 at 07:33:13PM +0100, Jakub Jelinek wrote:
> > Hi!
> > 
> > The following patch adds .note.ABI-tag to glibc DSOs, and disallows loading
> > DSOs which are built for newer kernels than installed. The --enable-kernel
> 
> I haven't looked at your patch. I built my glibc against the 2.4 kernel
> headers. But I am running 2.2 kernel. It won't be a problem unless
> glibc uses some features in the new kernel which has no fallback in
> the old kernel.

Yes, if you don't use --enable-kernel 2.4.0 or later, you can run glibc
built against 2.4 headers on 2.2 kernel, the thing which the patch does is
allowing multiple libraries built with various --enable-kernel settings to
coexist on the same system and keep searching for other libraries if dynamic
linker found a library it cannot use.

> One of them is the thread register.

The %gs based threading is actually the most important reason why people
want a --enable-kernel 2.4.0+ libc, but then temporarily booting to 2.2
kernel is impossible.

> How do you test those features? I don't think checking kernel version is a good idea.

ld.so already checks kernel version even without this patch, the difference
is that without this patch there is just one check when ld.so starts up,
while this patch checks each library as it is being loaded.

Below is an updated version, which supports LD_ASSUME_KERNEL environment
override so one can force using libraries supporting kernels older than the
one currently running, plus with one Makerules fix and one ldconfig bug
which were present in the last patch.

2001-03-12  Jakub Jelinek  <jakub@redhat.com>

	* csu/Makefile (abi-tag.h): Define OS and version separately, allow
	version to be overriden from config.h.
	* csu/abi-note.S: Use OS and version separately, include config.h.
	* elf/dl-load.c (_dl_osversion): New.
	(_dl_map_object_from_fd): Kill some warnings.
	(open_verify): Check .note.ABI-tag of the library if present.
	* elf/Makefile (CPPFLAGS-dl-load.c): Add -I$(csu-objpfx).
	* elf/cache.c (struct cache_entry): Add osversion.
	(print_entry): Print osversion.
	(print_cache): Pass osversion to it.
	(compare): Sort according to osversion.
	(save_cache): Set osversion.
	(add_to_cache): Add osversion argument.
	* sysdeps/generic/ldconfig.h (add_to_cache, process_file,
	process_elf_file): Add osversion argument.
	* elf/readlib.c (process_file): Likewise.
	* sysdeps/generic/readelflib.c (process_elf_file): Likewise.
	* sysdeps/unix/sysv/linux/ia64/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* sysdeps/unix/sysv/linux/i386/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* sysdeps/unix/sysv/linux/sparc/readelflib.c (process_elf_file,
	process_elf32_file, process_elf64_file): Likewise.
	* elf/ldconfig.c (manual_link): Pass it.
	(search_dir): Issue diagnostic if two libs with the same soname in
	the same directory have different .note.ABI-tag. Record osversion in
	dlib_entry and use it from there.
	(struct lib_entry): Remove.
	(struct dlib_entry): Add osversion.
	* sysdeps/generic/dl-cache.c (_dl_load_cache_lookup): Check
	osversion.
	* sysdeps/generic/ldsodefs.h (_dl_osversion): Declare.
	* sysdeps/unix/sysv/linux/init-first.c: Include ldsodefs.h.
	* sysdeps/unix/sysv/linux/dl-osinfo.h (DL_SYSDEP_OSCHECK): Save kernel
	version in _dl_osversion.
	* sysdeps/unix/sysv/linux/configure.in: Define __ABI_TAG_VERSION.
	* sysdeps/unix/sysv/linux/configure: Rebuilt.
	* Makerules (build-shlib-helper, build-module-helper): New.
	(build-shlib, build-module-helper): Make sure .note.ABI-tag comes
	early.
	* config.h.in (__ABI_TAG_VERSION): Add.
	* elf/dl-minimal.c (__strtoul_internal): Set endptr on return.
	* sysdeps/unix/sysv/linux/i386/dl-librecon.h (EXTRA_LD_ENVVARS):
	Handle LD_ASSUME_KERNEL.
	* sysdeps/unix/sysv/linux/dl-librecon.h: New.

--- libc/csu/Makefile.jj	Mon Mar 12 11:10:04 2001
+++ libc/csu/Makefile	Mon Mar 12 15:07:15 2001
@@ -168,12 +168,17 @@ $(objpfx)abi-tag.h: $(..)abi-tags
 	$(make-target-directory)
 	rm -f $@.new
 	sed -e 's/#.*$$//' -e '/^[	]*$$/d' $< | \
-	while read conf tag; do \
+	while read conf tagos tagver; do \
 	  test `expr '$(config-machine)-$(config-vendor)-$(config-os)' \
 		     : "$$conf"` != 0 || continue; \
-	  echo "$$tag" | \
-	  sed -e 's/[^0-9xXa-fA-F]/ /g' -e 's/ *$$//' \
-	      -e 's/ /,/g' -e 's/^ */#define ABI_TAG /' > $@.new; \
+	  ( echo "$$tagos" | \
+	    sed -e 's/[^0-9xXa-fA-F 	]//' \
+		-e 's/^/#define __ABI_TAG_OS /'; \
+	    echo "#ifndef __ABI_TAG_VERSION"; \
+	    echo "$$tagver" | \
+	    sed -e 's/[^0-9xXa-fA-F]/ /g' -e 's/ *$$//' \
+	      -e 's/ /,/g' -e 's/^/# define __ABI_TAG_VERSION /'; \
+	    echo "#endif" ) > $@.new; \
 	done
 	if test -r $@.new; then mv -f $@.new $@; \
 	else echo >&2 'This configuration not matched in $<'; exit 1; fi
--- libc/csu/abi-note.S.jj	Mon Mar 12 11:10:11 2001
+++ libc/csu/abi-note.S	Mon Mar 12 15:07:15 2001
@@ -1,5 +1,5 @@
 /* Special .init and .fini section support.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it
@@ -54,6 +54,7 @@ offset	length	contents	
    identify the earliest release of that OS that supports this ABI.
    See abi-tags (top level) for details. */
 
+#include <config.h>
 #include <abi-tag.h>		/* OS-specific ABI tag value */
 	
 /* The linker (GNU ld 2.8 and later) recognizes an allocated section whose
@@ -67,5 +68,6 @@ offset	length	contents	
 	.long  1		/* note type */
 0:	.asciz "GNU"		/* vendor name */
 1:	.align 4		
-2:	.long ABI_TAG		/* note data: the ABI tag */
+2:	.long __ABI_TAG_OS	/* note data: the ABI tag */
+	.long __ABI_TAG_VERSION
 3:	.align 4		/* pad out section */
--- libc/elf/Makefile.jj	Mon Mar 12 11:10:11 2001
+++ libc/elf/Makefile	Mon Mar 12 15:07:15 2001
@@ -188,7 +188,7 @@ $(objpfx)trusted-dirs.st: Makefile $(..)
 	| $(AWK) -f gen-trusted-dirs.awk > ${@:st=T};
 	$(move-if-change) ${@:st=T} ${@:st=h}
 	touch $@
-CPPFLAGS-dl-load.c = -I$(objpfx).
+CPPFLAGS-dl-load.c = -I$(objpfx). -I$(csu-objpfx).
 
 ifeq (yes,$(build-shared))
 $(inst_slibdir)/$(rtld-version-installed-name): $(objpfx)ld.so $(+force)
--- libc/elf/cache.c.jj	Mon Mar 12 11:10:11 2001
+++ libc/elf/cache.c	Mon Mar 12 15:07:15 2001
@@ -39,6 +39,7 @@ struct cache_entry
   char *lib;			/* Library name.  */
   char *path;			/* Path to find library.  */
   int flags;			/* Flags to indicate kind of library.  */
+  unsigned int osversion;	/* Required OS version.  */
   uint64_t hwcap;		/* Important hardware capabilities.  */
   int bits_hwcap;		/* Number of bits set in hwcap.  */
   struct cache_entry *next;	/* Next entry in list.  */
@@ -52,7 +53,8 @@ static const char *flag_descr[] =
 
 /* Print a single entry.  */
 static void
-print_entry (const char *lib, int flag, uint64_t hwcap, const char *key)
+print_entry (const char *lib, int flag, unsigned int osversion,
+	     uint64_t hwcap, const char *key)
 {
   printf ("\t%s (", lib);
   switch (flag & FLAG_TYPE_MASK)
@@ -85,6 +87,23 @@ print_entry (const char *lib, int flag, 
     }
   if (hwcap != 0)
     printf (", hwcap: 0x%" PRIx64, hwcap);
+  if (osversion != 0)
+    {
+      static const char * const abi_tag_os [] =
+      {
+	[0] = "Linux",
+	[1] = "Hurd",
+	[2] = "Solaris",
+	[3] = "Unknown OS"
+      };
+      unsigned int os = osversion >> 24;
+
+      printf (", OS ABI: %s %d.%d.%d",
+	      abi_tag_os [os > 3 ? 3 : os],
+	      (osversion >> 16) & 0xff,
+	      (osversion >> 8) & 0xff,
+	      osversion & 0xff);
+    }
   printf (") => %s\n", key);
 }
 
@@ -167,7 +186,7 @@ print_cache (const char *cache_name)
       /* Print everything.  */
       for (i = 0; i < cache->nlibs; i++)
 	print_entry (cache_data + cache->libs[i].key,
-		     cache->libs[i].flags, 0,
+		     cache->libs[i].flags, 0, 0,
 		     cache_data + cache->libs[i].value);
     }
   else if (format == 1)
@@ -178,6 +197,7 @@ print_cache (const char *cache_name)
       for (i = 0; i < cache_new->nlibs; i++)
 	print_entry (cache_data + cache_new->libs[i].key,
 		     cache_new->libs[i].flags,
+		     cache_new->libs[i].osversion,
 		     cache_new->libs[i].hwcap,
 		     cache_data + cache_new->libs[i].value);
     }
@@ -217,6 +237,10 @@ int compare (const struct cache_entry *e
 	return 1;
       else if (e2->hwcap < e1->hwcap)
 	return -1;
+      if (e2->osversion > e1->osversion)
+	return 1;
+      if (e2->osversion < e1->osversion)
+	return -1;
     }
   return res;
 }
@@ -319,9 +343,9 @@ save_cache (const char *cache_name)
 	     always begins at the beginning of the the new cache
 	     struct.  */
 	  file_entries_new->libs[idx_new].flags = entry->flags;
+	  file_entries_new->libs[idx_new].osversion = entry->osversion;
 	  file_entries_new->libs[idx_new].hwcap = entry->hwcap;
 	  file_entries_new->libs[idx_new].key = str_offset;
-	  file_entries_new->libs[idx_new].__unused = 0;
 	}
       len = strlen (entry->lib);
       str = stpcpy (str, entry->lib);
@@ -414,7 +438,7 @@ save_cache (const char *cache_name)
 /* Add one library to the cache.  */
 void
 add_to_cache (const char *path, const char *lib, int flags,
-	      uint64_t hwcap)
+	      unsigned int osversion, uint64_t hwcap)
 {
   struct cache_entry *new_entry, *ptr, *prev;
   char *full_path;
@@ -430,6 +454,7 @@ add_to_cache (const char *path, const ch
   new_entry->lib = xstrdup (lib);
   new_entry->path = full_path;
   new_entry->flags = flags;
+  new_entry->osversion = osversion;
   new_entry->hwcap = hwcap;
   new_entry->bits_hwcap = 0;
 
--- libc/elf/dl-load.c.jj	Mon Mar 12 11:10:12 2001
+++ libc/elf/dl-load.c	Mon Mar 12 15:07:15 2001
@@ -30,6 +30,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include "dynamic-link.h"
+#include <abi-tag.h>
+#include <dl-osinfo.h>
 
 #include <dl-dst.h>
 
@@ -111,6 +113,8 @@ struct filebuf
 
 size_t _dl_pagesize;
 
+unsigned int _dl_osversion;
+
 int _dl_clktck;
 
 extern const char *_dl_platform;
@@ -1061,12 +1065,12 @@ _dl_map_object_from_fd (const char *name
   if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
     _dl_debug_printf ("  dynamic: 0x%0*lx  base: 0x%0*lx   size: 0x%0*Zx\n"
 		      "    entry: 0x%0*lx  phdr: 0x%0*lx  phnum:   %*u\n\n",
-		      sizeof (void *) * 2, (unsigned long int) l->l_ld,
-		      sizeof (void *) * 2, (unsigned long int) l->l_addr,
-		      sizeof (void *) * 2, maplength,
-		      sizeof (void *) * 2, (unsigned long int) l->l_entry,
-		      sizeof (void *) * 2, (unsigned long int) l->l_phdr,
-		      sizeof (void *) * 2, l->l_phnum);
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_ld,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_addr,
+		      (int) sizeof (void *) * 2, maplength,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_entry,
+		      (int) sizeof (void *) * 2, (unsigned long int) l->l_phdr,
+		      (int) sizeof (void *) * 2, l->l_phnum);
 
   elf_get_dynamic_info (l);
 
@@ -1213,6 +1217,10 @@ open_verify (const char *name, struct fi
     [EI_OSABI] = ELFOSABI_SYSV,
     [EI_ABIVERSION] = 0
   };
+  static const struct {
+    ElfW(Word) vendorlen, datalen, type;
+    char vendor [4];
+  } expected_note = { 4, 16, 1, "GNU" };
   int fd;
 
   /* Open the file.  We always open files read-only.  */
@@ -1220,6 +1228,10 @@ open_verify (const char *name, struct fi
   if (fd != -1)
     {
       ElfW(Ehdr) *ehdr;
+      ElfW(Phdr) *phdr, *ph;
+      ElfW(Word) *abi_note, abi_note_buf[8];
+      unsigned int osversion;
+      size_t maplength;
 
       /* We successfully openened the file.  Now verify it is a file
 	 we can use.  */
@@ -1287,12 +1299,7 @@ open_verify (const char *name, struct fi
 	lose (0, fd, name, NULL, NULL,
 	      N_("ELF file version does not match current one"));
       if (! __builtin_expect (elf_machine_matches_host (ehdr), 1))
-	{
-	close_and_out:
-	  __close (fd);
-	  __set_errno (ENOENT);
-	  fd = -1;
-	}
+	goto close_and_out;
       else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr)))
 	       != sizeof (ElfW(Phdr)))
 	lose (0, fd, name, NULL, NULL,
@@ -1301,6 +1308,50 @@ open_verify (const char *name, struct fi
 	       && __builtin_expect (ehdr->e_type, ET_EXEC) != ET_EXEC)
 	lose (0, fd, name, NULL, NULL,
 	      N_("only ET_DYN and ET_EXEC can be loaded"));
+
+      maplength = ehdr->e_phnum * sizeof (ElfW(Phdr));
+      if (ehdr->e_phoff + maplength <= fbp->len)
+	phdr = (void *) (fbp->buf + ehdr->e_phoff);
+      else
+	{
+	  phdr = alloca (maplength);
+	  __lseek (fd, SEEK_SET, ehdr->e_phoff);
+	  if (__libc_read (fd, (void *) phdr, maplength) != maplength)
+	    lose (errno, fd, name, NULL, NULL, N_("cannot read file data"));
+	}
+
+      /* Check .note.ABI-tag if present.  */
+      for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
+	if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4)
+	  {
+	    if (ph->p_offset + 32 <= fbp->len)
+	      abi_note = (void *) (fbp->buf + ph->p_offset);
+	    else
+	      {
+		__lseek (fd, SEEK_SET, ph->p_offset);
+		if (__libc_read (fd, (void *) abi_note_buf, 32) != 32)
+		  lose (errno, fd, name, NULL, NULL,
+			N_("cannot read file data"));
+		abi_note = abi_note_buf;
+	      }
+
+	    if (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+	      continue;
+
+	    osversion = (abi_note [5] & 0xff) * 65536
+			+ (abi_note [6] & 0xff) * 256
+			+ (abi_note [7] & 0xff);
+	    if (abi_note [4] != __ABI_TAG_OS
+		|| (_dl_osversion && _dl_osversion < osversion))
+	      {
+	      close_and_out:
+		__close (fd);
+		__set_errno (ENOENT);
+		fd = -1;
+	      }
+
+	    break;
+	  }
     }
 
   return fd;
--- libc/elf/dl-minimal.c.jj	Mon Mar 12 11:10:12 2001
+++ libc/elf/dl-minimal.c	Mon Mar 12 15:07:15 2001
@@ -252,6 +252,8 @@ __strtoul_internal (const char *nptr, ch
 	  || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
 	{
 	  errno = ERANGE;
+	  if (endptr != NULL)
+	    *endptr = (char *) nptr;
 	  return ULONG_MAX;
 	}
       result *= base;
@@ -259,5 +261,7 @@ __strtoul_internal (const char *nptr, ch
       ++nptr;
     }
 
+  if (endptr != NULL)
+    *endptr = (char *) nptr;
   return result * sign;
 }
--- libc/elf/ldconfig.c.jj	Mon Mar 12 11:11:29 2001
+++ libc/elf/ldconfig.c	Mon Mar 12 15:07:15 2001
@@ -48,14 +48,6 @@
 
 #define PACKAGE _libc_intl_domainname
 
-struct lib_entry
-  {
-    int flags;
-    uint64_t hwcap;
-    char *lib;
-    char *path;
-  };
-
 static const struct
 {
   const char *name;
@@ -460,6 +452,7 @@ manual_link (char *library)
   char *soname;
   struct stat64 stat_buf;
   int flag;
+  unsigned int osversion;
 
   /* Prepare arguments for create_links call.  Split library name in
      directory and filename first.  Since path is allocated, we've got
@@ -524,7 +517,8 @@ manual_link (char *library)
       free (path);
       return;
     }
-  if (process_file (real_library, library, libname, &flag, &soname, 0))
+  if (process_file (real_library, library, libname, &flag, &osversion,
+		    &soname, 0))
     {
       error (0, 0, _("No link created since soname could not be found for %s"),
 	     library);
@@ -568,6 +562,7 @@ struct dlib_entry
   char *soname;
   int flag;
   int is_link;
+  unsigned int osversion;
   struct dlib_entry *next;
 };
 
@@ -585,6 +580,7 @@ search_dir (const struct dir_entry *entr
   struct stat64 stat_buf;
   int is_link;
   uint64_t hwcap = path_hwcap (entry->path);
+  unsigned int osversion;
 
   file_name_len = PATH_MAX;
   file_name = alloca (file_name_len);
@@ -700,7 +696,7 @@ search_dir (const struct dir_entry *entr
 	real_name = real_file_name;
 
       if (process_file (real_name, file_name, direntry->d_name, &flag,
-			&soname, is_link))
+			&osversion, &soname, is_link))
 	{
 	  if (real_name != real_file_name)
 	    free (real_name);
@@ -762,6 +758,11 @@ search_dir (const struct dir_entry *entr
 			error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
 			       dlib_ptr->name, direntry->d_name, entry->path);
 		    }
+		  /* OS version should be the same - sanity check.  */
+		  if (dlib_ptr->osversion != osversion)
+		    error (0, 0, _("libraries %s and %s in directory %s have same\n"
+				   "soname but different minimal supported OS version."),
+			   dlib_ptr->name, direntry->d_name, entry->path);
 		  free (dlib_ptr->name);
 		  dlib_ptr->name = xstrdup (direntry->d_name);
 		  dlib_ptr->is_link = is_link;
@@ -778,6 +779,7 @@ search_dir (const struct dir_entry *entr
 	  dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
 	  dlib_ptr->name = xstrdup (direntry->d_name);
 	  dlib_ptr->flag = flag;
+	  dlib_ptr->osversion = osversion;
 	  dlib_ptr->soname = soname;
 	  dlib_ptr->is_link = is_link;
 	  /* Add at head of list.  */
@@ -797,7 +799,8 @@ search_dir (const struct dir_entry *entr
 	create_links (dir_name, entry->path, dlib_ptr->name,
 		      dlib_ptr->soname);
       if (opt_build_cache)
-	add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
+	add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
+		      dlib_ptr->osversion, hwcap);
     }
 
   /* Free all resources.  */
--- libc/elf/readlib.c.jj	Mon Mar 12 11:11:29 2001
+++ libc/elf/readlib.c	Mon Mar 12 15:07:30 2001
@@ -70,7 +70,8 @@ static struct known_names known_libs [] 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_file (const char *real_file_name, const char *file_name,
-	      const char *lib, int *flag, char **soname, int is_link)
+	      const char *lib, int *flag, unsigned int *osversion,
+	      char **soname, int is_link)
 {
   FILE *file;
   struct stat64 statbuf;
@@ -161,8 +162,8 @@ process_file (const char *real_file_name
       goto done;
     }
 
-  if (process_elf_file (file_name, lib, flag, soname, file_contents,
-			statbuf.st_size))
+  if (process_elf_file (file_name, lib, flag, osversion, soname,
+			file_contents, statbuf.st_size))
     ret = 1;
 
  done:
--- libc/sysdeps/generic/dl-cache.c.jj	Mon Mar 12 11:10:13 2001
+++ libc/sysdeps/generic/dl-cache.c	Mon Mar 12 15:07:30 2001
@@ -228,6 +228,8 @@ _dl_load_cache_lookup (const char *name)
 
       /* Only accept hwcap if it's for the right platform.  */
 #define HWCAP_CHECK							       \
+      if (_dl_osversion	&& cache_new->libs[middle].osversion > _dl_osversion)  \
+	continue;							       \
       if (_DL_PLATFORMS_COUNT && platform != -1				       \
 	  && (cache_new->libs[middle].hwcap & _DL_HWCAP_PLATFORM) != 0	       \
 	  && (cache_new->libs[middle].hwcap & _DL_HWCAP_PLATFORM) != platform) \
--- libc/sysdeps/generic/dl-cache.h.jj	Mon Mar 12 11:10:13 2001
+++ libc/sysdeps/generic/dl-cache.h	Mon Mar 12 15:07:30 2001
@@ -76,7 +76,7 @@ struct file_entry_new
 {
   int32_t flags;		/* This is 1 for an ELF library.  */
   uint32_t key, value;		/* String table indices.  */
-  uint32_t __unused;		/* Align next field always on 8 byte boundary.	*/
+  uint32_t osversion;		/* Required OS version.	 */
   uint64_t hwcap;		/* Hwcap entry.	 */
 };
 
--- libc/sysdeps/generic/ldsodefs.h.jj	Mon Mar 12 11:10:15 2001
+++ libc/sysdeps/generic/ldsodefs.h	Mon Mar 12 15:07:30 2001
@@ -173,6 +173,9 @@ extern char **_dl_argv;
 /* Cached value of `getpagesize ()'.  */
 extern size_t _dl_pagesize;
 
+/* OS version.  */
+extern unsigned int _dl_osversion;
+
 /* File descriptor referring to the zero-fill device.  */
 extern int _dl_zerofd;
 
--- libc/sysdeps/generic/readelflib.c.jj	Mon Mar 12 11:10:15 2001
+++ libc/sysdeps/generic/readelflib.c	Mon Mar 12 15:07:30 2001
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
 		  Jakub Jelinek <jakub@redhat.com>, 1999.
@@ -41,7 +41,8 @@ do								\
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_elf_file (const char *file_name, const char *lib, int *flag,
-		  char **soname, void *file_contents, size_t file_length)
+		  unsigned int *osversion, char **soname, void *file_contents,
+		  size_t file_length)
 {
   int i;
   unsigned int j;
@@ -56,6 +57,7 @@ process_elf_file (const char *file_name,
   char *dynamic_strings;  
 
   elf_header = (ElfW(Ehdr) *) file_contents;
+  *osversion = 0;
 
   if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
     {
@@ -110,6 +112,7 @@ process_elf_file (const char *file_name,
 	  dynamic_addr = segment->p_offset;
 	  dynamic_size = segment->p_filesz;
 	  break;
+
 	case PT_INTERP:
 	  program_interpreter = (char *) (file_contents + segment->p_offset);
 	  check_ptr (program_interpreter);
@@ -123,6 +126,21 @@ process_elf_file (const char *file_name,
 		break;
 	      }
 	  break;
+
+	case PT_NOTE:
+	  if (!*osversion && segment->p_filesz == 32 && segment->p_align >= 4)
+	    {
+	      ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
+						     + segment->p_offset);
+	      if (abi_note [0] == 4 && abi_note [1] == 16 && abi_note [2] == 1
+		  && memcmp (abi_note + 3, "GNU", 4) == 0)
+		*osversion = (abi_note [4] << 24) |
+			     ((abi_note [5] & 0xff) << 16) |
+			     ((abi_note [6] & 0xff) << 8) |
+			     (abi_note [7] & 0xff);
+	    }
+	  break;
+
 	default:
 	  break;
 	}
--- libc/sysdeps/generic/ldconfig.h.jj	Mon Mar 12 15:09:21 2001
+++ libc/sysdeps/generic/ldconfig.h	Mon Mar 12 15:09:25 2001
@@ -39,17 +39,17 @@ extern void init_cache (void);
 extern void save_cache (const char *cache_name);
 
 extern void add_to_cache (const char *path, const char *lib, int flags,
-			  uint64_t hwcap);
+			  unsigned int osversion, uint64_t hwcap);
 
 /* Declared in readlib.c.  */
 extern int process_file (const char *real_file_name, const char *file_name,
-			 const char *lib, int *flag, char **soname,
-			 int is_link);
+			 const char *lib, int *flag, unsigned int *osversion,
+			 char **soname, int is_link);
 
 /* Declared in readelflib.c.  */
 extern int process_elf_file (const char *file_name, const char *lib, int *flag,
-			     char **soname, void *file_contents,
-			     size_t file_length);
+			     unsigned int *osversion, char **soname,
+			     void *file_contents, size_t file_length);
 
 /* Declared in chroot_canon.c.  */
 extern char *chroot_canon (const char *chroot, const char *name);
--- libc/sysdeps/unix/sysv/linux/ia64/readelflib.c.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/ia64/readelflib.c	Mon Mar 12 15:07:31 2001
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -18,25 +18,28 @@
 
 
 int process_elf32_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents, size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 int process_elf64_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents, size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_elf_file (const char *file_name, const char *lib, int *flag,
-		  char **soname, void *file_contents, size_t file_length)
+		  unsigned int *osversion, char **soname,
+		  void *file_contents, size_t file_length)
 {
   ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
   int ret;
 
   if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
-    return process_elf32_file (file_name, lib, flag, soname, file_contents,
-				file_length);
+    return process_elf32_file (file_name, lib, flag, osversion, soname,
+			       file_contents, file_length);
   else
     {
-      ret = process_elf64_file (file_name, lib, flag, soname, file_contents,
-				 file_length);
+      ret = process_elf64_file (file_name, lib, flag, osversion, soname,
+				file_contents, file_length);
       /* Intel 64bit libraries are always libc.so.6+.  */
       if (!ret)
 	*flag = FLAG_IA64_LIB64|FLAG_ELF_LIBC6;
--- libc/sysdeps/unix/sysv/linux/i386/dl-librecon.h.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/i386/dl-librecon.h	Mon Mar 12 15:07:31 2001
@@ -48,6 +48,29 @@
 
 /* Recognizing extra environment variables.  */
 #define EXTRA_LD_ENVVARS \
+  case 13:								      \
+    if (memcmp (&envline[3], "ASSUME_KERNEL", 13) == 0)			      \
+      {									      \
+	unsigned long int i, j, osversion = 0;				      \
+	char *p = &envline[17], *q;					      \
+									      \
+	for (i = 0; i < 3; i++, p = q + 1)				      \
+	  {								      \
+	    j = __strtoul_internal (p, &q, 0, 0);			      \
+	    if (j >= 255 || p == q || (i < 2 && *q && *q != '.'))	      \
+	      {								      \
+		osversion = 0;						      \
+		break;							      \
+	      }								      \
+	    osversion |= j << (16 - 8 * i);				      \
+	    if (!*q)							      \
+	      break;							      \
+	  }								      \
+	if (osversion)							      \
+	  _dl_osversion = osversion;					      \
+	break;								      \
+      }									      \
+									      \
   case 15:								      \
     if (memcmp (&envline[3], "LIBRARY_VERSION", 15) == 0)		      \
       {									      \
--- libc/sysdeps/unix/sysv/linux/i386/readelflib.c.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/i386/readelflib.c	Mon Mar 12 15:07:31 2001
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
 		  Jakub Jelinek <jakub@redhat.com>, 2000.
@@ -20,23 +20,24 @@
 
 
 int process_elf32_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents,
-			size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 int process_elf64_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents,
-			size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_elf_file (const char *file_name, const char *lib, int *flag,
-		  char **soname, void *file_contents, size_t file_length)
+		  unsigned int *osversion, char **soname, void *file_contents,
+		  size_t file_length)
 {
   ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
   int ret;
 
   if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
-    return process_elf32_file (file_name, lib, flag, soname, file_contents,
-			       file_length);
+    return process_elf32_file (file_name, lib, flag, osversion, soname,
+			       file_contents, file_length);
   else
     {
       switch (elf_header->e_machine)
@@ -50,8 +51,8 @@ process_elf_file (const char *file_name,
 	  return 1;
 	}
 
-      ret = process_elf64_file (file_name, lib, flag, soname, file_contents,
-				file_length);
+      ret = process_elf64_file (file_name, lib, flag, osversion, soname,
+				file_contents, file_length);
       /* IA64/X86-64 64bit libraries are always libc.so.6+.  */
       if (!ret)
 	switch (elf_header->e_machine)
--- libc/sysdeps/unix/sysv/linux/sparc/readelflib.c.jj	Mon Mar 12 11:10:18 2001
+++ libc/sysdeps/unix/sysv/linux/sparc/readelflib.c	Mon Mar 12 15:07:31 2001
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
 		  Jakub Jelinek <jakub@redhat.com>, 1999.
@@ -20,27 +20,28 @@
 
 
 int process_elf32_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents,
-			size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 int process_elf64_file (const char *file_name, const char *lib, int *flag,
-			char **soname, void *file_contents,
-			size_t file_length);
+			unsigned int *osversion, char **soname,
+			void *file_contents, size_t file_length);
 
 /* Returns 0 if everything is ok, != 0 in case of error.  */
 int
 process_elf_file (const char *file_name, const char *lib, int *flag,
-		  char **soname, void *file_contents, size_t file_length)
+		  unsigned int *osversion, char **soname, void *file_contents,
+		  size_t file_length)
 {
   ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
   int ret;
 
   if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
-    return process_elf32_file (file_name, lib, flag, soname, file_contents,
-			       file_length);
+    return process_elf32_file (file_name, lib, flag, osversion, soname,
+			       file_contents, file_length);
   else
     {
-      ret = process_elf64_file (file_name, lib, flag, soname, file_contents,
-				file_length);
+      ret = process_elf64_file (file_name, lib, flag, osversion, soname,
+				file_contents, file_length);
       /* Sparc 64bit libraries are always libc.so.6+.  */
       if (!ret)
 	*flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;
--- libc/sysdeps/unix/sysv/linux/configure.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/configure	Mon Mar 12 15:07:31 2001
@@ -87,6 +87,7 @@ if test -n "$minimum_kernel"; then
   echo $ac_n "checking for kernel header at least $minimum_kernel""... $ac_c" 1>&6
 echo "configure:89: checking for kernel header at least $minimum_kernel" >&5
   decnum=`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/(\1 * 65536 + \2 * 256 + \3)/'`;
+  abinum=`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1,\2,\3/'`;
   cat > conftest.$ac_ext <<EOF
 #line 92 "configure"
 #include "confdefs.h"
@@ -109,6 +110,10 @@ rm -f conftest*
   if test "$libc_minimum_kernel" = ok; then
     cat >> confdefs.h <<EOF
 #define __LINUX_KERNEL_VERSION $decnum
+EOF
+
+    cat >> confdefs.h <<EOF
+#define __ABI_TAG_VERSION $abinum
 EOF
 
   else
--- libc/sysdeps/unix/sysv/linux/configure.in.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/configure.in	Mon Mar 12 15:07:31 2001
@@ -74,6 +74,7 @@ if test -n "$minimum_kernel"; then
   AC_MSG_CHECKING(for kernel header at least $minimum_kernel)
 changequote(,)dnl
   decnum=`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/(\1 * 65536 + \2 * 256 + \3)/'`;
+  abinum=`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1,\2,\3/'`;
 changequote([,])dnl
   AC_EGREP_CPP([eat flaming death], [#include <linux/version.h>
 #if LINUX_VERSION_CODE < $decnum
@@ -82,6 +83,7 @@ eat flaming death
   AC_MSG_RESULT($libc_minimum_kernel)
   if test "$libc_minimum_kernel" = ok; then
     AC_DEFINE_UNQUOTED(__LINUX_KERNEL_VERSION, $decnum)
+    AC_DEFINE_UNQUOTED(__ABI_TAG_VERSION, $abinum)
   else
     AC_MSG_ERROR([*** The available kernel headers are older than the requested
 *** compatible kernel version])
--- libc/sysdeps/unix/sysv/linux/dl-librecon.h.jj	Mon Mar 12 15:07:31 2001
+++ libc/sysdeps/unix/sysv/linux/dl-librecon.h	Mon Mar 12 15:07:31 2001
@@ -0,0 +1,49 @@
+/* Optional code to distinguish library flavours.
+   Copyright (C) 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _DL_LIBRECON_H
+#define _DL_LIBRECON_H	1
+
+/* Recognizing extra environment variables.  */
+#define EXTRA_LD_ENVVARS \
+  case 13:								      \
+    if (memcmp (&envline[3], "ASSUME_KERNEL", 13) == 0)			      \
+      {									      \
+	unsigned long int i, j, osversion = 0;				      \
+	char *p = &envline[17], *q;					      \
+									      \
+	for (i = 0; i < 3; i++, p = q + 1)				      \
+	  {								      \
+	    j = __strtoul_internal (p, &q, 0, 0);			      \
+	    if (j >= 255 || p == q || (i < 2 && *q && *q != '.'))	      \
+	      {								      \
+		osversion = 0;						      \
+		break;							      \
+	      }								      \
+	    osversion |= j << (16 - 8 * i);				      \
+	    if (!*q)							      \
+	      break;							      \
+	  }								      \
+	if (osversion)							      \
+	  _dl_osversion = osversion;					      \
+	break;								      \
+      }
+
+#endif /* dl-librecon.h */
--- libc/sysdeps/unix/sysv/linux/dl-osinfo.h.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/dl-osinfo.h	Mon Mar 12 15:07:31 2001
@@ -102,5 +102,7 @@ dl_fatal (const char *str)
 	if (version < __LINUX_KERNEL_VERSION)				      \
 	  /* Not sufficent.  */						      \
 	  FATAL ("FATAL: kernel too old\n");				      \
+									      \
+	_dl_osversion = version;					      \
       }									      \
   } while (0)
--- libc/sysdeps/unix/sysv/linux/init-first.c.jj	Mon Mar 12 11:10:17 2001
+++ libc/sysdeps/unix/sysv/linux/init-first.c	Mon Mar 12 15:07:31 2001
@@ -29,6 +29,7 @@
 #include <libc-internal.h>
 
 #ifndef SHARED
+# include <ldsodefs.h>
 # include "dl-osinfo.h"
 #endif
 
--- libc/Makerules.jj	Mon Mar 12 11:09:59 2001
+++ libc/Makerules	Mon Mar 12 15:07:15 2001
@@ -413,29 +413,75 @@ endif
 lib%.so: lib%_pic.a $(+preinit) $(+postinit) $(+interp)
 	$(build-shlib)
 
-define build-shlib
-$(LINK.o) -shared -Wl,-O1 -o $@ $(sysdep-LDFLAGS) $(config-LDFLAGS)  \
+define build-shlib-helper
+$(LINK.o) -shared -Wl,-O1 $(sysdep-LDFLAGS) $(config-LDFLAGS) \
 	  $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
 	  $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
 	  -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
 	  $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
-	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
-	  -Wl,--whole-archive \
+	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
+endef
+
+ifeq (yes,$(elf))
+# binutils only position loadable notes into the first page for binaries,
+# not for shared objects
+define build-shlib
+$(build-shlib-helper) \
+	  -o $@.new $(csu-objpfx)/abi-note.o -Wl,--verbose \
+	  $(LDLIBS-$(@F:lib%.so=%).so) 2>&1 | \
+	  sed -e '/^=========/,/^=========/!d;/^=========/d' \
+	      -e 's/^.*\.hash[ 	]*:.*$$/  .note.ABI-tag : { *(.note.ABI-tag) } &/' \
+	  > $@.lds; \
+	  rm -f $@.new; \
+	  $(build-shlib-helper) -o $@ -T $@.lds \
+	  -Wl,--whole-archive $(csu-objpfx)/abi-note.o \
+	  $(filter-out $(map-file) $(+preinit) $(+postinit),$^) \
+	  $(no-whole-archive) $(LDLIBS-$(@F:lib%.so=%).so); \
+	  rm -f $@.lds
+endef
+else
+define build-shlib
+$(build-shlib-helper) \
+	  -o $@ -Wl,--whole-archive \
 	  $(filter-out $(map-file) $(+preinit) $(+postinit),$^) \
 	  $(no-whole-archive) $(LDLIBS-$(@F:lib%.so=%).so)
 endef
+endif
+
+define build-module-helper
+$(LINK.o) -shared $(sysdep-LDFLAGS) $(config-LDFLAGS) \
+	  -B$(csu-objpfx) $(load-map-file) \
+	  $(LDFLAGS.so) $(LDFLAGS-$(@F:%.so=%).so) \
+	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
+endef
 
 # This macro is similar to build-shlib but it does not define a soname
 # and it does not depend on the destination name to start with `lib'.
+ifeq (yes,$(elf))
+# binutils only position loadable notes into the first page for binaries,
+# not for shared objects
 define build-module
-$(LINK.o) -shared -o $@ $(sysdep-LDFLAGS) $(config-LDFLAGS)  \
-	  -B$(csu-objpfx) $(load-map-file) \
-	  $(LDFLAGS.so) $(LDFLAGS-$(@F:%.so=%).so) \
-	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
-	  -Wl,--whole-archive \
+$(build-module-helper) \
+	  -o $@.new $(csu-objpfx)/abi-note.o -Wl,--verbose \
+	  $(LDLIBS-$(@F:lib%.so=%).so) 2>&1 | \
+	  sed -e '/^=========/,/^=========/!d;/^=========/d' \
+	      -e 's/^.*\.hash[ 	]*:.*$$/  .note.ABI-tag : { *(.note.ABI-tag) } &/' \
+	  > $@.lds; \
+	  rm -f $@.new; \
+	  $(build-module-helper) -o $@ -T $@.lds \
+	  -Wl,--whole-archive $(csu-objpfx)/abi-note.o \
+	  $(filter-out $(map-file) $(+preinit) $(+postinit),$^) \
+	  $(no-whole-archive) $(LDLIBS-$(@F:lib%.so=%).so); \
+	  rm -f $@.lds
+endef
+else
+define build-module
+$(build-module-helper) \
+	  -o $@ -Wl,--whole-archive \
 	  $(filter-out $(map-file) $(+preinit) $(+postinit),$^) \
 	  $(no-whole-archive) $(LDLIBS-$(@F:%.so=%).so)
 endef
+endif
 
 # Don't try to use -lc when making libc.so itself.
 # Also omits crti.o and crtn.o, which we do not want
--- libc/config.h.in.jj	Mon Mar 12 11:10:04 2001
+++ libc/config.h.in	Mon Mar 12 15:07:15 2001
@@ -93,6 +93,9 @@
 /* Linux specific: minimum supported kernel version.  */
 #undef	__LINUX_KERNEL_VERSION
 
+/* Override abi-tags ABI version if necessary.  */
+#undef  __ABI_TAG_VERSION
+
 /* An extension in gcc 2.96 and up allows the subtraction of two
    local labels.  */
 #undef	HAVE_SUBTRACT_LOCAL_LABELS


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]