shared library support for HP-UX 10
authorKen Raeburn <raeburn@mit.edu>
Fri, 25 Mar 2005 21:36:55 +0000 (21:36 +0000)
committerKen Raeburn <raeburn@mit.edu>
Fri, 25 Mar 2005 21:36:55 +0000 (21:36 +0000)
Our somewhat outdated HP-UX support (which was targeted at HP-UX 10, not 11)
does not have support for shared library initialization and finalization
functions, nor for shared library export lists.  The former was causing
compilation failures unless shared library support was disabled.

* include/k5-platform.h: Expand on init/fini comments some more.
(MAKE_FINI_FUNCTION): Add an HP-UX specific variant that defines an auxiliary
function fitting the signature of HP-UX 10 library combined
initializer/finalizer functions.

* config/lib.in (hpux10.exports): New target, constructed similar to
osf1.exports but with HP-UX 10.x linker options, no initializers, and "errno"
explicitly added to the export list.
* shlib.conf (*-*-hpux*): Combine PICFLAGS setting with SHLIB_EXPFLAGS and
LDCOMBINE setting.  Add linker option "-c hpux10.exports" to LDCOMBINE.  Set
SHLIB_EXPORT_FILE_DEP to hpux10.exports.  Set use_linker_fini_option.

ticket: new

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@17153 dc483132-0cff-0310-8789-dd5450dbe970

src/config/ChangeLog
src/config/lib.in
src/config/shlib.conf
src/include/ChangeLog
src/include/k5-platform.h

index 7950df236038214251d2d355f9644b07168b83b4..a5ccc5437f954a965549c1fb67308b6c0aeffcb3 100644 (file)
@@ -1,3 +1,13 @@
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+       * lib.in (hpux10.exports): New target, constructed similar to
+       osf1.exports but with HP-UX 10.x linker options, no initializers,
+       and "errno" explicitly added to the export list.
+       * shlib.conf (*-*-hpux*): Combine PICFLAGS setting with
+       SHLIB_EXPFLAGS and LDCOMBINE setting.  Add linker option "-c
+       hpux10.exports" to LDCOMBINE.  Set SHLIB_EXPORT_FILE_DEP to
+       hpux10.exports.  Set use_linker_fini_option.
+
 2005-02-08  Ken Raeburn  <raeburn@mit.edu>
 
        * lib.in (config.status): Change target to be in $thisconfigdir
index eea4601d594e03470a40615e5fa16455b3c91201..ef159f528cbcdc459ac9ba56009a4ca5f60bbf46 100644 (file)
@@ -72,6 +72,18 @@ osf1.exports: $(SHLIB_EXPORT_FILE) Makefile
        done; echo " $$a" >> osf1.tmp; \
        mv -f osf1.tmp osf1.exports
 
+hpux10.exports: $(SHLIB_EXPORT_FILE) Makefile
+       $(RM) hpux10.tmp hpux10.exports
+       sed "s/^/+e /" < $(SHLIB_EXPORT_FILE) > hpux10.tmp
+       a=""; \
+       for f in . $(LIBFINIFUNC); do \
+         if test "$$f" != .; then \
+           a="+I $${f}__auxfini $$a"; \
+         else :; fi; \
+       done; echo "$$a" >> hpux10.tmp
+       echo "+e errno" >> hpux10.tmp
+       mv -f hpux10.tmp hpux10.exports
+
 lib$(LIBBASE)$(PFLIBEXT): $(PFOBJLISTS)
        $(RM) $@
        @echo "building profiled $(LIBBASE) library"
index 4d09e84e464448651a8513b8d612ec73d7d200ee..3261b672ceff8281576483469d8f8ca6b8251787 100644 (file)
@@ -75,27 +75,42 @@ alpha*-dec-osf*)
 # on the commandline of the linker will determine which path
 # (compiled-in or SHLIB_PATH) will be searched first.
 #
+# +I initproc routine gets called at load and unload time for
+#    shl_load calls, but appears to never be called for link-time
+#    specified libraries.
+# +e sym exports symbol and supposedly prevents other symbols
+#    from being exported, according to the man page, but the
+#    latter bit doesn't actually seem to work
+# -O +dpv should display any routines eliminated as unused, but -b
+#        apparently turns that off
 *-*-hpux*)
-       if test "$krb5_cv_prog_gcc" = yes; then
-               PICFLAGS=-fPIC
-       else
-               PICFLAGS=+z
-       fi
        INSTALL_SHLIB='$(INSTALL)'
        SHLIBEXT=.sl
        SHLIBVEXT='.$(LIBMAJOR).$(LIBMINOR)'
        SHLIBSEXT='.$(LIBMAJOR)'
        RPATH_FLAG='-Wl,+b,'
        if test "$krb5_cv_prog_gcc" = yes; then
+               PICFLAGS=-fPIC
                SHLIB_EXPFLAGS='-Wl,+s -Wl,+b,$(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
-               LDCOMBINE='gcc -fPIC -shared -Wl,+h,lib$(LIBBASE)$(SHLIBSEXT)'
+               LDCOMBINE='gcc -fPIC -shared -Wl,+h,lib$(LIBBASE)$(SHLIBSEXT) -Wl,-c,hpux10.exports'
        else
+               PICFLAGS=+z
                SHLIB_EXPFLAGS='+s +b $(SHLIB_RDIRS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
-               LDCOMBINE='ld -b +h lib$(LIBBASE)$(SHLIBSEXT)'
+               LDCOMBINE='ld -b +h lib$(LIBBASE)$(SHLIBSEXT) -c hpux10.exports'
        fi
        CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) -Wl,+s $(RPATH_FLAG)$(PROG_RPATH) $(CFLAGS) $(LDFLAGS)'
        CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
        RUN_ENV='SHLIB_PATH=`echo $(PROG_LIBPATH) | sed -e "s/-L//g" -e "s/ /:/g"`; export SHLIB_PATH;'
+       SHLIB_EXPORT_FILE_DEP=hpux10.exports
+       # Do *not* set use_linker_init_option=yes here, because in the
+       # case where the library is specified at program link time, the
+       # initialization function appears not to get called, only for
+       # shl_load.  But for finalization functions, the shl_load case
+       # is the one we care about.
+       #
+       # Not setting use_linker_init_option here should cause compilation
+       # failures if the user tries to disable delayed initialization.
+       use_linker_fini_option=yes
        ;;
 
 mips-sgi-irix6.3)      # This is a Kludge; see below
index b1de45f4926e6d535a4ff882321c855eccd46a97..f7c5ac739cad90458fb30b1ef8c7b53b14a2ac48 100644 (file)
@@ -1,3 +1,10 @@
+2005-03-25  Ken Raeburn  <raeburn@mit.edu>
+
+       * k5-platform.h: Expand on init/fini comments some more.
+       (MAKE_FINI_FUNCTION): Add an HP-UX specific variant that defines
+       an auxiliary function fitting the signature of HP-UX 10 library
+       combined initializer/finalizer functions.
+
 2005-03-04  Ken Raeburn  <raeburn@mit.edu>
 
        * configure.in: Check return type of gmtime_r, and define
index 5c634bfc4100202782f7fa54bae8d347917a1347..b178622d8702840f205742f0e0bb38aa7bc449bc 100644 (file)
    At top level, before the functions are defined or even declared:
    MAKE_INIT_FUNCTION(init_fn);
    MAKE_FINI_FUNCTION(fini_fn);
+   Then:
    int init_fn(void) { ... }
    void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
-
    In code, in the same file:
    err = CALL_INIT_FUNCTION(init_fn);
 
    To trigger or verify the initializer invocation from another file,
-   an additional function must be created.
+   a helper function must be created.
+
+   This model handles both the load-time execution (Windows) and
+   delayed execution (pthread_once) approaches, and should be able to
+   guarantee in both cases that the init function is run once, in one
+   thread, before other stuff in the library is done; furthermore, the
+   finalization code should only run if the initialization code did.
+   (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via
+   another function hidden in macros, but this is hairy enough
+   already.)
 
    The init_fn and fini_fn names should be chosen such that any
    exported names staring with those names, and optionally followed by
    the library in question.
 
 
+   There's also PROGRAM_EXITING() currently always defined as zero.
+   If there's some trivial way to find out if the fini function is
+   being called because the program that the library is linked into is
+   exiting, we can just skip all the work because the resources are
+   about to be freed up anyways.  Generally this is likely to be the
+   same as distinguishing whether the library was loaded dynamically
+   while the program was running, or loaded as part of program
+   startup.  On most platforms, I don't think we can distinguish these
+   cases easily, and it's probably not worth expending any significant
+   effort.  (Note in particular that atexit() won't do, because if the
+   library is explicitly loaded and unloaded, it would have to be able
+   to deregister the atexit callback function.  Also, the system limit
+   on atexit callbacks may be small.)
+
+
    Implementation outline:
 
    Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
    just check the flag) and returns the stored error code (or the
    pthread_once error).
 
+   (That's the basic idea.  With some debugging assert() calls and
+   such, it's a bit more complicated.  And we also need to handle
+   doing the pthread test at run time on systems where that works, so
+   we use the k5_once_t stuff instead.)
+
    UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
    function as a destructor, and the run time linker support or
    whatever will cause it to be invoked when the library is unloaded,
    UNIX, no library finalization support: The finalization function
    never runs, and we leak memory.  Tough.
 
+   DELAY_INITIALIZER will be defined by the configure script if we
+   want to use k5_once instead of load-time initialization.  That'll
+   be the preferred method on most systems except Windows, where we
+   have to initialize some mutexes.
+
+
 
 
    For maximum flexibility in defining the macros, the function name
    parameter should be a simple name, not even a macro defined as
    another name.  The function should have a unique name, and should
    conform to whatever namespace is used by the library in question.
+   (We do have export lists, but (1) they're not used for all
+   platforms, and (2) they're not used for static libraries.)
 
    If the macro expansion needs the function to have been declared, it
    must include a declaration.  If it is not necessary for the symbol
 
    This is going to be compiler- and environment-specific, and may
    require some support at library build time, and/or "asm"
-   statements.
+   statements.  But through macro expansion and auxiliary functions,
+   we should be able to handle most things except #pragma.
 
    It's okay for this code to require that the library be built
    with the same compiler and compiler options throughout, but
    work, we'll only have memory leaks in a load/use/unload cycle.  If
    anyone (like, say, the OS vendor) complains about this, they can
    tell us how to get a shared library finalization function invoked
-   automatically.  */
+   automatically.
+
+   Currently there's --disable-delayed-initialization for preventing
+   the initialization from being delayed on UNIX, but that's mainly
+   just for testing the linker options for initialization, and will
+   probably be removed at some point.  */
 
 /* Helper macros.  */
 
@@ -194,8 +237,11 @@ static inline int k5_call_init_function(k5_init_t *i)
    multiple active threads mucking around in our library at this
    point.  So ignore the once_t object and just look at the flag.
 
-   XXX Could we have problems with memory coherence between
-   processors if we don't invoke mutex/once routines?  */
+   XXX Could we have problems with memory coherence between processors
+   if we don't invoke mutex/once routines?  Probably not, the
+   application code should already be coordinating things such that
+   the library code is not in use by this point, and memory
+   synchronization will be needed there.  */
 # define INITIALIZER_RAN(NAME) \
        (JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
 
@@ -206,6 +252,7 @@ static inline int k5_call_init_function(k5_init_t *i)
 /* Run initializer at load time, via GCC/C++ hook magic.  */
 
 # ifdef USE_LINKER_INIT_OPTION
+     /* Both gcc and linker option??  Favor gcc.  */
 #  define MAYBE_DUMMY_INIT(NAME)               \
        void JOIN__2(NAME, auxinit) () { }
 # else
@@ -273,9 +320,35 @@ typedef struct { int error; unsigned char did_run; } k5_init_t;
    matter what compiler we're using.  Do it the same way
    regardless.  */
 
-# define MAKE_FINI_FUNCTION(NAME)      \
+# ifdef __hpux
+
+     /* On HP-UX, we need this auxiliary function.  At dynamic load or
+       unload time (but *not* program startup and termination for
+       link-time specified libraries), the linker-indicated function
+       is called with a handle on the library and a flag indicating
+       whether it's being loaded or unloaded.
+
+       The "real" fini function doesn't need to be exported, so
+       declare it static.
+
+       As usual, the final declaration is just for syntactic
+       convenience, so the top-level invocation of this macro can be
+       followed by a semicolon.  */
+
+#  include <dl.h>
+#  define MAKE_FINI_FUNCTION(NAME)                                         \
+       static void NAME(void);                                             \
+       void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \
+       void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); }     \
+       static void NAME(void)
+
+# else /* not hpux */
+
+#  define MAKE_FINI_FUNCTION(NAME)     \
        void NAME(void)
 
+# endif
+
 #elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
 /* If we're using gcc, if the C++ support works, the compiler should
    build executables and shared libraries that support the use of