Hi. I've started working on introduction of a new shared library for GCOV. Justification is PR84107 where libgcov does not properly work properly for multiple DSOs.
I created a working prototype and as it's my first time I'm creating a shared library in GCC, I've got multiple questions: 1) currently both libgcov.so and libgcov.a are installed in an install folder and when using: gcc main.c -lcov the static one is preferred. Do we need an option -static-libgcov? 2) I created libgcc/config/t-libgcov-elf file. It's currently added just for: x86_64-*-linux*) What's the right placement of content added to t-libgcov-elf? 3) Should I come up with a symbol versioning of the libgcov API? I'm attaching current patch, so any comment is welcomed. Thanks, Martin
>From 3ffb36795ea6999be34ce079c435b391d5db62cb Mon Sep 17 00:00:00 2001 From: marxin <mli...@suse.cz> Date: Fri, 3 Aug 2018 11:14:15 +0200 Subject: [PATCH] Add libgcov.so: work in progress. --- libgcc/Makefile.in | 18 +++++++++++++- libgcc/config.host | 2 +- libgcc/config/t-libgcov-elf | 48 +++++++++++++++++++++++++++++++++++++ libgcc/libgcov-profiler.c | 6 ++--- libgcc/libgcov.h | 14 +++++------ 5 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 libgcc/config/t-libgcov-elf diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index 0c5b264f717..530bc0dced4 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -944,7 +944,7 @@ libgcc.a libgcov.a libunwind.a libgcc_eh.a: all: libgcc.a ifeq ($(enable_gcov),yes) -all: libgcov.a +all: libgcov.a libgcov$(SHLIB_EXT) endif ifneq ($(LIBUNWIND),) @@ -1006,6 +1006,18 @@ libunwind$(SHLIB_EXT): $(libunwind-s-objects) $(extra-parts) @shlib_base_name@,libunwind,$(subst \ @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIBUNWIND_LINK)))))) +libgcov$(SHLIB_EXT): $(libgcov-objects) libgcc_s$(SHLIB_EXT) + # @multilib_flags@ is still needed because this may use + # $(GCC_FOR_TARGET) and $(LIBGCC2_CFLAGS) directly. + # @multilib_dir@ is not really necessary, but sometimes it has + # more uses than just a directory name. + $(mkinstalldirs) $(MULTIDIR) + $(subst @multilib_flags@,$(CFLAGS) -B./,$(subst \ + @multilib_dir@,$(MULTIDIR),$(subst \ + @shlib_objs@,$(objects),$(subst \ + @shlib_base_name@,libgcov,$(subst \ + @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIBGCOV_LINK)))))) + endif # Build the standard GCC startfiles and endfiles. @@ -1172,6 +1184,10 @@ ifeq ($(enable_gcov),yes) $(INSTALL_DATA) libgcov.a $(DESTDIR)$(inst_libdir)/ chmod 644 $(DESTDIR)$(inst_libdir)/libgcov.a $(RANLIB) $(DESTDIR)$(inst_libdir)/libgcov.a + + $(subst @multilib_dir@,$(MULTIDIR),$(subst \ + @shlib_base_name@,libgcov,$(subst \ + @shlib_slibdir_qual@,$(MULTIOSSUBDIR),$(SHLIBGCOV_INSTALL)))) endif parts="$(INSTALL_PARTS)"; \ diff --git a/libgcc/config.host b/libgcc/config.host index 18cabaf24f6..dca583b8110 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -659,7 +659,7 @@ i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-gnu* | i[34567]86-*-kopensolaris*-gnu) ;; x86_64-*-linux*) extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" - tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprulesi t-libgcov-elf" tm_file="${tm_file} i386/elf-lib.h" md_unwind_header=i386/linux-unwind.h ;; diff --git a/libgcc/config/t-libgcov-elf b/libgcc/config/t-libgcov-elf new file mode 100644 index 00000000000..19ef3db47ab --- /dev/null +++ b/libgcc/config/t-libgcov-elf @@ -0,0 +1,48 @@ +# Copyright (C) 2004-2018 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Build libunwind for ELF with the GNU linker. + +SHLIB_SOLINK = @shlib_base_name@.so +SHLIB_OBJS = @shlib_objs@ +SHLIB_DIR = @multilib_dir@ +SHLIB_SLIBDIR_QUAL = @shlib_slibdir_qual@ + +SHLIBGCOV_SOVERSION = 1 +SHLIBGCOV_SONAME = @shlib_base_name@.so.$(SHLIBGCOV_SOVERSION) + +SHLIBGCOV_LINK = $(CC) $(LIBGCC2_CFLAGS) -shared \ + -nodefaultlibs -Wl,-h,$(SHLIBGCOV_SONAME) \ + -Wl,-z,text -Wl,-z,defs -o $(SHLIB_DIR)/$(SHLIBGCOV_SONAME).tmp \ + @multilib_flags@ $(SHLIB_OBJS) -lc -lgcc && \ + rm -f $(SHLIB_DIR)/$(SHLIB_SOLINK) && \ + if [ -f $(SHLIB_DIR)/$(SHLIBGCOV_SONAME) ]; then \ + mv -f $(SHLIB_DIR)/$(SHLIBGCOV_SONAME) \ + $(SHLIB_DIR)/$(SHLIBGCOV_SONAME).backup; \ + else true; fi && \ + mv $(SHLIB_DIR)/$(SHLIBGCOV_SONAME).tmp \ + $(SHLIB_DIR)/$(SHLIBGCOV_SONAME) && \ + $(LN_S) $(SHLIBGCOV_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK) + +SHLIBGCOV_INSTALL = \ + $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL); \ + $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIBGCOV_SONAME) \ + $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIBGCOV_SONAME); \ + rm -f $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK); \ + $(LN_S) $(SHLIBGCOV_SONAME) \ + $(DESTDIR)$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK) diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c index 7e208d75d86..df20e73b4e1 100644 --- a/libgcc/libgcov-profiler.c +++ b/libgcc/libgcov-profiler.c @@ -271,12 +271,12 @@ __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value) #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) __thread #endif -gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN; +gcov_type *__gcov_indirect_call_topn_counters; #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) __thread #endif -void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN; +void *__gcov_indirect_call_topn_callee; #ifdef TARGET_VTABLE_USES_DESCRIPTORS #define VTABLE_USES_DESCRIPTORS 1 @@ -344,7 +344,7 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) #ifdef L_gcov_time_profiler /* Counter for first visit of each function. */ -gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN; +gcov_type __gcov_time_profiler_counter; #endif diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h index 21422873cf2..2e445b60bba 100644 --- a/libgcc/libgcov.h +++ b/libgcc/libgcov.h @@ -234,10 +234,10 @@ extern struct gcov_master __gcov_master; extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN; /* Register a new object file module. */ -extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN; +extern void __gcov_init (struct gcov_info *); /* GCOV exit function registered via a static destructor. */ -extern void __gcov_exit (void) ATTRIBUTE_HIDDEN; +extern void __gcov_exit (void); /* Function to reset all counters to 0. Both externally visible (and overridable) and internal version. */ @@ -247,19 +247,19 @@ extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN; extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN; /* The merge function that just sums the counters. */ -extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_add (gcov_type *, unsigned); /* The merge function to select the minimum valid counter value. */ -extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_time_profile (gcov_type *, unsigned); /* The merge function to choose the most common value. */ -extern void __gcov_merge_single (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_single (gcov_type *, unsigned); /* The merge function that just ors the counters together. */ -extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_ior (gcov_type *, unsigned); /* The merge function is used for topn indirect call counters. */ -extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; +extern void __gcov_merge_icall_topn (gcov_type *, unsigned); /* The profiler functions. */ extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned); -- 2.18.0