From 8380fc26a471d64bcddc38a2bce9442f6386b805 Mon Sep 17 00:00:00 2001
From: Alexander Golubev <fatzer2@gmail.com>
Date: Fri, 3 Oct 2025 10:48:01 +0300
Subject: Use compilation config-time checks instead of linker version

To rely on current linker's version to determine the libbfd version is
unreliable. In particular it's likely to yield wrong result in next
use-cases:
 - cross-compilations
 - build with non-GNU toolchain
 - just  build with another linker version

Unfortunately libbfd doesn't provide a reliable way to retrieve version
information, so we will have to check for features in specific versions
we are interested in.

Note: this essentially reverts most of the changes introduced by
c57eae31615bc70072c7e99d712c2285817bd2e5.

Signed-off-by: Alexander Golubev <fatzer2@gmail.com>
---
 CMakeLists.txt     | 25 ++++++++++---------------
 src/config.h.cmake |  7 +++++--
 src/libr-bfd.c     | 22 +++++++++++-----------
 3 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e7bbf15..4b90b14 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,7 @@ set( PACKAGE_VERSION 0.7.0 )
 
 include( FindPkgConfig )
 include( FindThreads )
+include( CheckCSourceCompiles )
 include( CheckIncludeFile )
 include( CheckFunctionExists )
 include( CheckLibraryExists )
@@ -59,26 +60,20 @@ option( WITH_GTK              "Build support for GTK"        OFF )
 #### configure checks ###########################
 
 if( WITH_BACKEND_LIBBFD )
-    message( STATUS "Checking linker version" )
-    execute_process(
-      COMMAND ${CMAKE_LINKER} --version
-      OUTPUT_VARIABLE _linker_version
-      ERROR_VARIABLE _linker_version
-    )
-    string( REGEX REPLACE "^GNU [^\n]* ([^ ]*)\n.*" "\\1" LINKER_VERSION ${_linker_version} )
-    string( REGEX MATCH "^([0-9]+)\\.([0-9]+)(\\.([0-9]+))?.*" LINKER_VERSION_MATCH ${LINKER_VERSION} )
-    math( EXPR LINKER_VERSION_MAJOR "${CMAKE_MATCH_1}+0" )
-    math( EXPR LINKER_VERSION_MINOR "${CMAKE_MATCH_2}+0" )
-    math( EXPR LINKER_VERSION_PATCH "${CMAKE_MATCH_4}+0" )
-    math( EXPR LINKER_VERSION_C "(${LINKER_VERSION_MAJOR}*1000000) + (${LINKER_VERSION_MINOR}*1000) + ${LINKER_VERSION_PATCH}" )
-    set( LINKER_VERSION_C ${LINKER_VERSION_C} CACHE INTERNAL "Linker version as code number" )
-    message( STATUS "Checking linker version - ${LINKER_VERSION}" )
-
     tde_save_and_set( CMAKE_REQUIRED_DEFINITIONS "-DPACKAGE" "-DPACKAGE_VERSION" )
     check_include_file( bfd.h HAVE_BFD_H )
     if( NOT HAVE_BFD_H )
         tde_message_fatal( "Could not find libbfd header file (bfd.h)!\nThis file is usually included in the package binutils-dev." )
     endif( NOT HAVE_BFD_H )
+    tde_save_and_set( CMAKE_REQUIRED_LIBRARIES "bfd" )
+    check_symbol_exists( bfd_asymbol_section bfd.h HAVE_BFD_2_34 )
+    check_c_source_compiles(
+        "#include <bfd.h>
+         int main() { bfd *ihandle, *ohandle; asection *iscn, *oscn;
+           bfd_copy_private_section_data(ihandle, iscn, ohandle, oscn, NULL);
+         }"
+        HAVE_BFD_2_45)
+    tde_restore( CMAKE_REQUIRED_LIBRARIES )
     tde_restore( CMAKE_REQUIRED_DEFINITIONS )
     set( BACKEND_LIBRARIES "-lbfd" )
     set( LIBR_BACKEND "bfd" )
diff --git a/src/config.h.cmake b/src/config.h.cmake
index 8842734..e2673d2 100644
--- a/src/config.h.cmake
+++ b/src/config.h.cmake
@@ -8,5 +8,8 @@
    language is requested. */
 #define ENABLE_NLS 1
 
-/* Define Binutils linker version code */
-#cmakedefine LINKER_VERSION_C @LINKER_VERSION_C@
+/* Define to 1 if you have Binutils >= 2.34 */
+#cmakedefine HAVE_BFD_2_34 1
+
+/* Define to 1 if you have Binutils >= 2.45 */
+#cmakedefine HAVE_BFD_2_45 1
diff --git a/src/libr-bfd.c b/src/libr-bfd.c
index 7d72036..9d72cce 100644
--- a/src/libr-bfd.c
+++ b/src/libr-bfd.c
@@ -114,7 +114,7 @@ int keep_symbol(libr_section *sections, libr_section *chkscn)
 		{
 			/* if it is, and has size zero, then it was marked for deletion */
 			if(
-				#if (LINKER_VERSION_C >= 2034000)
+				#ifdef HAVE_BFD_2_34
 				bfd_section_size(chkscn) == 0
 				#else
 				bfd_get_section_size(chkscn) == 0
@@ -144,7 +144,7 @@ void remove_sections(libr_section *sections, void *symtab_buffer, long *symtab_c
 		
 		if(symbol != NULL)
 		{
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			chkscn = bfd_asymbol_section(symbol);
 			#else
 			chkscn = bfd_get_section(symbol);
@@ -171,7 +171,7 @@ int setup_sections(bfd *ihandle, bfd *ohandle)
 	for(iscn = ihandle->sections; iscn != NULL; iscn = iscn->next)
 	{
 		if(
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			bfd_section_size(iscn) == 0
 			#else
 			bfd_get_section_size(iscn) == 0
@@ -199,7 +199,7 @@ int setup_sections(bfd *ihandle, bfd *ohandle)
 			return false;
 		}
 		if(
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			!bfd_set_section_size(oscn, iscn->size)
 			#else
 			!bfd_set_section_size(ohandle, oscn, iscn->size)
@@ -209,13 +209,13 @@ int setup_sections(bfd *ihandle, bfd *ohandle)
 			printf("failed to set data size: %s\n", bfd_errmsg(bfd_get_error()));
 			return false;
 		}
-		#if (LINKER_VERSION_C >= 2034000)
+		#ifdef HAVE_BFD_2_34
 		vma = bfd_section_vma(iscn);
 		#else
 		vma = bfd_section_vma(ihandle, iscn);
 		#endif
 		if(
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			!bfd_set_section_vma(oscn, vma)
 			#else
 			!bfd_set_section_vma(ohandle, oscn, vma)
@@ -227,7 +227,7 @@ int setup_sections(bfd *ihandle, bfd *ohandle)
 		}
 		oscn->lma = iscn->lma;
 		if(
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			!bfd_set_section_alignment(oscn, bfd_section_alignment(iscn))
 			#else
 			!bfd_set_section_alignment(ohandle, oscn, bfd_section_alignment(ihandle, iscn))
@@ -241,7 +241,7 @@ int setup_sections(bfd *ihandle, bfd *ohandle)
 		iscn->output_section = oscn;
 		iscn->output_offset = vma;
 		if(
-			#if (LINKER_VERSION_C >= 2045000)
+			#ifdef HAVE_BFD_2_45
 			!bfd_copy_private_section_data(ihandle, iscn, ohandle, oscn, NULL)
 			#else
 			!bfd_copy_private_section_data(ihandle, iscn, ohandle, oscn)
@@ -310,7 +310,7 @@ int build_output(libr_file *file_handle)
 	/* Actually copy section data */
 	for(iscn = ihandle->sections; iscn != NULL; iscn = iscn->next)
 	{
-		#if (LINKER_VERSION_C >= 2034000)
+		#ifdef HAVE_BFD_2_34
 		size = bfd_section_size(iscn);
 		#else
 		size = bfd_get_section_size(iscn);
@@ -329,7 +329,7 @@ int build_output(libr_file *file_handle)
 		}
 
 		if(
-			#if (LINKER_VERSION_C >= 2034000)
+			#ifdef HAVE_BFD_2_34
 			bfd_section_flags(iscn) & SEC_HAS_CONTENTS
 			#else
 			bfd_get_section_flags(ihandle, iscn) & SEC_HAS_CONTENTS
@@ -554,7 +554,7 @@ libr_intstatus add_section(libr_file *file_handle, char *resource_name, libr_sec
 	if(scn == NULL)
 		RETURN(LIBR_ERROR_NEWSECTION, "Failed to create new section");
 	if(
-		#if (LINKER_VERSION_C >= 2034000)
+		#ifdef HAVE_BFD_2_34
 		!bfd_set_section_flags(scn, SEC_HAS_CONTENTS | SEC_DATA | SEC_IN_MEMORY)
 		#else
 		!bfd_set_section_flags(file_handle->bfd_read, scn, SEC_HAS_CONTENTS | SEC_DATA | SEC_IN_MEMORY)
-- 
cgit v1.2.3

