This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC 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]

[java] RFC/RFA: libgcj_bc.so.1


Currently, binaries built with GCJ's "Binary Compatibility" ABI link against the same SONAME as binaries built with the C++ ABI. This is problematic because changes to the Java class libraries frequently break C++ ABI compatibility: we need to bump the SONAME with each release, but changing the SONAME itself breaks BC-ABI applications which would otherwise be compatible. If the two ABIs are to continue to co-exist, we need different SONAMEs for them.

This solution works by creating a shared library called libgcj_bc.so which contains empty, "fake" declarations of all the symbols that BC-ABI applications are allowed to reference in libgcj. At compilation time, if -findirect-dispatch is specified, gcj will link with -lgcj_bc instead of -lgcj. The linker will find libgcj_bc.so, which has an SONAME of libgcj_bc.so.1.

However, libgcj_bc.so.1 itself is actually a symlink to the real libgcj.so. So at runtime, the dynamic linker loads the real library to resolve the libgcj_bc.so.1 SONAME.

This approach also has the side-benefit of ensuring that BC applications only link against legitimate BC-ABI symbols.

Currently this is only enabled for linux systems. It may make sense to enable it for other ELF platforms too.

OK for trunk?

Bryce


gcc/java:
2006-07-13  Bryce McKinlay  <mckinlay@redhat.com>

	* jvspec.c (lang_specific_driver): Add -s-bc-abi flag to compiler
	arguments if linking for the BC-ABI.

libjava:
2006-07-13  Bryce McKinlay  <mckinlay@redhat.com>

	* configure.host: New use_libgcj_bc variable. Set it on linux hosts.
	* configure.ac: New USE_LIBGCJ_BC automake conditional.
	* libtool-version: Change format so that individual elements can be
	read separately. When use_libgcj_bc is enabled, set LIBGCJ_SPEC to 
	link to libgcj_bc if -s-bc-abi is specified.
	* libgcj.spec.in: Substitute LIBGCJ_SPEC in lib spec.
	* Makefile.am (libgcj_bc.la): New rule to build libgcj_bc.so.
	(install-exec-hook): New hook to configure symlinks for libgcj_bc.so.
	* libgcj_bc.c: New file. Fake BC-API definitions for libgcj_bc.so.

Index: gcc/java/jvspec.c
===================================================================
--- gcc/java/jvspec.c	(revision 115370)
+++ gcc/java/jvspec.c	(working copy)
@@ -243,6 +243,9 @@
   /* The argument we use to specify the spec file.  */
   char *spec_file = NULL;
 
+  /* If linking, nonzero if the BC-ABI is in use.  */
+  int link_for_bc_abi = 0;
+
   argc = *in_argc;
   argv = *in_argv;
   added_libraries = *in_added_libraries;
@@ -365,6 +368,11 @@
           else if (strcmp (argv[i], "-static-libgcc") == 0
                    || strcmp (argv[i], "-static") == 0)
 	    shared_libgcc = 0;
+	  else if (strcmp (argv[i], "-findirect-dispatch") == 0
+		   || strcmp (argv[i], "--indirect-dispatch") == 0)
+	    {
+	      link_for_bc_abi = 1;
+	    }
 	  else
 	    /* Pass other options through.  */
 	    continue;
@@ -490,6 +498,8 @@
   
   num_args += shared_libgcc;
 
+  num_args += link_for_bc_abi;
+
   arglist = XNEWVEC (const char *, num_args + 1);
   j = 0;
 
@@ -599,6 +609,9 @@
   if (shared_libgcc)
     arglist[j++] = "-shared-libgcc";
 
+  if (link_for_bc_abi)
+    arglist[j++] = "-s-bc-abi";
+
   arglist[j] = NULL;
 
   *in_argc = j;
Index: libjava/configure.host
===================================================================
--- libjava/configure.host	(revision 115370)
+++ libjava/configure.host	(working copy)
@@ -31,6 +31,8 @@
 #   fallback_backtrace_h  Header to use for fallback backtrace implementation
 #			  (only for targets that don't support DWARF2 unwind)
 #   descriptor_h	Header to use for looking past function descriptors
+#   use_libgcj_bc	Whether to build a "libgcj-bc" library for BC-ABI
+#			binaries to link against.
 
 libgcj_flags=
 libgcj_cflags=
@@ -314,6 +316,15 @@
 	;;
 esac
 
+case "${host}" in
+  *linux*)
+    use_libgcj_bc=yes
+  ;;
+  *)
+    use_libgcj_bc=no
+  ;;
+esac    
+
 libgcj_cflags="${libgcj_cflags} ${libgcj_flags}"
 libgcj_cxxflags="${libgcj_cxxflags} ${libgcj_flags}"
 libgcj_javaflags="${libgcj_javaflags} ${libgcj_flags}"
Index: libjava/configure.ac
===================================================================
--- libjava/configure.ac	(revision 115370)
+++ libjava/configure.ac	(working copy)
@@ -866,12 +867,19 @@
 AM_CONDITIONAL(USING_POSIX_THREADS, test "$THREADS" = posix)
 AM_CONDITIONAL(USING_WIN32_THREADS, test "$THREADS" = win32)
 AM_CONDITIONAL(USING_NO_THREADS, test "$THREADS" = none)
+AM_CONDITIONAL(USE_LIBGCJ_BC, test "$use_libgcj_bc" = yes)
 
 if test -d sysdep; then true; else mkdir sysdep; fi
 AC_CONFIG_LINKS(sysdep/locks.h:sysdep/$sysdeps_dir/locks.h)
 AC_CONFIG_LINKS(sysdep/backtrace.h:$fallback_backtrace_h)
 AC_CONFIG_LINKS(sysdep/descriptor.h:$descriptor_h)
 
+LIBGCJ_SPEC="%{s-bc-abi:} -lgcj"
+if test "$use_libgcj_bc" = yes; then
+  LIBGCJ_SPEC="%{s-bc-abi:-lgcj_bc;:-lgcj}"
+fi
+AC_SUBST(LIBGCJ_SPEC)
+
 HASH_SYNC_SPEC=
 # Hash synchronization is only useful with posix threads right now.
 if test "$enable_hash_synchronization" = yes && test "$THREADS" != "none"; then
Index: libjava/libtool-version
===================================================================
--- libjava/libtool-version	(revision 115370)
+++ libjava/libtool-version	(working copy)
@@ -3,4 +3,7 @@
 # a separate file so that version updates don't involve re-running
 # automake.
 # CURRENT:REVISION:AGE
-7:0:0
+# 7:0:0
+ver_current = 7
+ver_revision = 0
+ver_age = 0
Index: libjava/libgcj.spec.in
===================================================================
--- libjava/libgcj.spec.in	(revision 115370)
+++ libjava/libgcj.spec.in	(working copy)
@@ -7,6 +7,6 @@
 *startfile: @THREADSTARTFILESPEC@ %(startfileorig)
 
 %rename lib liborig
-*lib: @LD_START_STATIC_SPEC@ -lgcj @LD_FINISH_STATIC_SPEC@ -lm @LIBICONV@ @GCSPEC@ @THREADSPEC@ @ZLIBSPEC@ @SYSTEMSPEC@ %(libgcc) %(liborig)
+*lib: @LD_START_STATIC_SPEC@ @LIBGCJ_SPEC@ @LD_FINISH_STATIC_SPEC@ -lm @LIBICONV@ @GCSPEC@ @THREADSPEC@ @ZLIBSPEC@ @SYSTEMSPEC@ %(libgcc) %(liborig)
 
 *jc1: @HASH_SYNC_SPEC@ @DIVIDESPEC@ @CHECKREFSPEC@ @JC1GCSPEC@ @EXCEPTIONSPEC@ @BACKTRACESPEC@ @IEEESPEC@ -fkeep-inline-functions
Index: libjava/Makefile.am
===================================================================
--- libjava/Makefile.am	(revision 115370)
+++ libjava/Makefile.am	(working copy)
@@ -12,6 +12,8 @@
 SUBDIRS += testsuite
 endif
 
+include $(srcdir)/libtool-version
+
 # write_entries_to_file - writes each entry in a list
 # to the specified file. Each entry is written individually
 # to accomodate systems with severe command-line-length
@@ -36,6 +38,10 @@
 toolexeclib_LTLIBRARIES = libgcj.la libgij.la libgcj-tools.la
 toolexecmainlib_DATA = libgcj.spec
 
+if USE_LIBGCJ_BC
+toolexeclib_LTLIBRARIES += libgcj_bc.la
+endif
+
 if XLIB_AWT
 toolexeclib_LTLIBRARIES += lib-gnu-awt-xlib.la
 endif
@@ -173,9 +179,8 @@
 libgij_la_DEPENDENCIES = libgcj.la libgcj.spec
 ## See jv_convert_LDADD.
 libgij_la_LIBADD = -L$(here)/.libs libgcj.la
-## The mysterious backslash in the grep pattern is consumed by make.
 libgij_la_LDFLAGS = -rpath $(toolexeclibdir) \
-        -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC)
+        -version-info $(ver_current):$(ver_revision):$(ver_age) $(LIBGCJ_LD_SYMBOLIC)
 
 libgcj_la_SOURCES = prims.cc jni.cc exception.cc stacktrace.cc \
 	link.cc defineclass.cc interpret.cc verify.cc \
@@ -220,10 +225,9 @@
 
 # Include THREADLIBS here to ensure that the correct version of
 # certain linuxthread functions get linked:
-## The mysterious backslash in the grep pattern is consumed by make.
 libgcj_la_LDFLAGS = -rpath $(toolexeclibdir) $(THREADLDFLAGS) $(THREADLIBS) \
 	$(LIBLTDL) $(SYS_ZLIBS) \
-	-version-info `grep -v '^\#' $(srcdir)/libtool-version`
+        -version-info $(ver_current):$(ver_revision):$(ver_age)
 libgcj_la_LIBADD = \
 	classpath/native/fdlibm/libfdlibm.la \
 	$(all_packages_source_files:.list=.lo) \
@@ -238,7 +242,7 @@
 libgcj_tools_la_SOURCES = classpath/tools/tools.jar
 libgcj_tools_la_GCJFLAGS = $(AM_GCJFLAGS) -findirect-dispatch -fno-indirect-classes
 libgcj_tools_la_LDFLAGS = -rpath $(toolexeclibdir) \
- -version-info `grep -v '^\#' $(srcdir)/libtool-version`
+ -version-info $(ver_current):$(ver_revision):$(ver_age)
 libgcj_tools_la_DEPENDENCIES = libgcj.la libgcj.spec
 libgcj_tools_la_LINK = $(LIBLINK)
 
@@ -247,10 +251,26 @@
 libjvm_la_DEPENDENCIES = libgcj.la libgcj.spec
 ## See jv_convert_LDADD.
 libjvm_la_LIBADD = -L$(here)/.libs libgcj.la
-## The mysterious backslash in the grep pattern is consumed by make.
 libjvm_la_LDFLAGS = \
-        -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC)
+        -version-info $(ver_current):$(ver_revision):$(ver_age) $(LIBGCJ_LD_SYMBOLIC)
 
+## Support for libgcj_bc: fake shared library used only at link-time.
+##
+## This lets us have one soname in BC objects and another in C++ ABI objects.
+libgcj_bc_la_SOURCES = libgcj_bc.c
+libgcj_bc_la_LDFLAGS = -no-static -version-info 1:0:0
+libgcj_bc_la_LIBADD = libgcj.la
+libgcj_bc_la_DEPENDENCIES = libgcj.la
+libgcj_bc_la_LINK = $(LIBLINK)
+
+## This rule creates the libgcj_bc symlink in the .libs directory, for use
+## when testing.
+libgcj_bc.la: $(libgcj_bc_la_OBJECTS) $(libgcj_bc_la_DEPENDENCIES)
+	$(libgcj_bc_la_LINK) $(am_libgcj_bc_la_rpath) $(libgcj_bc_la_LDFLAGS) \
+	$(libgcj_bc_la_OBJECTS) $(libgcj_bc_la_LIBADD) $(LIBS); \
+	rm .libs/libgcj_bc.so.1; \
+	$(LN_S) libgcj.so.7.0.0 .libs/libgcj_bc.so.1
+
 ## The .db file.  This rule is only used for native builds, so it is
 ## safe to invoke gcj-dbtool.
 $(db_name): gcj-dbtool$(EXEEXT)
@@ -272,11 +292,10 @@
 	-I../libstdc++-v3/include \
 	-I../libstdc++-v3/include/$(target_noncanonical) \
 	-I$(srcdir)/../libstdc++-v3/libsupc++
-## The mysterious backslash in the grep pattern is consumed by make.
 lib_gnu_awt_xlib_la_LDFLAGS = ../libstdc++-v3/src/libstdc++.la \
 	@X_PRE_LIBS@ @X_LIBS@ -lX11 @X_EXTRA_LIBS@ \
         -rpath $(toolexeclibdir) \
-        -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC)
+        -version-info $(ver_current):$(ver_revision):$(ver_age) $(LIBGCJ_LD_SYMBOLIC)
 lib_gnu_awt_xlib_la_LINK = $(LIBLINK)
 
 ## Note that property_files is defined in sources.am.
@@ -506,6 +525,20 @@
 $(extra_headers) $(srcdir)/java/lang/Object.h $(srcdir)/java/lang/Class.h:
 	@:
 
+## Support for libgcj_bc: fake shared library used only at link-time.
+if USE_LIBGCJ_BC
+libgcj_lib_name = libgcj.so.$(ver_current).$(ver_revision).$(ver_age)
+
+## Install libgcj_bc symlink in the target directory. We also need to delete
+## libtool's .la file, this prevents libtool resetting the symlinks again 
+## later.
+install-exec-hook: install-toolexeclibLTLIBRARIES
+	@echo Installing symbolic link from libgcj_bc.so.1 to $(libgcj_lib_name); \
+	rm $(toolexeclibdir)/libgcj_bc.so.1; \
+	$(LN_S) $(libgcj_lib_name) $(toolexeclibdir)/libgcj_bc.so.1; \
+	rm $(toolexeclibdir)/libgcj_bc.la;
+endif
+
 ## Install the headers.  It is fairly ugly that we have to do this by
 ## hand.
 install-data-local:
@@ -543,7 +576,6 @@
 	$(INSTALL_DATA) 'gnu/java/nio/PipeImpl$$SourceChannelImpl.h' $(DESTDIR)$(gxx_include_dir)/gnu/java/nio/
 ## Don't install java/nio/DirectByteBufferImpl$$ReadWrite.h here. It's for internal use only.
 
-
 ## ################################################################
 
 ##
Index: libjava/libgcj_bc.c
===================================================================
--- libjava/libgcj_bc.c	(revision 0)
+++ libjava/libgcj_bc.c	(revision 0)
@@ -0,0 +1,93 @@
+// libgcj_bc.c
+
+/* Copyright (C) 2006 Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+// This file is used to build libgcj_bc.so, a 'fake' library that is used at
+// link time only. It ensures that binaries built with the BC-ABI link against
+// a constant SONAME. This way, BC-ABI binaries continue to work if the SONAME
+// underlying libgcj.so changes.
+
+#include <stdio.h>
+
+static void print_wrong_lib_msg ()
+{
+  fprintf (stderr, "libgcj error: \
+This is libgcj_bc.so, a fake library used only for linking.\n\
+Please create a symlink from libgcj_bc.so.1 to the real libgcj.so.\n");
+  exit (1);
+}
+
+// Functions called from code generated by gcj
+
+extern void __gcj_personality_v0 () {}
+extern void _Jv_AllocObject () {}
+extern void _Jv_AllocObjectNoFinalizer () {}
+extern void _Jv_InitClass () {}
+extern void _Jv_ResolvePoolEntry () {}
+extern void _Jv_Throw () {}
+extern void _Jv_MonitorEnter () {}
+extern void _Jv_NewPrimArray () {}
+extern void _Jv_NewObjectArray () {}
+extern void _Jv_NewMultiArray () {}
+extern void _Jv_ThrowBadArrayIndex () {}
+extern void _Jv_ThrowNullPointerException () {}
+extern void _Jv_ThrowAbstractMethodError () {}
+extern void _Jv_ThrowNoSuchFieldError () {}
+extern void _Jv_CheckCast () {}
+extern void _Jv_IsInstanceOf () {}
+extern void _Jv_CheckArrayStore () {}
+extern void _Jv_LookupInterfaceMethodIdx () {}
+
+extern void _Jv_RegisterClasses () 
+{
+  print_wrong_lib_msg ();
+}
+
+extern void _Jv_RegisterNewClasses () 
+{
+  print_wrong_lib_msg ();
+}
+
+// Symbols used by jvgenmain (-fmain)
+
+extern void JvRunMain () {}
+const char **_Jv_Compiler_Properties;
+
+// Functions used by -fjni
+
+extern void _Jv_LookupJNIMethod () {}
+extern void _Jv_GetJNIEnvNewFrame () {}
+extern void _Jv_UnwrapJNIweakReference () {}
+
+
+// Checked divide (-fuse-divide-subroutine)
+
+extern void _Jv_divI () {}
+extern void _Jv_remI () {}
+extern void _Jv_divJ () {}
+extern void _Jv_remJ () {}
+
+
+// CNI Functions
+
+extern void _Jv_AllocBytes () {}
+extern void _Jv_AllocString () {}
+extern void _Jv_NewString () {}
+extern void _Jv_NewStringLatin1 () {}
+extern void _Jv_GetStringChars () {}
+extern void _Jv_GetStringUTFLength () {}
+extern void _Jv_GetStringUTFRegion () {}
+extern void _Jv_NewStringUTF () {}
+extern void _Jv_Malloc () {}
+extern void _Jv_Realloc () {}
+extern void _Jv_Free () {}
+extern void _Jv_CreateJavaVM () {}
+extern void _Jv_AttachCurrentThread () {}
+extern void _Jv_AttachCurrentThreadAsDaemon () {}
+extern void _Jv_DetachCurrentThread () {}

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