These changes were tested with an Ubuntu 22.04 x86_64 --enable-languages=all bootstrapped multilib build.
From: Robert Dubner <[email protected]> Date: Wed, 7 Oct 2026 18:35:08 -0400 Subject: [PATCH] cobol: Establish libgcobol symbol versioning. This patch establishes a baseline of @GCOBOL_17.1 for exported symbols in the libgcobol.so, libgcobol_posix.so, and libgcobol_compat_gnu.so shared objects. libgcobol/ChangeLog: * Makefile.am: Include libgcobol.map, libgcobol_compat_gnu.map, and libgcobol_posix.map as -Wl,--version-script inputs. * Makefile.in: Regenerated. * compat/gnu/lib/cbl_gpi.cc (__gg__get_module_names): Minor change to how the external is declared and referenced. (callstack): Likewise. * libgcobol.cc (NO_RDIGITS): Lengthy comment about "How to use symbol versioning". (__gg__module_name_pop): Likewise. * libgcobol.map: New file. * libgcobol_compat_gnu.map: New file. * libgcobol_posix.map: New file. --- libgcobol/Makefile.am | 19 +- libgcobol/Makefile.in | 18 +- libgcobol/compat/gnu/lib/cbl_gpi.cc | 5 +- libgcobol/libgcobol.cc | 72 ++++++- libgcobol/libgcobol.map | 297 ++++++++++++++++++++++++++++ libgcobol/libgcobol_compat_gnu.map | 20 ++ libgcobol/libgcobol_posix.map | 19 ++ 7 files changed, 433 insertions(+), 17 deletions(-) create mode 100644 libgcobol/libgcobol.map create mode 100644 libgcobol/libgcobol_compat_gnu.map create mode 100644 libgcobol/libgcobol_posix.map diff --git a/libgcobol/Makefile.am b/libgcobol/Makefile.am index 8cbddee682d..0dfc706c18c 100644 --- a/libgcobol/Makefile.am +++ b/libgcobol/Makefile.am @@ -190,8 +190,10 @@ $(LP_COPYDIR_BUILD)/%.cpy: ${srcdir}/posix/cpy/%.cpy libgcobol_la_LINK = $(CXXLINK) $(libgcobol_la_LDFLAGS) version_arg = -version-info $(LIBGCOBOL_VERSION) libgcobol_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ - $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) -libgcobol_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) + $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ + -Wl,--version-script=$(srcdir)/libgcobol.map +libgcobol_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ + $(srcdir)/libgcobol.map # Rules for libgcobol_posix.so and libgcobol_compat_gnu.so, which have # COBOL sources. They require gcobol and libgcobol to have already @@ -206,16 +208,17 @@ libgcobol_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) libgcobol_posix_la_LINK = $(CXXLINK) $(libgcobol_posix_la_LDFLAGS) libgcobol_posix_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ - $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) + $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ + -Wl,--version-script=$(srcdir)/libgcobol_posix.map libgcobol_posix_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ - $(LP_COPYBOOKS) + $(LP_COPYBOOKS) $(srcdir)/libgcobol_posix.map libgcobol_compat_gnu_la_LINK = $(CXXLINK) $(libgcobol_compat_gnu_la_LDFLAGS) libgcobol_compat_gnu_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ - $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) + $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ + -Wl,--version-script=$(srcdir)/libgcobol_compat_gnu.map libgcobol_compat_gnu_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ - $(LC_COPYBOOKS) - + $(LC_COPYBOOKS) $(srcdir)/libgcobol_compat_gnu.map LTCOBCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(AM_COBC) $(AM_COBFLAGS) @@ -226,6 +229,6 @@ 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 endif BUILD_LIBGCOBOL diff --git a/libgcobol/Makefile.in b/libgcobol/Makefile.in index 72b08363c78..2c26a49e445 100644 --- a/libgcobol/Makefile.in +++ b/libgcobol/Makefile.in @@ -604,9 +604,12 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) @BUILD_LIBGCOBOL_TRUE@libgcobol_la_LINK = $(CXXLINK) $(libgcobol_la_LDFLAGS) @BUILD_LIBGCOBOL_TRUE@version_arg = -version-info $(LIBGCOBOL_VERSION) @BUILD_LIBGCOBOL_TRUE@libgcobol_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ -@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) +@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ +@BUILD_LIBGCOBOL_TRUE@ -Wl,--version-script=$(srcdir)/libgcobol.map + +@BUILD_LIBGCOBOL_TRUE@libgcobol_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ +@BUILD_LIBGCOBOL_TRUE@ $(srcdir)/libgcobol.map -@BUILD_LIBGCOBOL_TRUE@libgcobol_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) # Rules for libgcobol_posix.so and libgcobol_compat_gnu.so, which have # COBOL sources. They require gcobol and libgcobol to have already @@ -619,21 +622,24 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) # Because CFLAGS means "C flags", COBFLAGS means "COBOL flags". @BUILD_LIBGCOBOL_TRUE@libgcobol_posix_la_LINK = $(CXXLINK) $(libgcobol_posix_la_LDFLAGS) @BUILD_LIBGCOBOL_TRUE@libgcobol_posix_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ -@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) +@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ +@BUILD_LIBGCOBOL_TRUE@ -Wl,--version-script=$(srcdir)/libgcobol_posix.map @BUILD_LIBGCOBOL_TRUE@libgcobol_posix_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ -@BUILD_LIBGCOBOL_TRUE@ $(LP_COPYBOOKS) +@BUILD_LIBGCOBOL_TRUE@ $(LP_COPYBOOKS) $(srcdir)/libgcobol_posix.map @BUILD_LIBGCOBOL_TRUE@libgcobol_compat_gnu_la_LINK = $(CXXLINK) $(libgcobol_compat_gnu_la_LDFLAGS) @BUILD_LIBGCOBOL_TRUE@libgcobol_compat_gnu_la_LDFLAGS = $(LTLDFLAGS) $(LIBQUADLIB) $(LTLIBICONV) \ -@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) +@BUILD_LIBGCOBOL_TRUE@ $(extra_ldflags_libgcobol) $(LIBS) $(LIBXML2_LIBS) $(version_arg) \ +@BUILD_LIBGCOBOL_TRUE@ -Wl,--version-script=$(srcdir)/libgcobol_compat_gnu.map @BUILD_LIBGCOBOL_TRUE@libgcobol_compat_gnu_la_DEPENDENCIES = libgcobol.spec $(LIBQUADLIB_DEP) \ -@BUILD_LIBGCOBOL_TRUE@ $(LC_COPYBOOKS) +@BUILD_LIBGCOBOL_TRUE@ $(LC_COPYBOOKS) $(srcdir)/libgcobol_compat_gnu.map @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 all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am diff --git a/libgcobol/compat/gnu/lib/cbl_gpi.cc b/libgcobol/compat/gnu/lib/cbl_gpi.cc index 4d414ba169a..f83b054d7b7 100644 --- a/libgcobol/compat/gnu/lib/cbl_gpi.cc +++ b/libgcobol/compat/gnu/lib/cbl_gpi.cc @@ -103,11 +103,12 @@ enum cbl_backtrace_flags CBL_BACKTRACE_DATA31 = 1 << 24 }; +extern "C" const std::vector<std::string> &__gg__get_module_names(); + static std::vector<std::string> callstack() { - const std::vector<std::string> &__gg__get_module_names(), - &names = __gg__get_module_names(); + const std::vector<std::string> &names = __gg__get_module_names(); const char *s = NULL; std::vector<std::string> ret; diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc index b698e16e181..6ee5628ed88 100644 --- a/libgcobol/libgcobol.cc +++ b/libgcobol/libgcobol.cc @@ -8,7 +8,6 @@ * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above - * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. @@ -82,6 +81,76 @@ #define NO_RDIGITS (0) +/* How to use symbol versioning. + (Disclaimer: As of this writing, I have gotten this far looking at + documentation. The .map files seem to work; I haven't yet tried to + incorporate altered versions of existing functions.) + + Imagine we discover a bug in __gg__acos(), but it is a bug that somebody + is counting on. That's kind of absurd, but ride with me, here. + + We want to create a second version of __gg__acos() for GCC17.2 that will + become the default in libgcobol.so going forward. But we need the library + to continue to support the one released with GCC17.1 because people are + still using the older compiler, or running executables created with the + older compiler, even in the face up updating their libgcobol.so file. + + The process: + + Rename the __gg__acos() routine to __gg__acos_17_1(). The contents of that + routine must stay functionally the same, for ever and ever. + + Write the new __gg__acos_17_2() routine. + + The libgcobol/libgcobol.map file needs to be modified as well: + + GCOBOL_17.1 + { + global: + // The entire list, including __gg__acos, is left alone + + local: + *; + }; + + GCOBOL_17.2 + { + global: + __gg__acos; + } GCOBOL_17.1; + + There are two ways of routing the symbol versions in the source code. + + First method: + + Add the following directives at file scope in the .cc file that contains + __gg__acos_17_1() and __gg__acos_17_1(): + + __asm__(".symver __gg__acos_17_1,__gg__acos@GCOBOL_17.1"); + __asm__(".symver __gg__acos_17_2,__gg__acos@@GCOBOL_17.2"); + + Second method: + + extern "C" void + __attribute__((symver("__gg__acos@GCOBOL_17.1"))) + __gg__acos_17_1() + { + // Preserved implementation. + } + + extern "C" void + __attribute__((symver("__gg__acos@@GCOBOL_17.2"))) + __gg__acos_17_2() + { + // New implementation. + } + + In either case, those specify that somebody trying to link to + __gg__acos@GCOBOL_17.1 will actually link to __gg__acos_17_1(). The @@ + in __gg__acos@@GCOBOL_17.2 means that somebody linking to __gg__acos() + will actually be linked to __gg__acos_17_2(). + + And that's supposedly how symbol versioning works. */ static inline char * as_chars(unsigned char *p) @@ -12003,6 +12072,7 @@ __gg__module_name_pop() module_name_stack.pop_back(); } +extern "C" const std::vector<std::string> & __gg__get_module_names() { diff --git a/libgcobol/libgcobol.map b/libgcobol/libgcobol.map new file mode 100644 index 00000000000..5b9e4ea98c5 --- /dev/null +++ b/libgcobol/libgcobol.map @@ -0,0 +1,297 @@ +GCOBOL_17.1 + { + global: + __gg__abs; + __gg__accept; + __gg__accept_arg_value; + __gg__accept_envar; + __gg__acos; + __gg__allocate; + __gg__alphabet_create; + __gg__alphabet_use; + __gg__annuity; + __gg__asin; + __gg__assign_value_from_stack; + __gg__atan; + __gg__binary_to_packed; + __gg__binary_to_string_ascii; + __gg__binary_to_string_ebcdic; + __gg__bitop; + __gg__bitwise_op; + __gg__byte_length; + __gg__call_parameter_count; + __gg__call_parameter_lengths; + __gg__call_parameter_signature; + __gg__call_warning_message; + __gg__char; + __gg__check_fatal_exception; + __gg__classify; + __gg__clear_exception; + __gg__codeset_figurative_constants; + __gg__combined_datetime; + __gg__compare_binary_to_string; + __gg__compare_field_class; + __gg__compare_numdisp_alpha; + __gg__compare_numeric_all; + __gg__compare_string_1; + __gg__compare_string_1a; + __gg__compare_string_1e; + __gg__compare_string_2; + __gg__compare_string_2a; + __gg__compare_string_4; + __gg__compare_string_4a; + __gg__compare_string_all; + __gg_compare_string_different; + __gg__compute_fixed; + __gg__compute_float; + __gg__concat; + __gg__conditional_stash; + __gg__conditional_stash_float; + __gg__convert; + __gg__cos; + __gg__currency_sign; + __gg__currency_sign_init; + __gg__current_date; + __gg__data_; + __gg__data__file_status; + __gg__data__literally_one; + __gg__data__literally_zero; + __gg__data_nulls; + __gg__date_of_integer; + __gg__date_to_yyyymmdd; + __gg__day_of_integer; + __gg__day_to_yyyyddd; + __gg__deallocate; + __gg__decimal_point_is_comma; + __gg__default_compute_error; + __gg__dialects; + __gg__display; + __gg__display_clean; + __gg__dividef1_phase2; + __gg__dividef23; + __gg__dividef45; + __gg__dp2bin; + __gg__e; + __gg__entry_index; + __gg__exception_code; + __gg__exception_file_name; + __gg__exception_file_status; + __gg__exception_line_number; + __gg__exception_paragraph; + __gg__exception_pop; + __gg__exception_program_id; + __gg__exception_push; + __gg__exception_section; + __gg__exception_source_file; + __gg__exception_statement; + __gg__exit_address; + __gg__exp; + __gg__exp10; + __gg__factorial; + __gg__file_close; + __gg__file_delete; + __gg__file_init; + __gg__file_open; + __gg__file_read; + __gg__file_remove; + __gg__file_rewrite; + __gg__file_sort_ff_input; + __gg__file_sort_ff_output; + __gg__file_start; + __gg__file_stash; + __gg__file_write; + __gg__find_string; + __gg__float128_from_int128; + __gg__float32_from_128; + __gg__float32_from_64; + __gg__float32_from_int128; + __gg__float64_from_128; + __gg__float64_from_int128; + __gg__formatted_current_date; + __gg__formatted_date; + __gg__formatted_datetime; + __gg__formatted_time; + __gg__fprintf_stderr; + __gg__fracdigits; + __gg__fraction_part; + __gg__func_exception_file; + __gg__func_exception_location; + __gg__func_exception_statement; + __gg__func_exception_status; + __gg__function_handle_from_literal; + __gg__function_handle_from_name; + __gg__get_argc; + __gg__get_argv; + __gg__get_command_line; + __gg__get_date_dow; + __gg__get_date_hhmmssff; + __gg__get_date_yyddd; + __gg__get_date_yymmdd; + __gg__get_date_yyyymmdd; + __gg__get_env_name; + __gg__get_env_value; + __gg__get_file_descriptor; + __gg__get_module_names; + __gg__get_yyyyddd; + __gg__globals_are_initialized; + __gg__hex_of; + __gg__highest_algebraic; + __gg__initialization_values; + __gg__initialize_variable; + __gg__initialize_variable_clean; + __gg__init_program_state; + __gg__inspect_format_1; + __gg__inspect_format_1_sbc; + __gg__inspect_format_2; + __gg__inspect_format_2_sbc; + __gg__inspect_format_4; + __gg__inspect_format_4_sbc; + __gg__int128_to_ascii_numeric_display; + __gg__int128_to_field; + __gg__int128_to_int128_rounded; + __gg__int128_to_qualified_field; + __gg__integer; + __gg__integer_of_date; + __gg__integer_of_day; + __gg__integer_of_formatted_date; + __gg__integer_part; + __gg__is_canceled; + __gg__is_float_infinite; + __gg__length; + __gg__locale_compare; + __gg__locale_date; + __gg__locale_time; + __gg__locale_time_from_seconds; + __gg__log; + __gg__log10; + __gg__lower_case; + __gg__lowest_algebraic; + __gg__main_called; + __gg__match_exception; + __gg__max; + __gg__mean; + __gg__median; + __gg__merge_files; + __gg__midrange; + __gg__min; + __gg__mirror_range; + __gg__mod; + __gg__module_name; + __gg__module_name_pop; + __gg__module_name_push; + __gg__move; + __gg__move_literala; + __gg__move_stash_acquire; + __gg__move_stash_release; + __gg__multiplyf1_phase1; + __gg__multiplyf1_phase2; + __gg__multiplyf2; + __gg__nop; + __gg__numval; + __gg__numval_c; + __gg__numval_f; + __gg__onetime_initialization; + __gg__ord; + __gg__ord_max; + __gg__ord_min; + __gg__parser_set_conditional; + __gg__pi; + __gg__pop_local_variables; + __gg__pop_program_state; + __gg__pow; + __gg__power_of_ten; + __gg__present_value; + __gg__process_compute_error; + __gg__prohibited; + __gg__propagate_linkage_offsets; + __gg__pseudo_return_bookmark; + __gg__pseudo_return_flush; + __gg__pseudo_return_pop; + __gg__pseudo_return_push; + __gg__psz_to_alpha_move; + __gg__push_local_variable; + __gg__push_program_state; + __gg__random; + __gg__random_next; + __gg__range; + __gg__refer_from_psz; + __gg__refer_from_string; + __gg__rem; + __gg__resolve_literal_call_descriptor; + __gg__reverse; + __gg__scale_by_power_of_ten_1; + __gg__scale_by_power_of_ten_2; + __gg__seconds_from_formatted_time; + __gg__seconds_past_midnight; + __gg__set_arg_num; + __gg__set_envar; + __gg__set_env_name; + __gg__set_env_value; + __gg__set_exception_call; + __gg__set_exception_code; + __gg__set_exception_environment; + __gg__setop_compare; + __gg__set_pointer; + __gg__set_program_list; + __gg__set_program_name; + __gg__set_user_status; + __gg__sign; + __gg__sin; + __gg__sleep; + __gg__sort_table; + __gg__sort_workfile; + __gg__sqrt; + __ggsr__debug_contents; + __ggsr__debug_item; + __ggsr__debug_line; + __ggsr__debug_name; + __ggsr__debug_sub_1; + __ggsr__debug_sub_2; + __ggsr__debug_sub_3; + __ggsr___file_status; + __ggsr__high_values; + __ggsr___literally_zero; + __ggsr__low_values; + __ggsr__nulls; + __ggsr__quotes; + __ggsr__spaces; + __ggsr__upsi_0; + __ggsr__zeros; + __gg__standard_deviation; + __gg__stash_argc_argv; + __gg__string; + __gg__string_to_alpha_edited; + __gg__substitute; + __gg__sum; + __gg__tan; + __gg__test_date_yyyymmdd; + __gg__test_day_yyyyddd; + __gg__test_formatted_datetime; + __gg__test_numval; + __gg__test_numval_c; + __gg__test_numval_f; + __gg__to_be_canceled; + __gg__trim_1; + __gg__trim_a; + __gg__unique_prog_id; + __gg__unstring; + __gg__upper_case; + __gg__variables_to_init; + __gg__variance; + __gg__when_compiled; + __gg__xml_parse; + __gg__year_to_yyyy; + + __compat_file_status_word; + + posix_clock_gettime; + posix_errno; + posix_fstat; + posix_localtime; + posix_lseek; + posix_open; + posix_stat; + + local: + *; + }; diff --git a/libgcobol/libgcobol_compat_gnu.map b/libgcobol/libgcobol_compat_gnu.map new file mode 100644 index 00000000000..07b9665da12 --- /dev/null +++ b/libgcobol/libgcobol_compat_gnu.map @@ -0,0 +1,20 @@ +GCOBOL_17.1 + { + global: + + cbl_alloc_mem; + cbl_check_file_exist; + cbl_close_file; + cbl_create_file; + cbl_delete_file; + cbl_free_mem; + cbl_get_program_info; + cbl_open_file; + cbl_read_file; + cbl_write_file; + + stored$char$length; + + local: + *; + }; diff --git a/libgcobol/libgcobol_posix.map b/libgcobol/libgcobol_posix.map new file mode 100644 index 00000000000..64821325ee7 --- /dev/null +++ b/libgcobol/libgcobol_posix.map @@ -0,0 +1,19 @@ +GCOBOL_17.1 + { + global: + + posix$close; + posix$errno; + posix$fstat; + posix$ftruncate; + posix$localtime; + posix$lseek; + posix$open; + posix$read; + posix$stat; + posix$unlink; + posix$write; + + local: + *; + }; -- 2.34.1
