Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 10 May 2018 18:21:51 +0200
From:      Tijl Coosemans <tijl@FreeBSD.org>
To:        Steve Kargl <sgk@troutmask.apl.washington.edu>
Cc:        freebsd-current@freebsd.org, freebsd-hackers@freebsd.org, freebsd-ports@freebsd.org
Subject:   Re: Runtime loader issue
Message-ID:  <20180510182151.409b7fb8@kalimero.tijl.coosemans.org>
In-Reply-To: <20180509234551.GA39526@troutmask.apl.washington.edu>
References:  <20180509234551.GA39526@troutmask.apl.washington.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
--MP_/nD2m3FmfImDp2u+ur0Mr4sg
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On Wed, 9 May 2018 16:45:51 -0700 Steve Kargl <sgk@troutmask.apl.washington.edu> wrote:
> In review PR 228007, it came to my attention some individuals are
> mis-characterizing a FreeBSD loader issue as "gfortran's FreeBSD
> issue".  See
>  
> https://lists.freebsd.org/pipermail/freebsd-fortran/2018-May/000124.html
> 
> The problem can be summarized by the following 
> 
> % gfortran7 -o z h.f90
> % ./z
> /lib/libgcc_s.so.1: version GCC_4.8.0 required by \
>   /usr/local/lib/gcc7/libgfortran.so.4 not found
> 
> gfortran7 is installed from ports/lang/gcc7.  This is not 
> a "gfortran's FreeBSD issue".  This is a FreeBSD loader issue.
> 
> Specifically, there is a shared library name clash.
> 
> % ldconfig -r | grep gcc_
>      6:-lgcc_s.1 => /lib/libgcc_s.so.1
>    716:-lgcc_s.1 => /usr/local/lib/gcc7/libgcc_s.so.1
> 
> % ldd z
> z:
>    libgfortran.so.4 => /usr/local/lib/gcc7/libgfortran.so.4 (0x200645000)
>    libm.so.5 => /lib/libm.so.5 (0x200a17000)
>    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x200a4b000)
>    libquadmath.so.0 => /usr/local/lib/gcc7/libquadmath.so.0 (0x200a63000)
>    libc.so.7 => /lib/libc.so.7 (0x200ca3000)
> 
> So, the runtime loader finds 6 instead of 716, tries to link, 
> fails, and issues an error message.  There are a number ways to
> fix this issue.
> 
> 1) By far, the best solution would be to stop hijacking the libgcc
>    name in libraries installed on FreeBSD that are not related to
>    actual GCC software.
> 
> % ls -l /lib/libgcc* /usr/lib/libgcc*
> (trimming lines)
> /lib/libgcc_s.so.1
> /usr/lib/libgcc.a@ -> libcompiler_rt.a
> /usr/lib/libgcc_eh.a
> /usr/lib/libgcc_eh_p.a
> /usr/lib/libgcc_p.a@ -> libcompiler_rt_p.a
> /usr/lib/libgcc_s.so@ -> ../../lib/libgcc_s.so.1
> 
>    Why not use libcompiler_rt_s.so.1 (or libclang_s.so.1)?  Yes, I'm
>    aware that clang does not work on all archs and the ancient gcc
>    lives on.
> 
> 2) Given the expected push back againt solution 1), this solution
>    proposes bumping the library version for /lib/libgcc_s.so.1 from
>    1 to some larger value, say, 10.  It is unlikely that GCC will
>    bump its shared library number anytime soon.  GCC bumped it from
>    0 to 1 some 16 years ago.
> 
>    https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=43316
> 
>    This solution, however, papers over the general problem with
>    name clashes.
> 
> 3) This solution is to actually fix the runtime loader.  If an error
>    occurs with loading a shared library, then iterate over the entries
>    in the hints file to check to see if another hint would satisfy
>    the linking.  Here, instead of issuing the above error, the loader
>    would find entry 716, and load the correct libgcc_s.so.1.
> 
>    Admittedly, I haven't looked to see how difficult this solution
>    would be.
>    
> 4) Bump the shared library number of the individual ports.  As a proof
>    of concept, I've done this with ports/lang/gcc6.
> 
> % cat /usr/ports/lang/gcc6/files/patch-t-slibgcc 
> --- libgcc/config/t-slibgcc.orig        2018-05-08 12:47:42.334495000 -0700
> +++ libgcc/config/t-slibgcc     2018-05-08 12:45:26.872312000 -0700
> @@ -20,7 +20,7 @@
>  
>  SHLIB_EXT = .so
>  SHLIB_SOLINK = @shlib_base_name@.so
> -SHLIB_SOVERSION = 1
> +SHLIB_SOVERSION = 2
>  SHLIB_SONAME = @shlib_base_name@.so.$(SHLIB_SOVERSION)
>  SHLIB_MAP = @shlib_map_file@
>  SHLIB_OBJS = @shlib_objs@
> 
> % ldconfig -r | grep gcc_
>      6:-lgcc_s.1 => /lib/libgcc_s.so.1
>    716:-lgcc_s.1 => /usr/local/lib/gcc7/libgcc_s.so.1
>    766:-lgcc_s.2 => /usr/local/lib/gcc6/libgcc_s.so.2
> 
> % gfortran6 -o z h.f90
> % ./z
>  hello
> % ldd z
> z:
>    libgfortran.so.3 => /usr/local/lib/gcc6/libgfortran.so.3 (0x200645000)
>    libm.so.5 => /lib/libm.so.5 (0x20096c000)
>    libgcc_s.so.2 => /usr/local/lib/gcc6/libgcc_s.so.2 (0x2009a0000)
>    libquadmath.so.0 => /usr/local/lib/gcc7/libquadmath.so.0 (0x200bb7000)
>    libc.so.7 => /lib/libc.so.7 (0x200df7000)
> 
>    This works for this particular name conflict.  Hopefully, FreeBSD
>    never needs to bump /lib/libgcc_s.so.1 to /lib/libgcc_s.so.2.  This,
>    however, introduces an incompatibility with what is actually distributed
>    by GCC.
> 
> Finally, can people stop referring to the above error as
> "gfortran's FreeBSD issue".  This is a FreeBSD runtime loader issue.

libgcc_s.so implements the _Unwind_* API to handle stack unwinding.  This
code is shared between all compilers and languages because the stack can
contain frames from different compilers and languages.  So, you cannot
change the name or version of the library.

I've been testing the attached patch in combination with the ports tree
patch from https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=228046.

The patch makes three changes to /etc/rc.d/ldconfig:
1) Use 'sort -r' so /usr/local/lib/gcc7 appears before /usr/local/lib/gcc6.
2) Move hardcoded paths like /lib and /usr/lib to /etc/defaults/rc.conf
   so the order relative to other paths can be configured.
3) Change the order of ldconfig_local_dirs and ldconfig_paths so /lib and
   /usr/lib appear last.  This brings rc.d/ldconfig in line with compilers
   and rtld(1) which also search /lib and /usr/lib last.

--MP_/nD2m3FmfImDp2u+ur0Mr4sg
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=ldconfig.patch

Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf	(revision 333461)
+++ etc/defaults/rc.conf	(working copy)
@@ -629,14 +629,14 @@ linux_enable="NO"	# Linux binary compatibility loaded 
 clear_tmp_enable="NO"	# Clear /tmp at startup.
 clear_tmp_X="YES" 	# Clear and recreate X11-related directories in /tmp
 ldconfig_insecure="NO"	# Set to YES to disable ldconfig security checks
-ldconfig_paths="/usr/lib/compat /usr/local/lib /usr/local/lib/compat/pkg"
+ldconfig_paths="/usr/local/lib /usr/local/lib/compat/pkg /usr/lib /usr/lib/compat /lib"
 			# shared library search paths
 ldconfig32_paths="/usr/lib32 /usr/lib32/compat"
 			# 32-bit compatibility shared library search paths
-ldconfigsoft_paths="/usr/libsoft /usr/libsoft/compat /usr/local/libsoft"
+ldconfigsoft_paths="/usr/local/libsoft /usr/libsoft /usr/libsoft/compat"
 			# soft float compatibility shared library search paths
 			# Note: temporarily with extra stuff for transition
-ldconfig_paths_aout="/usr/lib/compat/aout /usr/local/lib/aout"
+ldconfig_paths_aout="/usr/local/lib/aout /usr/lib/aout /usr/lib/compat/aout"
 			# a.out shared library search paths
 ldconfig_local_dirs="/usr/local/libdata/ldconfig"
 			# Local directories with ldconfig configuration files.
Index: etc/rc.d/ldconfig
===================================================================
--- etc/rc.d/ldconfig	(revision 333461)
+++ etc/rc.d/ldconfig	(working copy)
@@ -17,22 +17,23 @@ stop_cmd=":"
 
 ldconfig_start()
 {
-	local _files _ins
+	local _files _ins _paths _LDC
 
 	_ins=
 	ldconfig=${ldconfig_command}
 	checkyesno ldconfig_insecure && _ins="-i"
 	if [ -x "${ldconfig_command}" ]; then
-		_LDC="/lib /usr/lib"
+		_paths=""
 		for i in ${ldconfig_local_dirs}; do
 			if [ -d "${i}" ]; then
 				_files=`find ${i} -type f`
 				if [ -n "${_files}" ]; then
-					ldconfig_paths="${ldconfig_paths} `cat ${_files} | sort -u`"
+					_paths="${_paths} `cat ${_files} | sort -ru`"
 				fi
 			fi
 		done
-		for i in ${ldconfig_paths} /etc/ld-elf.so.conf; do
+		_LDC=""
+		for i in ${_paths} ${ldconfig_paths} /etc/ld-elf.so.conf; do
 			if [ -r "${i}" ]; then
 				_LDC="${_LDC} ${i}"
 			fi
@@ -42,16 +43,17 @@ ldconfig_start()
 
 		case `sysctl -n hw.machine_arch` in
 		amd64|powerpc64)
+			_paths=""
 			for i in ${ldconfig_local32_dirs}; do
 				if [ -d "${i}" ]; then
 					_files=`find ${i} -type f`
 					if [ -n "${_files}" ]; then
-						ldconfig32_paths="${ldconfig32_paths} `cat ${_files} | sort -u`"
+						_paths="${_paths} `cat ${_files} | sort -ru`"
 					fi
 				fi
 			done
 			_LDC=""
-			for i in ${ldconfig32_paths}; do
+			for i in ${_paths} ${ldconfig32_paths}; do
 				if [ -r "${i}" ]; then
 					_LDC="${_LDC} ${i}"
 				fi
@@ -64,16 +66,17 @@ ldconfig_start()
 
 		case `sysctl -n hw.machine_arch` in
 		armv[67])
+			_paths=""
 			for i in ${ldconfig_localsoft_dirs}; do
 				if [ -d "${i}" ]; then
 					_files=`find ${i} -type f`
 					if [ -n "${_files}" ]; then
-						ldconfigsoft_paths="${ldconfigsoft_paths} `cat ${_files} | sort -u`"
+						_paths="${_paths} `cat ${_files} | sort -ru`"
 					fi
 				fi
 			done
 			_LDC=""
-			for i in ${ldconfigsoft_paths}; do
+			for i in ${_paths} ${ldconfigsoft_paths}; do
 				if [ -r "${i}" ]; then
 					_LDC="${_LDC} ${i}"
 				fi
@@ -87,10 +90,8 @@ ldconfig_start()
 		# Legacy aout support for i386 only
 		case `sysctl -n hw.machine_arch` in
 		i386)
-			# Default the a.out ldconfig path.
-			: ${ldconfig_paths_aout=${ldconfig_paths}}
 			_LDC=""
-			for i in /usr/lib/aout ${ldconfig_paths_aout} /etc/ld.so.conf; do
+			for i in ${ldconfig_paths_aout} /etc/ld.so.conf; do
 				if [ -r "${i}" ]; then
 					_LDC="${_LDC} ${i}"
 				fi

--MP_/nD2m3FmfImDp2u+ur0Mr4sg--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20180510182151.409b7fb8>