Commit ea563a27 authored by Brad King's avatar Brad King Committed by Kitware Robot

Merge topic 'mips-rld-map-rel'

15762b72 elf: Remove GetDynamicEntryCount and ReadBytes methods
cd4f573a cmSystemTools, elf: handle DT_MIPS_RLD_REL_MAP in RemoveRPath
b8b1d151 cmSystemTools: rewrite RemoveRPath using DyanmicEntryList methods
72eb6a37 elf: add DynamicEntryList methods and rpath tag constants
66c4d082 elf: remove tag switch from ELF_Dyn ByteSwap function
parents 36e07e10 15762b72
......@@ -132,18 +132,13 @@ 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<char> EncodeDynamicEntries(
const cmELF::DynamicEntryList&) = 0;
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()
{
......@@ -246,10 +241,13 @@ public:
return static_cast<unsigned int>(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;
std::vector<char> 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;
......@@ -289,6 +287,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 +325,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)
......@@ -636,30 +524,64 @@ bool cmELFInternalImpl<Types>::LoadDynamicSection()
}
template <class Types>
unsigned int cmELFInternalImpl<Types>::GetDynamicEntryCount()
unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
{
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;
}
if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
return 0;
}
return static_cast<unsigned int>(this->DynamicSectionEntries.size());
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
}
template <class Types>
unsigned long cmELFInternalImpl<Types>::GetDynamicEntryPosition(int j)
cmELF::DynamicEntryList cmELFInternalImpl<Types>::GetDynamicEntries()
{
cmELF::DynamicEntryList result;
// Ensure entries have been read from file
if (!this->LoadDynamicSection()) {
return 0;
return result;
}
if (j < 0 || j >= static_cast<int>(this->DynamicSectionEntries.size())) {
return 0;
// Copy into public array
result.reserve(this->DynamicSectionEntries.size());
for (typename std::vector<ELF_Dyn>::iterator di =
this->DynamicSectionEntries.begin();
di != this->DynamicSectionEntries.end(); ++di) {
ELF_Dyn& dyn = *di;
result.push_back(
std::pair<unsigned long, unsigned long>(dyn.d_tag, dyn.d_un.d_val));
}
ELF_Shdr const& sec = this->SectionHeaders[this->DynamicSectionIndex];
return static_cast<unsigned long>(sec.sh_offset + sec.sh_entsize * j);
return result;
}
template <class Types>
std::vector<char> cmELFInternalImpl<Types>::EncodeDynamicEntries(
const cmELF::DynamicEntryList& entries)
{
std::vector<char> 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<tagtype>(it->first);
dyn.d_un.d_val = static_cast<tagtype>(it->second);
if (this->NeedSwap) {
ByteSwap(dyn);
}
char* pdyn = reinterpret_cast<char*>(&dyn);
result.insert(result.end(), pdyn, pdyn + sizeof(ELF_Dyn));
}
return result;
}
template <class Types>
......@@ -752,6 +674,15 @@ cmELF::StringEntry const* cmELFInternalImpl<Types>::GetDynamicSectionString(
//============================================================================
// External class implementation.
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)
{
......@@ -839,28 +770,31 @@ unsigned int cmELF::GetNumberOfSections() const
return 0;
}
unsigned int cmELF::GetDynamicEntryCount() const
unsigned long cmELF::GetDynamicEntryPosition(int index) const
{
if (this->Valid()) {
return this->Internal->GetDynamicEntryCount();
return this->Internal->GetDynamicEntryPosition(index);
}
return 0;
}
unsigned long cmELF::GetDynamicEntryPosition(int index) const
cmELF::DynamicEntryList cmELF::GetDynamicEntries() const
{
if (this->Valid()) {
return this->Internal->GetDynamicEntryPosition(index);
return this->Internal->GetDynamicEntries();
}
return 0;
return cmELF::DynamicEntryList();
}
bool cmELF::ReadBytes(unsigned long pos, unsigned long size, char* buf) const
std::vector<char> cmELF::EncodeDynamicEntries(
const cmELF::DynamicEntryList& dentries) const
{
if (this->Valid()) {
return this->Internal->ReadBytes(pos, size, buf);
return this->Internal->EncodeDynamicEntries(dentries);
}
return false;
return std::vector<char>();
}
bool cmELF::GetSOName(std::string& soname)
......
......@@ -7,6 +7,8 @@
#include <iosfwd>
#include <string>
#include <utility>
#include <vector>
#if !defined(CMAKE_USE_ELF_PARSER)
#error "This file may be included only if CMAKE_USE_ELF_PARSER is enabled."
......@@ -61,22 +63,27 @@ public:
int IndexInSection;
};
/** Represent entire dynamic section header */
typedef std::vector<std::pair<long, unsigned long> > DynamicEntryList;
/** Get the type of the file opened. */
FileType GetFileType() const;
/** 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;
/** Read bytes from the file. */
bool ReadBytes(unsigned long pos, unsigned long size, char* buf) 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<char> EncodeDynamicEntries(
const DynamicEntryList& entries) const;
/** Get the SONAME field if any. */
bool GetSOName(std::string& soname);
......@@ -91,6 +98,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, TagMipsRldMapRel;
private:
friend class cmELFInternal;
bool Valid() const;
......
......@@ -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,46 @@ 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];
// Get size of one DYNAMIC entry
unsigned long const sizeof_dentry =
elf.GetDynamicEntryPosition(1) - elf.GetDynamicEntryPosition(0);
// 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.";
// 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 {
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;
}
return false;
it++;
}
data += sz;
}
// Encode new entries list
bytes = elf.EncodeDynamicEntries(dentries);
bytesBegin = elf.GetDynamicEntryPosition(0);
}
// Open the file for update.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment