|
|
@@ -26,6 +26,7 @@
|
|
|
#if defined(CMAKE_BUILD_WITH_CMAKE)
|
|
|
# include <cmsys/Terminal.h>
|
|
|
#endif
|
|
|
+#include <cmsys/stl/algorithm>
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
# include <windows.h>
|
|
|
@@ -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<char> 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(se)
|
|
|
+ if(cmELF::StringEntry const* se_runpath = elf.GetRunPath())
|
|
|
{
|
|
|
- // Store information about the entry.
|
|
|
- rpathPosition = se->Position;
|
|
|
- rpathSize = se->Size;
|
|
|
- rpathEntryPosition = elf.GetDynamicEntryPosition(se->IndexInSection);
|
|
|
+ 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]);
|
|
|
+ }
|
|
|
|
|
|
- // 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)
|
|
|
+ // Get the size of the dynamic section header.
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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);
|
|
|
|
|
|
- // 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]))
|
|
|
+ // 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;
|
|
|
}
|
|
|
- return false;
|
|
|
- }
|
|
|
- for(unsigned long i=0; i < rpathSize; ++i)
|
|
|
- {
|
|
|
- f << '\0';
|
|
|
- }
|
|
|
-
|
|
|
- // Make sure everything was okay.
|
|
|
- if(f)
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if(emsg)
|
|
|
+ for(unsigned long j=0; j < zeroSize[i]; ++j)
|
|
|
{
|
|
|
- *emsg = "Error writing the empty rpath to the file.";
|
|
|
+ f << '\0';
|
|
|
+ }
|
|
|
+ if(!f)
|
|
|
+ {
|
|
|
+ if(emsg)
|
|
|
+ {
|
|
|
+ *emsg = "Error writing the empty rpath string to the file.";
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
- return false;
|
|
|
}
|
|
|
+
|
|
|
+ // Everything was updated successfully.
|
|
|
+ return true;
|
|
|
#else
|
|
|
(void)file;
|
|
|
(void)emsg;
|