From 66c4d0820ca86b0b119303859f3dae0f7c560969 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Fri, 30 Sep 2016 15:34:48 +0100 Subject: elf: remove tag switch from ELF_Dyn ByteSwap function sizeof(dyn.d_un.d_val) always equals sizeof(dyn.d_un.d_ptr) so every byte swap call in this function is identical. --- Source/cmELF.cxx | 120 +++---------------------------------------------------- 1 file changed, 5 insertions(+), 115 deletions(-) diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 2d86674..f78eed5 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -289,6 +289,10 @@ public: } private: + // ByteSwap(ELF_Dyn) assumes d_val and d_ptr are the same size + typedef char dyn_size_assert + [sizeof(ELF_Dyn().d_un.d_val) == sizeof(ELF_Dyn().d_un.d_ptr) ? 1 : -1]; + void ByteSwap(ELF_Ehdr& elf_header) { cmELFByteSwap(elf_header.e_type); @@ -323,121 +327,7 @@ private: void ByteSwap(ELF_Dyn& dyn) { cmELFByteSwap(dyn.d_tag); - switch (dyn.d_tag) { - case DT_NULL: /* dyn.d_un ignored */ - break; - case DT_NEEDED: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_PLTRELSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_PLTGOT: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_HASH: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_STRTAB: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_SYMTAB: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_RELA: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_RELASZ: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_RELAENT: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_STRSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_SYMENT: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_INIT: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_FINI: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_SONAME: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_RPATH: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_SYMBOLIC: /* dyn.d_un ignored */ - break; - case DT_REL: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_RELSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_RELENT: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_PLTREL: - cmELFByteSwap(dyn.d_un.d_val); - break; - case DT_DEBUG: - cmELFByteSwap(dyn.d_un.d_ptr); - break; - case DT_TEXTREL: /* dyn.d_un ignored */ - break; - case DT_JMPREL: - cmELFByteSwap(dyn.d_un.d_ptr); - break; -#ifdef T_BIND_NOW - case T_BIND_NOW: /* dyn.d_un ignored */ - break; -#endif -#ifdef DT_INIT_ARRAY - case DT_INIT_ARRAY: - cmELFByteSwap(dyn.d_un.d_ptr); - break; -#endif -#ifdef DT_FINI_ARRAY - case DT_FINI_ARRAY: - cmELFByteSwap(dyn.d_un.d_ptr); - break; -#endif -#ifdef DT_INIT_ARRAYSZ - case DT_INIT_ARRAYSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; -#endif -#ifdef DT_FINI_ARRAYSZ - case DT_FINI_ARRAYSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; -#endif -#ifdef DT_RUNPATH - case DT_RUNPATH: - cmELFByteSwap(dyn.d_un.d_val); - break; -#endif -#ifdef DT_FLAGS - case DT_FLAGS: - cmELFByteSwap(dyn.d_un.d_val); - break; -#endif -#ifdef DT_PREINIT_ARRAY - case DT_PREINIT_ARRAY: - cmELFByteSwap(dyn.d_un.d_ptr); - break; -#endif -#ifdef DT_PREINIT_ARRAYSZ - case DT_PREINIT_ARRAYSZ: - cmELFByteSwap(dyn.d_un.d_val); - break; -#endif - } + cmELFByteSwap(dyn.d_un.d_val); } bool FileTypeValid(ELF_Half et) -- cgit v0.12 From 72eb6a374ed12cfa0dee0ce1930a4dcd8473c700 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Wed, 5 Oct 2016 16:43:16 +0100 Subject: elf: add DynamicEntryList methods and rpath tag constants --- Source/cmELF.cxx | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Source/cmELF.h | 18 +++++++++++++ 2 files changed, 95 insertions(+) diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index f78eed5..bf0130a 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -134,6 +134,9 @@ public: virtual unsigned int GetNumberOfSections() const = 0; virtual unsigned int GetDynamicEntryCount() = 0; virtual unsigned long GetDynamicEntryPosition(int j) = 0; + virtual cmELF::DynamicEntryList GetDynamicEntries() = 0; + virtual std::vector EncodeDynamicEntries( + const cmELF::DynamicEntryList&) = 0; virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; virtual void PrintInfo(std::ostream& os) const = 0; @@ -250,6 +253,10 @@ public: unsigned int GetDynamicEntryCount() CM_OVERRIDE; unsigned long GetDynamicEntryPosition(int j) CM_OVERRIDE; + cmELF::DynamicEntryList GetDynamicEntries() CM_OVERRIDE; + std::vector EncodeDynamicEntries(const cmELF::DynamicEntryList&) + CM_OVERRIDE; + // Lookup a string from the dynamic section with the given tag. StringEntry const* GetDynamicSectionString(unsigned int tag) CM_OVERRIDE; @@ -553,6 +560,54 @@ unsigned long cmELFInternalImpl::GetDynamicEntryPosition(int j) } template +cmELF::DynamicEntryList cmELFInternalImpl::GetDynamicEntries() +{ + cmELF::DynamicEntryList result; + + // Ensure entries have been read from file + if (!this->LoadDynamicSection()) { + return result; + } + + // Copy into public array + result.reserve(this->DynamicSectionEntries.size()); + for (typename std::vector::iterator di = + this->DynamicSectionEntries.begin(); + di != this->DynamicSectionEntries.end(); ++di) { + ELF_Dyn& dyn = *di; + result.push_back( + std::pair(dyn.d_tag, dyn.d_un.d_val)); + } + + return result; +} + +template +std::vector cmELFInternalImpl::EncodeDynamicEntries( + const cmELF::DynamicEntryList& entries) +{ + std::vector result; + result.reserve(sizeof(ELF_Dyn) * entries.size()); + + for (cmELF::DynamicEntryList::const_iterator it = entries.begin(); + it != entries.end(); it++) { + // Store the entry in an ELF_Dyn, byteswap it, then serialize to chars + ELF_Dyn dyn; + dyn.d_tag = static_cast(it->first); + dyn.d_un.d_val = static_cast(it->second); + + if (this->NeedSwap) { + ByteSwap(dyn); + } + + char* pdyn = reinterpret_cast(&dyn); + result.insert(result.end(), pdyn, pdyn + sizeof(ELF_Dyn)); + } + + return result; +} + +template cmELF::StringEntry const* cmELFInternalImpl::GetDynamicSectionString( unsigned int tag) { @@ -642,6 +697,9 @@ cmELF::StringEntry const* cmELFInternalImpl::GetDynamicSectionString( //============================================================================ // External class implementation. +const long cmELF::TagRPath = DT_RPATH; +const long cmELF::TagRunPath = DT_RUNPATH; + cmELF::cmELF(const char* fname) : Internal(CM_NULLPTR) { @@ -745,6 +803,25 @@ unsigned long cmELF::GetDynamicEntryPosition(int index) const return 0; } +cmELF::DynamicEntryList cmELF::GetDynamicEntries() const +{ + if (this->Valid()) { + return this->Internal->GetDynamicEntries(); + } + + return cmELF::DynamicEntryList(); +} + +std::vector cmELF::EncodeDynamicEntries( + const cmELF::DynamicEntryList& dentries) const +{ + if (this->Valid()) { + return this->Internal->EncodeDynamicEntries(dentries); + } + + return std::vector(); +} + bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const { if (this->Valid()) { diff --git a/Source/cmELF.h b/Source/cmELF.h index 7e7c1d6..3fc59b4 100644 --- a/Source/cmELF.h +++ b/Source/cmELF.h @@ -7,6 +7,8 @@ #include #include +#include +#include #if !defined(CMAKE_USE_ELF_PARSER) #error "This file may be included only if CMAKE_USE_ELF_PARSER is enabled." @@ -61,6 +63,9 @@ public: int IndexInSection; }; + /** Represent entire dynamic section header */ + typedef std::vector > DynamicEntryList; + /** Get the type of the file opened. */ FileType GetFileType() const; @@ -75,6 +80,15 @@ public: zero on error. */ unsigned long GetDynamicEntryPosition(int index) const; + /** Get a copy of all the DYNAMIC section header entries. + Returns an empty vector on error */ + DynamicEntryList GetDynamicEntries() const; + + /** Encodes a DYNAMIC section header entry list into a char vector according + to the type of ELF file this is */ + std::vector EncodeDynamicEntries( + const DynamicEntryList& entries) const; + /** Read bytes from the file. */ bool ReadBytes(unsigned long pos, unsigned long size, char* buf) const; @@ -91,6 +105,10 @@ public: /** Print human-readable information about the ELF file. */ void PrintInfo(std::ostream& os) const; + /** Interesting dynamic tags. + If the tag is 0, it does not exist in the host ELF implementation */ + static const long TagRPath, TagRunPath; + private: friend class cmELFInternal; bool Valid() const; -- cgit v0.12 From b8b1d15186b33ec598b1126169856184805b3e6f Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Wed, 5 Oct 2016 17:19:43 +0100 Subject: cmSystemTools: rewrite RemoveRPath using DyanmicEntryList methods --- Source/cmSystemTools.cxx | 52 ++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 3d8fdf5..8951788 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2518,9 +2518,9 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, std::swap(se[0], se[1]); } - // Get the size of the dynamic section header. - unsigned int count = elf.GetDynamicEntryCount(); - if (count == 0) { + // Obtain a copy of the dynamic entries + cmELF::DynamicEntryList dentries = elf.GetDynamicEntries(); + if (dentries.empty()) { // This should happen only for invalid ELF files where a DT_NULL // appears before the end of the table. if (emsg) { @@ -2536,40 +2536,22 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, 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); - - // 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) { - *emsg = "Failed to read DYNAMIC section header."; - } - return false; + // Adjust the entry list as necessary to remove the run path + unsigned long entriesErased = 0; + for (cmELF::DynamicEntryList::iterator it = dentries.begin(); + it != dentries.end();) { + if (it->first == cmELF::TagRPath || it->first == cmELF::TagRunPath) { + it = dentries.erase(it); + entriesErased++; + continue; + } else { + it++; } - data += sz; } + + // Encode new entries list + bytes = elf.EncodeDynamicEntries(dentries); + bytesBegin = elf.GetDynamicEntryPosition(0); } // Open the file for update. -- cgit v0.12 From cd4f573ae9f4ded1cb386698f90c7ccf1504f094 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Wed, 5 Oct 2016 17:20:58 +0100 Subject: cmSystemTools, elf: handle DT_MIPS_RLD_REL_MAP in RemoveRPath --- Source/cmELF.cxx | 6 ++++++ Source/cmELF.h | 2 +- Source/cmSystemTools.cxx | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index bf0130a..6f2885c 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -700,6 +700,12 @@ cmELF::StringEntry const* cmELFInternalImpl::GetDynamicSectionString( const long cmELF::TagRPath = DT_RPATH; const long cmELF::TagRunPath = DT_RUNPATH; +#ifdef DT_MIPS_RLD_MAP_REL +const long cmELF::TagMipsRldMapRel = DT_MIPS_RLD_MAP_REL; +#else +const long cmELF::TagMipsRldMapRel = 0; +#endif + cmELF::cmELF(const char* fname) : Internal(CM_NULLPTR) { diff --git a/Source/cmELF.h b/Source/cmELF.h index 3fc59b4..9c56be7 100644 --- a/Source/cmELF.h +++ b/Source/cmELF.h @@ -107,7 +107,7 @@ public: /** Interesting dynamic tags. If the tag is 0, it does not exist in the host ELF implementation */ - static const long TagRPath, TagRunPath; + static const long TagRPath, TagRunPath, TagMipsRldMapRel; private: friend class cmELFInternal; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 8951788..d800ef8 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2536,6 +2536,10 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, zeroSize[i] = se[i]->Size; } + // Get size of one DYNAMIC entry + unsigned long const sizeof_dentry = + elf.GetDynamicEntryPosition(1) - elf.GetDynamicEntryPosition(0); + // Adjust the entry list as necessary to remove the run path unsigned long entriesErased = 0; for (cmELF::DynamicEntryList::iterator it = dentries.begin(); @@ -2545,6 +2549,26 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, entriesErased++; continue; } else { + if (cmELF::TagMipsRldMapRel != 0 && + it->first == cmELF::TagMipsRldMapRel) { + // Background: debuggers need to know the "linker map" which contains + // the addresses each dynamic object is loaded at. Most arches use + // the DT_DEBUG tag which the dynamic linker writes to (directly) and + // contain the location of the linker map, however on MIPS the + // .dynamic section is always read-only so this is not possible. MIPS + // objects instead contain a DT_MIPS_RLD_MAP tag which contains the + // address where the dyanmic linker will write to (an indirect + // version of DT_DEBUG). Since this doesn't work when using PIE, a + // relative equivalent was created - DT_MIPS_RLD_MAP_REL. Since this + // version contains a relative offset, moving it changes the + // calculated address. This may cause the dyanmic linker to write + // into memory it should not be changing. + // + // To fix this, we adjust the value of DT_MIPS_RLD_MAP_REL here. If + // we move it up by n bytes, we add n bytes to the value of this tag. + it->second += entriesErased * sizeof_dentry; + } + it++; } } -- cgit v0.12 From 15762b72b456998ac0f87ceec750a20e9872f325 Mon Sep 17 00:00:00 2001 From: James Cowgill Date: Wed, 5 Oct 2016 16:57:24 +0100 Subject: elf: Remove GetDynamicEntryCount and ReadBytes methods These are no longer used after the DynamicEntryList changes. --- Source/cmELF.cxx | 41 +---------------------------------------- Source/cmELF.h | 7 ------- 2 files changed, 1 insertion(+), 47 deletions(-) diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx index 6f2885c..0655da9 100644 --- a/Source/cmELF.cxx +++ b/Source/cmELF.cxx @@ -132,7 +132,6 @@ public: // Forward to the per-class implementation. virtual unsigned int GetNumberOfSections() const = 0; - virtual unsigned int GetDynamicEntryCount() = 0; virtual unsigned long GetDynamicEntryPosition(int j) = 0; virtual cmELF::DynamicEntryList GetDynamicEntries() = 0; virtual std::vector EncodeDynamicEntries( @@ -140,13 +139,6 @@ public: virtual StringEntry const* GetDynamicSectionString(unsigned int tag) = 0; virtual void PrintInfo(std::ostream& os) const = 0; - bool ReadBytes(unsigned long pos, unsigned long size, char* buf) - { - this->Stream.seekg(pos); - this->Stream.read(buf, size); - return !this->Stream.fail(); - } - // Lookup the SONAME in the DYNAMIC section. StringEntry const* GetSOName() { @@ -249,8 +241,7 @@ public: return static_cast(this->ELFHeader.e_shnum); } - // Get the file position and size of a dynamic section entry. - unsigned int GetDynamicEntryCount() CM_OVERRIDE; + // Get the file position of a dynamic section entry. unsigned long GetDynamicEntryPosition(int j) CM_OVERRIDE; cmELF::DynamicEntryList GetDynamicEntries() CM_OVERRIDE; @@ -533,20 +524,6 @@ bool cmELFInternalImpl::LoadDynamicSection() } template -unsigned int cmELFInternalImpl::GetDynamicEntryCount() -{ - if (!this->LoadDynamicSection()) { - return 0; - } - for (unsigned int i = 0; i < this->DynamicSectionEntries.size(); ++i) { - if (this->DynamicSectionEntries[i].d_tag == DT_NULL) { - return i; - } - } - return static_cast(this->DynamicSectionEntries.size()); -} - -template unsigned long cmELFInternalImpl::GetDynamicEntryPosition(int j) { if (!this->LoadDynamicSection()) { @@ -793,14 +770,6 @@ unsigned int cmELF::GetNumberOfSections() const return 0; } -unsigned int cmELF::GetDynamicEntryCount() const -{ - if (this->Valid()) { - return this->Internal->GetDynamicEntryCount(); - } - return 0; -} - unsigned long cmELF::GetDynamicEntryPosition(int index) const { if (this->Valid()) { @@ -828,14 +797,6 @@ std::vector cmELF::EncodeDynamicEntries( return std::vector(); } -bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const -{ - if (this->Valid()) { - return this->Internal->ReadBytes(pos, size, buf); - } - return false; -} - bool cmELF::GetSOName(std::string& soname) { if (StringEntry const* se = this->GetSOName()) { diff --git a/Source/cmELF.h b/Source/cmELF.h index 9c56be7..763a240 100644 --- a/Source/cmELF.h +++ b/Source/cmELF.h @@ -72,10 +72,6 @@ public: /** Get the number of ELF sections present. */ unsigned int GetNumberOfSections() const; - /** Get the number of DYNAMIC section entries before the first - DT_NULL. Returns zero on error. */ - unsigned int GetDynamicEntryCount() const; - /** Get the position of a DYNAMIC section header entry. Returns zero on error. */ unsigned long GetDynamicEntryPosition(int index) const; @@ -89,9 +85,6 @@ public: std::vector EncodeDynamicEntries( const DynamicEntryList& entries) const; - /** Read bytes from the file. */ - bool ReadBytes(unsigned long pos, unsigned long size, char* buf) const; - /** Get the SONAME field if any. */ bool GetSOName(std::string& soname); StringEntry const* GetSOName(); -- cgit v0.12