https://gcc.gnu.org/g:f31fd0972456d5d5d45ae404d42ca4594e3ac907
commit r17-5380-gf31fd0972456d5d5d45ae404d42ca4594e3ac907 Author: Robert Dubner <[email protected]> Date: Mon Oct 19 17:21:23 2026 -0400 cobol: Incorporate RUNPATH tags into gcobol-generated executables. Using RUNPATH tags is a better solution of just how a gcobol-generated executable goes about locating the .so file needed for execution. gcc/cobol/ChangeLog: * gcobolspec.cc (lang_specific_driver): Adjust the generation of libgcobol.spec. (lang_specific_pre_link): Likewise. libgcobol/ChangeLog: * Makefile.am: Incorporate new files. * Makefile.in: Regenerate. * configure: Regenerate. * configure.ac: Specify linker targets. * libgcobol.spec.in: Switch to LIBGCOBOL_RPATH_SPEC. * README.runpath: New file. * mk-rpath-spec.sh: New file. Diff: --- gcc/cobol/gcobolspec.cc | 11 ++++- libgcobol/Makefile.am | 13 +++++- libgcobol/Makefile.in | 19 +++++++-- libgcobol/README.runpath | 97 +++++++++++++++++++++++++++++++++++++++++++++ libgcobol/configure | 41 +++++++++++++++++-- libgcobol/configure.ac | 28 ++++++++++++- libgcobol/libgcobol.spec.in | 2 +- libgcobol/mk-rpath-spec.sh | 11 +++++ 8 files changed, 210 insertions(+), 12 deletions(-) diff --git a/gcc/cobol/gcobolspec.cc b/gcc/cobol/gcobolspec.cc index 10ba87e1af85..29718a7d565b 100644 --- a/gcc/cobol/gcobolspec.cc +++ b/gcc/cobol/gcobolspec.cc @@ -88,6 +88,9 @@ static std::vector<cl_decoded_option>new_opt; static bool need_libgcobol = true; static bool need_libcompat = false; // This one need for dialect mf or ibm static bool need_libposix = true; +/* Whether the link needs the runtime specs, independently of whether the + user has already supplied -lgcobol. */ +static bool need_runtime_specs = false; // #define NOISY 1 @@ -162,6 +165,7 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, bool saw_OPT_shared = false; bool verbose = false; + bool linking = true; // These flags indicate whether we need various libraries @@ -264,6 +268,7 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, case OPT_S: case OPT_fsyntax_only: case OPT_E: + linking = false; // With these options, no libraries need be loaded need_libgcobol = false; need_libdl = false; @@ -427,6 +432,8 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, need_libstdc = false; } + need_runtime_specs = linking && n_infiles != 0; + /* Second pass through arglist, transforming arguments as appropriate. */ append_arg(decoded_options[0]); /* Start with command name, of course. */ @@ -624,8 +631,8 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, int lang_specific_pre_link (void) { - if (need_libgcobol) - do_spec ("%:include(libgcobol.spec)"); + if (need_runtime_specs) + return do_spec ("%:include(libgcobol.spec)"); return 0; } diff --git a/libgcobol/Makefile.am b/libgcobol/Makefile.am index 0dfc706c18c1..402608fd68ed 100644 --- a/libgcobol/Makefile.am +++ b/libgcobol/Makefile.am @@ -45,6 +45,16 @@ if BUILD_LIBGCOBOL toolexeclib_LTLIBRARIES = libgcobol.la libgcobol_posix.la libgcobol_compat_gnu.la toolexeclib_DATA = libgcobol.spec +# Expand the installation directory at make time, after multilib and +# version-specific directory variables have acquired their final values. +# DESTDIR is deliberately excluded: it is a staging location, not a runtime +# search directory. config.status supplies the other spec substitutions. +libgcobol.spec: libgcobol.spec.conf Makefile $(srcdir)/mk-rpath-spec.sh + $(SHELL) $(srcdir)/mk-rpath-spec.sh "$(toolexeclibdir)" < $< > [email protected] + mv [email protected] $@ + +CLEANFILES = libgcobol.spec libgcobol.spec.tmp + libsubdir := $(libdir)/gcc/$(target_noncanonical)/$(version)$(MULTISUBDIR)/cobol libsubincludedir = $(libsubdir) @@ -229,6 +239,7 @@ LTCOBCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ .cbl.lo: $(LTCOBCOMPILE) $(COBFLAGS) $(MULTIFLAGS) -c -o $@ $< -EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map +EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map \ + mk-rpath-spec.sh testsuite/runpath.py README.runpath endif BUILD_LIBGCOBOL diff --git a/libgcobol/Makefile.in b/libgcobol/Makefile.in index b2174b41a898..9ad6aba9f810 100644 --- a/libgcobol/Makefile.in +++ b/libgcobol/Makefile.in @@ -148,7 +148,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = libgcobol.spec +CONFIG_CLEAN_FILES = libgcobol.spec.conf CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -357,6 +357,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ +LIBGCOBOL_RPATH_SPEC = @LIBGCOBOL_RPATH_SPEC@ LIBGCOBOL_VERSION = @LIBGCOBOL_VERSION@ LIBICONV = @LIBICONV@ LIBM = @LIBM@ @@ -479,6 +480,7 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) # Skip the whole process if we are not building libgcobol. @BUILD_LIBGCOBOL_TRUE@toolexeclib_LTLIBRARIES = libgcobol.la libgcobol_posix.la libgcobol_compat_gnu.la @BUILD_LIBGCOBOL_TRUE@toolexeclib_DATA = libgcobol.spec +@BUILD_LIBGCOBOL_TRUE@CLEANFILES = libgcobol.spec libgcobol.spec.tmp @BUILD_LIBGCOBOL_TRUE@libsubdir := $(libdir)/gcc/$(target_noncanonical)/$(version)$(MULTISUBDIR)/cobol @BUILD_LIBGCOBOL_TRUE@libsubincludedir = $(libsubdir) @BUILD_LIBGCOBOL_TRUE@libgcobol_la_SOURCES = \ @@ -640,7 +642,9 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) @BUILD_LIBGCOBOL_TRUE@LTCOBCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @BUILD_LIBGCOBOL_TRUE@ --mode=compile $(AM_COBC) $(AM_COBFLAGS) -@BUILD_LIBGCOBOL_TRUE@EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map +@BUILD_LIBGCOBOL_TRUE@EXTRA_DIST = libgcobol.map libgcobol_posix.map libgcobol_compat_gnu.map \ +@BUILD_LIBGCOBOL_TRUE@ mk-rpath-spec.sh testsuite/runpath.py README.runpath + all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am @@ -694,7 +698,7 @@ $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) distclean-hdr: -rm -f config.h stamp-h1 -libgcobol.spec: $(top_builddir)/config.status $(srcdir)/libgcobol.spec.in +libgcobol.spec.conf: $(top_builddir)/config.status $(srcdir)/libgcobol.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES) @@ -1030,6 +1034,7 @@ install-strip: mostlyclean-generic: clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -1143,6 +1148,14 @@ uninstall-am: uninstall-nobase_libsubincludeHEADERS \ .PRECIOUS: Makefile +# Expand the installation directory at make time, after multilib and +# version-specific directory variables have acquired their final values. +# DESTDIR is deliberately excluded: it is a staging location, not a runtime +# search directory. config.status supplies the other spec substitutions. +@[email protected]: libgcobol.spec.conf Makefile $(srcdir)/mk-rpath-spec.sh +@BUILD_LIBGCOBOL_TRUE@ $(SHELL) $(srcdir)/mk-rpath-spec.sh "$(toolexeclibdir)" < $< > [email protected] +@BUILD_LIBGCOBOL_TRUE@ mv [email protected] $@ + @BUILD_LIBGCOBOL_TRUE@$(LC_COPYDIR_BUILD)/%.cpy: ${srcdir}/compat/gnu/cpy/%.cpy @BUILD_LIBGCOBOL_TRUE@ mkdir -p `dirname $@` @BUILD_LIBGCOBOL_TRUE@ cp $< $@ diff --git a/libgcobol/README.runpath b/libgcobol/README.runpath new file mode 100644 index 000000000000..1dc65bbf149f --- /dev/null +++ b/libgcobol/README.runpath @@ -0,0 +1,97 @@ +Native Linux runtime search paths +================================ + +For native Linux builds with shared libraries enabled, libgcobol.spec adds +--enable-new-dtags and -rpath to ordinary GCobol links. The path is the +configured toolexeclibdir, expanded by make so that multilib and +--enable-version-specific-runtime-libs layouts are respected. No /opt path +is hard-coded. DESTDIR is not part of the path. + +The three runtime DSOs receive the same RUNPATH. This is necessary because +ELF DT_RUNPATH applies to an object's direct dependencies, not recursively +to the dependencies of those dependencies. Private dependencies installed +elsewhere still need their own suitable search paths. This change does not +automatically discover arbitrary directories containing private libxml2, +libiconv, or other external dependencies. + +The path is absolute. An executable can be moved independently of the +compiler, but moving the runtime installation requires relinking programs +(or explicitly overriding the loader search). $ORIGIN in a user executable +would refer to that executable's directory, not the compiler's directory. + +--disable-libgcobol-rpath restores the previous runtime-path behavior. +Non-Linux targets, cross builds, and builds without shared libraries do not +receive these new ELF options. Darwin's existing rpath flags are unchanged. +Static and static-PIE links receive no RUNPATH. -static-libgcobol may still +need RUNPATH for the shared POSIX/compatibility libraries. Shared COBOL +outputs receive RUNPATH too, for their own direct runtime dependencies. + +The driver now loads libgcobol.spec for links with inputs even when the +user explicitly supplied -lgcobol or libgcobol.a. It must not use the +"automatically add -lgcobol" decision to decide whether to load specs. +Compile-only, preprocess-only, assembly-only, relocatable, syntax-only, +-nostdlib and -nodefaultlibs invocations do not load the runtime specs. + +Packaging +--------- + +1. Keep libgcobol.spec and the runtime DSOs in their configured installation + locations. Reconfigure/rebuild for a different final prefix. Stage with + DESTDIR; never configure the staging directory as the final prefix. + +2. Stop registering the GCobol library directory in /etc/ld.so.conf.d and + stop exporting a global LD_LIBRARY_PATH. On upgrades, remove only the + obsolete configuration owned/generated by this package, using the + package manager's conffile migration machinery where applicable. Refresh + the loader cache after removing the old registration. Do not delete + unrelated or locally maintained loader configuration. + +3. Removing global registration prevents unrelated programs such as apt + from selecting GCobol's private libstdc++.so.6 or libgcc_s.so.1. RUNPATH + still makes ALL matching libraries in that directory eligible for the + GCobol program itself. Prefer system dependency packages when their ABI + is sufficient. If private GCC runtimes are necessary, bundle compatible + versions deliberately; this patch does not provide per-SONAME isolation. + +4. Build all packaged binaries and shared libraries against the oldest + supported glibc baseline. A RUNPATH cannot make a library requiring + GLIBC_2.38 run against glibc 2.35. Audit the compiler executables and any + separately packaged tools too: this patch changes generated COBOL links + and libgcobol DSOs, not the bootstrap compiler/tool link flags. + +5. Previously linked COBOL executables do not acquire RUNPATH on upgrade. + Rebuild those executables before relying on removal of the old global + configuration. Include this change in the package's migration notes. + +Regression checks +----------------- + +Run the mechanism tests on Linux with a C compiler and readelf: + + python3 libgcobol/testsuite/runpath.py + +These exercise GCC spec expansion and the real ELF loader, including a +negative transitive-dependency test, but do not build the COBOL compiler. + +After building and installing the patched compiler into a clean GNU/Linux +container with no GCobol loader configuration, run, for example: + + python3 libgcobol/testsuite/runpath.py \ + --gcobol /opt/gcobol/bin/gcobol \ + --runtime-dir /opt/gcobol/lib64 + +Use the actual configured runtime directory. This tests ordinary linking, +explicit -lgcobol, the mf compatibility dialect, -static-libgcobol, separate +compilation, shared output, driver suppression options, all runtime DSO +tags, and execution with the loader cache inhibited. It prints the actual +loaded libraries for review. Static-libgcobol requires static archives to +have been built/installed. Dependencies requiring ABI symbols missing +from the target system are a test failure, not a reason to restore global +loader registration. + +In the package-install/upgrade test, also compare `ldd /usr/bin/apt` before +and after installation and run `apt --version`. Its libstdc++ and libgcc_s +must remain the system copies. Test fresh installation and upgrade from a +package that registered /opt/gcobol/lib64, plus removal of the new package. +Package scripts are maintained outside this upstream GCC source tree; the +exact migration edits must be made and tested in that packaging repository. diff --git a/libgcobol/configure b/libgcobol/configure index 9b26aa99355d..a03c8cd67ab6 100755 --- a/libgcobol/configure +++ b/libgcobol/configure @@ -646,6 +646,7 @@ LIBQUADLIB LIBQUADSPEC LIBXML2_LIBS LIBXML2_CPPFLAGS +LIBGCOBOL_RPATH_SPEC extra_ldflags_libgcobol LIBGCOBOL_VERSION BUILD_LIBGCOBOL_FALSE @@ -807,6 +808,7 @@ with_toolexeclibdir enable_rpath with_libiconv_prefix with_libiconv_type +enable_libgcobol_rpath with_target_libxml2 with_target_libxml2_include with_target_libxml2_lib @@ -1464,6 +1466,9 @@ Optional Features: install libraries with @rpath/library-name, requires rpaths to be added to executables --disable-rpath do not hardcode runtime library paths + --disable-libgcobol-rpath + do not embed the native Linux libgcobol installation + directory in RUNPATH --disable-libquadmath disable libquadmath support for libgcobol Optional Packages: @@ -12220,7 +12225,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12223 "configure" +#line 12228 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12326,7 +12331,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 12329 "configure" +#line 12334 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17689,6 +17694,34 @@ case $host in esac +# Do not add ELF linker options on other targets, or embed build-host paths +# in programs produced by a cross compiler. Native Linux installations can +# find their runtime without changing the system-wide loader configuration. +# Check whether --enable-libgcobol-rpath was given. +if test "${enable_libgcobol_rpath+set}" = set; then : + enableval=$enable_libgcobol_rpath; case $enableval in + yes|no) ;; + *) as_fn_error $? "--enable-libgcobol-rpath expects yes or no" "$LINENO" 5 ;; + esac +else + enable_libgcobol_rpath=yes +fi + +LIBGCOBOL_RPATH_SPEC= +case $host in + *-*-linux*) + if test x$enable_libgcobol_rpath = xyes \ + && test x$enable_shared = xyes \ + && { test -z "$with_cross_host" || test x$with_cross_host = xno; }; then + LIBGCOBOL_RPATH_SPEC='%{!static:%{!static-pie:--enable-new-dtags -rpath @LIBGCOBOL_RUNTIME_DIR@}}' + # RUNPATH is not transitive. Each runtime DSO needs its own entry + # for dependencies installed alongside it (for example libquadmath). + extra_ldflags_libgcobol="$extra_ldflags_libgcobol"' -Wl,--enable-new-dtags -Wl,-rpath,$(toolexeclibdir)' + fi + ;; +esac + + @@ -18420,7 +18453,7 @@ fi SPEC_LIBGCOBOL_DEPS="$LIBS" -ac_config_files="$ac_config_files Makefile libgcobol.spec" +ac_config_files="$ac_config_files Makefile libgcobol.spec.conf:libgcobol.spec.in" { $as_echo "$as_me:${as_lineno-$LINENO}: libgcobol has been configured." >&5 @@ -19546,7 +19579,7 @@ do "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "libgcobol.spec") CONFIG_FILES="$CONFIG_FILES libgcobol.spec" ;; + "libgcobol.spec.conf") CONFIG_FILES="$CONFIG_FILES libgcobol.spec.conf:libgcobol.spec.in" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/libgcobol/configure.ac b/libgcobol/configure.ac index 5baf9f12ed09..9c9295483429 100644 --- a/libgcobol/configure.ac +++ b/libgcobol/configure.ac @@ -204,6 +204,32 @@ case $host in esac AC_SUBST(extra_ldflags_libgcobol) +# Do not add ELF linker options on other targets, or embed build-host paths +# in programs produced by a cross compiler. Native Linux installations can +# find their runtime without changing the system-wide loader configuration. +AC_ARG_ENABLE([libgcobol-rpath], + [AS_HELP_STRING([--disable-libgcobol-rpath], + [do not embed the native Linux libgcobol installation directory in RUNPATH])], + [case $enableval in + yes|no) ;; + *) AC_MSG_ERROR([--enable-libgcobol-rpath expects yes or no]) ;; + esac], + [enable_libgcobol_rpath=yes]) +LIBGCOBOL_RPATH_SPEC= +case $host in + *-*-linux*) + if test x$enable_libgcobol_rpath = xyes \ + && test x$enable_shared = xyes \ + && { test -z "$with_cross_host" || test x$with_cross_host = xno; }; then + LIBGCOBOL_RPATH_SPEC='%{!static:%{!static-pie:--enable-new-dtags -rpath @LIBGCOBOL_RUNTIME_DIR@}}' + # RUNPATH is not transitive. Each runtime DSO needs its own entry + # for dependencies installed alongside it (for example libquadmath). + extra_ldflags_libgcobol="$extra_ldflags_libgcobol"' -Wl,--enable-new-dtags -Wl,-rpath,$(toolexeclibdir)' + fi + ;; +esac +AC_SUBST(LIBGCOBOL_RPATH_SPEC) + AC_CHECK_HEADERS_ONCE(floatingpoint.h ieeefp.h fenv.h fptrap.h \ complex.h stdlib.h errno.h) @@ -388,7 +414,7 @@ AC_SUBST(SPEC_LIBGCOBOL_DEPS) AC_CONFIG_FILES([ Makefile -libgcobol.spec +libgcobol.spec.conf:libgcobol.spec.in ]) AC_MSG_NOTICE([libgcobol has been configured.]) diff --git a/libgcobol/libgcobol.spec.in b/libgcobol/libgcobol.spec.in index 461587d1fb8e..470ff17dfada 100644 --- a/libgcobol/libgcobol.spec.in +++ b/libgcobol/libgcobol.spec.in @@ -5,4 +5,4 @@ # %rename lib liborig -*lib: @LIBQUADSPEC@ @LIBM@ %(liborig) +*lib: @LIBGCOBOL_RPATH_SPEC@ @LIBQUADSPEC@ @LIBM@ %(liborig) diff --git a/libgcobol/mk-rpath-spec.sh b/libgcobol/mk-rpath-spec.sh new file mode 100644 index 000000000000..c37446dcff31 --- /dev/null +++ b/libgcobol/mk-rpath-spec.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is part of GCC, distributed under the GNU General Public License, +# version 3 or (at your option) any later version. See COPYING3. + +# Escape a literal installation directory for GCC specs, then for a sed +# replacement. In particular, whitespace must remain in a single argument +# and '%' must not introduce a spec expansion. +test "$#" = 1 || exit 1 +runtime_dir=$(printf '%s\n' "$1" | sed 's/[%]/%%/g; s/[\\ \t]/\\&/g; s/[\\&|]/\\&/g') || exit 1 +sed "s|@LIBGCOBOL_RUNTIME_DIR@|$runtime_dir|g"
