This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[java] RFC/RFA: libgcj_bc.so.1
- From: Bryce McKinlay <mckinlay at redhat dot com>
- To: Java Patches <java-patches at gcc dot gnu dot org>, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 14 Jul 2006 00:37:44 -0400
- Subject: [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 () {}