Browse Source

Merge topic 'file-RPATH-large-ELF'

615a1c6691 cmELF: Get correct section count for large ELF binaries

Acked-by: Kitware Robot <[email protected]>
Merge-request: !9310
Brad King 1 year ago
parent
commit
7c326643ad

+ 2 - 0
.gitlab/ci/configure_debian12_ninja_common.cmake

@@ -90,6 +90,8 @@ set(CMake_TEST_FindwxWidgets "ON" CACHE BOOL "")
 set(CMake_TEST_FindX11 "ON" CACHE BOOL "")
 set(CMake_TEST_FindXalanC "ON" CACHE BOOL "")
 set(CMake_TEST_FindXercesC "ON" CACHE BOOL "")
+
+set(CMake_TEST_ELF_LARGE "ON" CACHE BOOL "")
 set(CMake_TEST_Fortran_SUBMODULES "ON" CACHE BOOL "")
 set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
 set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")

+ 2 - 0
.gitlab/ci/configure_fedora39_makefiles.cmake

@@ -90,6 +90,8 @@ set(CMake_TEST_FindwxWidgets "ON" CACHE BOOL "")
 set(CMake_TEST_FindX11 "ON" CACHE BOOL "")
 set(CMake_TEST_FindXalanC "ON" CACHE BOOL "")
 set(CMake_TEST_FindXercesC "ON" CACHE BOOL "")
+
+set(CMake_TEST_ELF_LARGE "ON" CACHE BOOL "")
 set(CMake_TEST_Fortran_SUBMODULES "ON" CACHE BOOL "")
 set(CMake_TEST_IPO_WORKS_C "ON" CACHE BOOL "")
 set(CMake_TEST_IPO_WORKS_CXX "ON" CACHE BOOL "")

+ 9 - 5
Source/cmELF.cxx

@@ -212,7 +212,8 @@ public:
   // Return the number of sections as specified by the ELF header.
   unsigned int GetNumberOfSections() const override
   {
-    return static_cast<unsigned int>(this->ELFHeader.e_shnum);
+    return static_cast<unsigned int>(this->ELFHeader.e_shnum +
+                                     this->SectionHeaders[0].sh_size);
   }
 
   // Get the file position of a dynamic section entry.
@@ -367,7 +368,7 @@ private:
     return !this->Stream->fail();
   }
 
-  bool LoadSectionHeader(ELF_Half i)
+  bool LoadSectionHeader(unsigned int i)
   {
     // Read the section header from the file.
     this->Stream->seekg(this->ELFHeader.e_shoff +
@@ -378,7 +379,7 @@ private:
 
     // Identify some important sections.
     if (this->SectionHeaders[i].sh_type == SHT_DYNAMIC) {
-      this->DynamicSectionIndex = i;
+      this->DynamicSectionIndex = static_cast<int>(i);
     }
     return true;
   }
@@ -444,8 +445,11 @@ cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
   this->Machine = this->ELFHeader.e_machine;
 
   // Load the section headers.
-  this->SectionHeaders.resize(this->ELFHeader.e_shnum);
-  for (ELF_Half i = 0; i < this->ELFHeader.e_shnum; ++i) {
+  this->SectionHeaders.resize(
+    this->ELFHeader.e_shnum == 0 ? 1 : this->ELFHeader.e_shnum);
+  this->LoadSectionHeader(0);
+  this->SectionHeaders.resize(this->GetNumberOfSections());
+  for (unsigned int i = 1; i < this->GetNumberOfSections(); ++i) {
     if (!this->LoadSectionHeader(i)) {
       this->SetErrorMessage("Failed to load section headers.");
       return;

+ 4 - 1
Tests/RunCMake/CMakeLists.txt

@@ -560,7 +560,10 @@ foreach(var
   endif()
 endforeach()
 add_RunCMake_test(file-DOWNLOAD)
-add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
+add_RunCMake_test(file-RPATH
+  -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+  -DCMake_TEST_ELF_LARGE=${CMake_TEST_ELF_LARGE}
+)
 add_RunCMake_test(file-STRINGS)
 add_RunCMake_test(find_file -DMINGW=${MINGW})
 add_RunCMake_test(find_library -DMINGW=${MINGW} -DCYGWIN=${CYGWIN} -DMSYS=${MSYS} -DMSVC=${MSVC})

+ 3 - 0
Tests/RunCMake/file-RPATH/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.29)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 26 - 0
Tests/RunCMake/file-RPATH/LargeELF.c

@@ -0,0 +1,26 @@
+/* Create more than 65536 ELF sections.  */
+
+/* clang-format off */
+#define C0(i) int v##i __attribute__((section("s" #i)))
+#define C1(i) C0(i##0); C0(i##1); C0(i##2); C0(i##3); C0(i##4); \
+              C0(i##5); C0(i##6); C0(i##7); C0(i##8); C0(i##9)
+#define C2(i) C1(i##0); C1(i##1); C1(i##2); C1(i##3); C1(i##4); \
+              C1(i##5); C1(i##6); C1(i##7); C1(i##8); C1(i##9)
+#define C3(i) C2(i##0); C2(i##1); C2(i##2); C2(i##3); C2(i##4); \
+              C2(i##5); C2(i##6); C2(i##7); C2(i##8); C2(i##9)
+#define C4(i) C3(i##0); C3(i##1); C3(i##2); C3(i##3); C3(i##4); \
+              C3(i##5); C3(i##6); C3(i##7); C3(i##8); C3(i##9)
+/* clang-format on */
+
+C4(1);
+C4(2);
+C4(3);
+C4(4);
+C4(5);
+C4(6);
+C4(7);
+
+int main(void)
+{
+  return 0;
+}

+ 5 - 0
Tests/RunCMake/file-RPATH/LargeELF.cmake

@@ -0,0 +1,5 @@
+enable_language(C)
+
+add_executable(LargeELF LargeELF.c)
+set_property(TARGET LargeELF PROPERTY INSTALL_RPATH "/test")
+install(TARGETS LargeELF)

+ 12 - 0
Tests/RunCMake/file-RPATH/RunCMakeTest.cmake

@@ -16,3 +16,15 @@ run_cmake_command(TextSet ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/TextSet.cma
 run_cmake_command(TextSetEmpty ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/TextSetEmpty.cmake)
 
 run_cmake_command(TextRemove ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/TextRemove.cmake)
+
+# Test install RPATH for ELF files with more than 65536 sections.
+# This is supported only by certain platforms/toolchains, so run
+# this case only if explicitly enabled.
+if(CMake_TEST_ELF_LARGE)
+  block()
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LargeELF-build)
+    run_cmake_with_options(LargeELF -DCMAKE_INSTALL_PREFIX=${RunCMake_TEST_BINARY_DIR}/root)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    run_cmake_command(LargeELF-build ${CMAKE_COMMAND} --build . --target install)
+  endblock()
+endif()