diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 4e1f9453e..f4ce41c78 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -26,6 +26,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) # include #endif +#include #if defined(_WIN32) # include @@ -2478,54 +2479,87 @@ bool cmSystemTools::ChangeRPath(std::string const& file, bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) { #if defined(CMAKE_USE_ELF_PARSER) - unsigned long rpathPosition = 0; - unsigned long rpathSize = 0; - unsigned long rpathEntryPosition = 0; + int zeroCount = 0; + unsigned long zeroPosition[2] = {0,0}; + unsigned long zeroSize[2] = {0,0}; + unsigned long bytesBegin = 0; std::vector bytes; { // Parse the ELF binary. cmELF elf(file.c_str()); - // Get the RPATH or RUNPATH entry from it. - cmELF::StringEntry const* se = elf.GetRPath(); - if(!se) + // Get the RPATH and RUNPATH entries from it and sort them by index + // in the dynamic section header. + int se_count = 0; + cmELF::StringEntry const* se[2] = {0, 0}; + if(cmELF::StringEntry const* se_rpath = elf.GetRPath()) { - se = elf.GetRunPath(); + se[se_count++] = se_rpath; + } + if(cmELF::StringEntry const* se_runpath = elf.GetRunPath()) + { + se[se_count++] = se_runpath; + } + if(se_count == 0) + { + // There is no RPATH or RUNPATH anyway. + return true; + } + if(se_count == 2 && se[1]->IndexInSection < se[0]->IndexInSection) + { + cmsys_stl::swap(se[0], se[1]); } - if(se) + // Get the size of the dynamic section header. + unsigned int count = elf.GetDynamicEntryCount(); + if(count == 0) { - // Store information about the entry. - rpathPosition = se->Position; - rpathSize = se->Size; - rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection); - - // Get the file range containing the rest of the DYNAMIC table - // after the RPATH entry. - unsigned long nextEntryPosition = - elf.GetDynamicEntryPosition(se->IndexInSection+1); - unsigned int count = elf.GetDynamicEntryCount(); - if(count == 0) + // This should happen only for invalid ELF files where a DT_NULL + // appears before the end of the table. + if(emsg) { - // This should happen only for invalid ELF files where a DT_NULL - // appears before the end of the table. - if(emsg) - { - *emsg = "DYNAMIC section contains a DT_NULL before the end."; - } - return false; + *emsg = "DYNAMIC section contains a DT_NULL before the end."; } - unsigned long nullEntryPosition = elf.GetDynamicEntryPosition(count); + return false; + } - // Allocate and fill a buffer with zeros. - bytes.resize(nullEntryPosition - rpathEntryPosition, 0); + // Save information about the string entries to be zeroed. + zeroCount = se_count; + for(int i=0; i < se_count; ++i) + { + zeroPosition[i] = se[i]->Position; + zeroSize[i] = se[i]->Size; + } - // Read the part of the DYNAMIC section header that will move. - // The remainder of the buffer will be left with zeros which - // represent a DT_NULL entry. - if(!elf.ReadBytes(nextEntryPosition, - nullEntryPosition - nextEntryPosition, - &bytes[0])) + // Get the range of file positions corresponding to each entry and + // the rest of the table after them. + unsigned long entryBegin[3] = {0,0,0}; + unsigned long entryEnd[2] = {0,0}; + for(int i=0; i < se_count; ++i) + { + entryBegin[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection); + entryEnd[i] = elf.GetDynamicEntryPosition(se[i]->IndexInSection+1); + } + entryBegin[se_count] = elf.GetDynamicEntryPosition(count); + + // The data are to be written over the old table entries starting at + // the first one being removed. + bytesBegin = entryBegin[0]; + unsigned long bytesEnd = entryBegin[se_count]; + + // Allocate a buffer to hold the part of the file to be written. + // Initialize it with zeros. + bytes.resize(bytesEnd - bytesBegin, 0); + + // Read the part of the DYNAMIC section header that will move. + // The remainder of the buffer will be left with zeros which + // represent a DT_NULL entry. + char* data = &bytes[0]; + for(int i=0; i < se_count; ++i) + { + // Read data between the entries being removed. + unsigned long sz = entryBegin[i+1] - entryEnd[i]; + if(sz > 0 && !elf.ReadBytes(entryEnd[i], sz, data)) { if(emsg) { @@ -2533,11 +2567,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } return false; } - } - else - { - // There is no RPATH or RUNPATH anyway. - return true; + data += sz; } } @@ -2554,7 +2584,7 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) } // Write the new DYNAMIC table header. - if(!f.seekp(rpathEntryPosition)) + if(!f.seekp(bytesBegin)) { if(emsg) { @@ -2571,33 +2601,33 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg) return false; } - // Fill the RPATH string with zero bytes. - if(!f.seekp(rpathPosition)) + // Fill the RPATH and RUNPATH strings with zero bytes. + for(int i=0; i < zeroCount; ++i) { - if(emsg) + if(!f.seekp(zeroPosition[i])) { - *emsg = "Error seeking to RPATH position."; + if(emsg) + { + *emsg = "Error seeking to RPATH position."; + } + return false; + } + for(unsigned long j=0; j < zeroSize[i]; ++j) + { + f << '\0'; + } + if(!f) + { + if(emsg) + { + *emsg = "Error writing the empty rpath string to the file."; + } + return false; } - return false; - } - for(unsigned long i=0; i < rpathSize; ++i) - { - f << '\0'; } - // Make sure everything was okay. - if(f) - { - return true; - } - else - { - if(emsg) - { - *emsg = "Error writing the empty rpath to the file."; - } - return false; - } + // Everything was updated successfully. + return true; #else (void)file; (void)emsg;