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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] ARM: Fix transitional issues with ld.so.cache.


Joseph, Steve,

With a recent binutils the objects built for the VFP ABI are 
marked with the ELF flag EF_ARM_ABI_FLOAT_HARD. This flag is 
used by ldconfig to annotate the object in the cache with the 
FLAG_ARM_LIBHF flag. The FLAG_ARM_LIBHF flag is used to prevent
the hard-float dyanmic linker from loading objects that use the
wrong ABI e.g. soft-float ABI.

Unfortunately the binutils changes for marking objects did not
make it into the initial distribution builds and therefore 
there are many objects in the wild that lack any markings to 
indicate their ABI.

The failure scenario is as follows:
* Upgrade to a new glibc.
* Upgrade to a new binutils.
* Build your library with the new binutils.
* Run the new glibc's ldconfig.
* Try to run an old application.

At this point you have a library marked FLAG_ARM_LIBHF, that
can't be mixed with any of the other libraries which are
hard-float ABI but no markings and therefore don't match
the flags for your library e.g. _dl_cache_check_flags() fails,
and the dynamic linker refuses run the application.

See BZ#15006 for an example:
"Libraries in ld.so.cache ignored by ld-linux-armhf.so.3 on armv6l"
http://sourceware.org/bugzilla/show_bug.cgi?id=15006

The solution to this problem is to use 3 states (instead of 2)
for the objects in the cache, namely:
(1) Don't know / Don't care.
(2) Soft-float ABI (new state)
(3) VFP ABI.

In order to support this transitional period we then allow (1)
to mix with either (2) or (3). Once all the distributions have
updated to a newer binutils, and all objects are rebuilt, then
every object may be either (2) or (3).

I say (1) is also a "Don't care" state because this lack of
flags can be used in the future to mark objects as not using
any of the features of the VFP ABI and thus compatible with
either (2) or (3) e.g. make no function calls that have
floating point values as arguments.

The patch does the following:

(a) Adds FLAG_ARM_LIBSF as a new ldconfig flag and adjusts
    the verbose cache printout to list `,soft-float' when
    this flag is set and distinguishing from "Don't know."

(b) Sets FLAG_ARM_LIBSF for any object with the ELF flag
    EF_ARM_ABI_FLOAT_SOFT.

(c) Expands the conditions in _dl_cache_check to allow
    hard-float and soft-float dynamic loaders to load
    unmarked don't know / don't care objects.

Tested on ARM with no regressions.

Tests run to validate the new compatibility feature:

* Built application and library with no markings.
  - Setup ld.so.conf to include the library.
  - Ran ldconfig.
  - Application runs correctly.

* Built hard-float ABI application and library with new bintuils.
  - Verified with readelf that both are now marked hard-float
    in the ELF flags (though only new readelf can parse it, old
    readelf prints <unknown>).
  - Ran ldconfig.
  - Application runs correctly.

* Built new glibc.
  - Removed ldconfig cache and aux cache.
  - Used newly built ldconfig to build cache.
  - Application runs correctly when run under new dynamic linker
    since support for mixing don't care with hard-float is in place.
  - Double checked that application *fails* to run with distro
    dynamic linker since the referenced library is marked in the
    cache with FLAG_ARM_LIBHF that doesn't match any other
    libraries in the cache and there is no support for mixing
    unmarked objects.

WARNING:
- Once you upgrade glibc and run ldconfig it is no longer safe 
  to downgrade glibc. If you downgrade you may not be able to 
  run the applications you need until you forcibly remove the 
  caches and run ldconfig again to rebuild the cache without 
  the new flags. By downgrading you have done is made the bug
  come back, but now it's worse because all of the objects 
  built with the new binutils are treated as incompatible.

OK to checkin?

ChangeLog

2013-02-06  Carlos O'Donell  <carlos@redhat.com>

	* sysdeps/generic/ldconfig.h: Define FLAG_ARM_LIBSF.
	* elf/cache.c (print_entry): Add FLAG_ARM_LIBSF support.

ports/ChangeLog.arm

2013-02-06  Carlos O'Donell  <carlos@redhat.com>

	* sysdeps/unix/sysv/linux/arm/dl-cache.h
	[__ARM_PCS_VFP] (_dl_cache_check_flags): Allow plain FLAG_ELF_LIBC6.
	[!__ARM_PCS_VFP] (_dl_cache_check_flags): Likewise.
	* sysdeps/unix/sysv/linux/arm/readelflib.c (process_elf_file):
	Set FLAG_ARM_LIBSF for soft-float ABI otherwise just FLAG_ELF_LIBC6.

diff --git a/elf/cache.c b/elf/cache.c
index 9901952..699550b 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -100,6 +100,10 @@ print_entry (const char *lib, int flag, unsigned int osversion,
     case FLAG_AARCH64_LIB64:
       fputs (",AArch64", stdout);
       break;
+    /* Uses the ARM soft-float ABI.  */
+    case FLAG_ARM_LIBSF:
+      fputs (",soft-float", stdout);
+      break;
     case 0:
       break;
     default:
diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
index 57a9a46..91190aa 100644
--- a/sysdeps/generic/ldconfig.h
+++ b/sysdeps/generic/ldconfig.h
@@ -36,6 +36,7 @@
 #define FLAG_X8664_LIBX32	0x0800
 #define FLAG_ARM_LIBHF		0x0900
 #define FLAG_AARCH64_LIB64	0x0a00
+#define FLAG_ARM_LIBSF		0x0b00
 
 /* Name of auxiliary cache.  */
 #define _PATH_LDCONFIG_AUX_CACHE "/var/cache/ldconfig/aux-cache"
diff --git a/ports/sysdeps/unix/sysv/linux/arm/dl-cache.h b/ports/sysdeps/unix/sysv/linux/arm/dl-cache.h
index acc4f28..1221181 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/dl-cache.h
+++ b/ports/sysdeps/unix/sysv/linux/arm/dl-cache.h
@@ -18,12 +18,17 @@
 
 #include <ldconfig.h>
 
+/* In order to support the transition from unmarked objects
+   to marked objects we must treat unmarked objects as
+   compatible with either FLAG_ARM_LIBHF or FLAG_ARM_LIBSF.  */
 #ifdef __ARM_PCS_VFP
 # define _dl_cache_check_flags(flags) \
-  ((flags) == (FLAG_ARM_LIBHF | FLAG_ELF_LIBC6))
+  ((flags) == (FLAG_ARM_LIBHF | FLAG_ELF_LIBC6) \
+   || (flags) == FLAG_ELF_LIBC6)
 #else
 # define _dl_cache_check_flags(flags) \
-  ((flags) == FLAG_ELF_LIBC6)
+  ((flags) == (FLAG_ARM_LIBSF | FLAG_ELF_LIBC6) \
+   || (flags) == FLAG_ELF_LIBC6)
 #endif
 
 #include_next <dl-cache.h>
diff --git a/ports/sysdeps/unix/sysv/linux/arm/readelflib.c b/ports/sysdeps/unix/sysv/linux/arm/readelflib.c
index 81e5ccb..0fbd0dc 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/readelflib.c
+++ b/ports/sysdeps/unix/sysv/linux/arm/readelflib.c
@@ -46,6 +46,12 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
 	  if (elf32_header->e_flags & EF_ARM_ABI_FLOAT_HARD)
 	    *flag = FLAG_ARM_LIBHF|FLAG_ELF_LIBC6;
 	  else if (elf32_header->e_flags & EF_ARM_ABI_FLOAT_SOFT)
+	    *flag = FLAG_ARM_LIBSF|FLAG_ELF_LIBC6;
+	  else
+	    /* We must assume the unmarked objects are compatible
+	       with all ABI variants. Such objects may have been
+	       generated in a transitional period when the ABI
+	       tags were not added to all objects.  */
 	    *flag = FLAG_ELF_LIBC6;
 	}
     }
---


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