mirror of
https://github.com/intel/compute-runtime.git
synced 2025-12-21 09:14:47 +08:00
feature: Improving elf rewriter - preserving strings
Original string section needs to be preserved so that symbol table does not get broken. Related-To: NEO-10190 Signed-off-by: Chodor, Jaroslaw <jaroslaw.chodor@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
fbb8fa7dea
commit
4116dd5c9e
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace NEO {
|
||||
@@ -25,15 +26,39 @@ struct StringSectionBuilder {
|
||||
undefStringIdx = 0U;
|
||||
}
|
||||
|
||||
void setInitialStringsTab(ArrayRef<const uint8_t> data) {
|
||||
DEBUG_BREAK_IF(stringTable.size() > 1);
|
||||
stringTable.assign(reinterpret_cast<const char *>(data.begin()), reinterpret_cast<const char *>(data.end()));
|
||||
if (stringTable.size() < 1) {
|
||||
stringTable.push_back('\0');
|
||||
}
|
||||
if (*stringTable.rbegin() != '\0') {
|
||||
stringTable.push_back('\0');
|
||||
}
|
||||
auto it = stringTable.begin() + 1;
|
||||
while (it != stringTable.end()) {
|
||||
stringOffsetsMap[std::string(&*it)] = static_cast<uint32_t>(it - stringTable.begin());
|
||||
while (*it != '\0') {
|
||||
++it;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t appendString(ConstStringRef str) {
|
||||
if (str.empty()) {
|
||||
return undefStringIdx;
|
||||
}
|
||||
auto existingEntry = stringOffsetsMap.find(str.str());
|
||||
if (stringOffsetsMap.end() != existingEntry) {
|
||||
return existingEntry->second;
|
||||
}
|
||||
uint32_t offset = static_cast<uint32_t>(stringTable.size());
|
||||
stringTable.insert(stringTable.end(), str.begin(), str.end());
|
||||
if (str[str.size() - 1] != '\0') {
|
||||
stringTable.push_back('\0');
|
||||
}
|
||||
stringOffsetsMap[str.str()] = offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -47,6 +72,7 @@ struct StringSectionBuilder {
|
||||
|
||||
protected:
|
||||
std::vector<char> stringTable;
|
||||
std::unordered_map<std::string, uint32_t> stringOffsetsMap;
|
||||
uint32_t undefStringIdx;
|
||||
};
|
||||
|
||||
@@ -55,6 +81,10 @@ struct ElfEncoder {
|
||||
ElfEncoder(bool addUndefSectionHeader = true, bool addHeaderSectionNamesSection = true,
|
||||
typename ElfSectionHeaderTypes<numBits>::AddrAlign defaultDataAlignment = 8U);
|
||||
|
||||
void setInitialStringsTab(ArrayRef<const uint8_t> data) {
|
||||
strSecBuilder.setInitialStringsTab(data);
|
||||
}
|
||||
|
||||
ElfSectionHeader<numBits> &appendSection(const ElfSectionHeader<numBits> §ionHeader, const ArrayRef<const uint8_t> sectionData);
|
||||
ElfProgramHeader<numBits> &appendSegment(const ElfProgramHeader<numBits> &programHeader, const ArrayRef<const uint8_t> segmentData);
|
||||
|
||||
|
||||
@@ -22,37 +22,37 @@ namespace NEO {
|
||||
|
||||
namespace Elf {
|
||||
|
||||
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
|
||||
template <ElfIdentifierClass numBits = NEO::Elf::EI_CLASS_64>
|
||||
struct MutableSectionHeader {
|
||||
MutableSectionHeader(const std::string &name, const NEO::Elf::ElfSectionHeader<NumBits> &header, const std::vector<uint8_t> &data)
|
||||
MutableSectionHeader(const std::string &name, const NEO::Elf::ElfSectionHeader<numBits> &header, const std::vector<uint8_t> &data)
|
||||
: name(name), header(header), data(data) {
|
||||
}
|
||||
std::string name;
|
||||
NEO::Elf::ElfSectionHeader<NumBits> header{};
|
||||
NEO::Elf::ElfSectionHeader<numBits> header{};
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
|
||||
template <ElfIdentifierClass numBits = NEO::Elf::EI_CLASS_64>
|
||||
struct MutableProgramHeader {
|
||||
MutableProgramHeader(const NEO::Elf::ElfProgramHeader<NumBits> &header, const std::vector<uint8_t> &data)
|
||||
MutableProgramHeader(const NEO::Elf::ElfProgramHeader<numBits> &header, const std::vector<uint8_t> &data)
|
||||
: header(header), data(data) {
|
||||
}
|
||||
NEO::Elf::ElfProgramHeader<NumBits> header = {};
|
||||
NEO::Elf::ElfProgramHeader<numBits> header = {};
|
||||
std::vector<uint8_t> data;
|
||||
MutableSectionHeader<NumBits> *referencedSectionData = nullptr;
|
||||
MutableSectionHeader<numBits> *referencedSectionData = nullptr;
|
||||
};
|
||||
|
||||
template <ElfIdentifierClass NumBits = NEO::Elf::EI_CLASS_64>
|
||||
template <ElfIdentifierClass numBits = NEO::Elf::EI_CLASS_64>
|
||||
struct ElfRewriter {
|
||||
using SectionId = uint32_t;
|
||||
|
||||
ElfRewriter(NEO::Elf::Elf<NumBits> &src) {
|
||||
ElfRewriter(NEO::Elf::Elf<numBits> &src) {
|
||||
elfFileHeader = *src.elfFileHeader;
|
||||
for (const auto &sh : src.sectionHeaders) {
|
||||
this->sectionHeaders.push_back(std::make_unique<MutableSectionHeader<NumBits>>(src.getName(sh.header->name), *sh.header, std::vector<uint8_t>{sh.data.begin(), sh.data.end()}));
|
||||
this->sectionHeaders.push_back(std::make_unique<MutableSectionHeader<numBits>>(src.getName(sh.header->name), *sh.header, std::vector<uint8_t>{sh.data.begin(), sh.data.end()}));
|
||||
}
|
||||
for (const auto &ph : src.programHeaders) {
|
||||
this->programHeaders.push_back(std::make_unique<MutableProgramHeader<NumBits>>(*ph.header, std::vector<uint8_t>{ph.data.begin(), ph.data.end()}));
|
||||
this->programHeaders.push_back(std::make_unique<MutableProgramHeader<numBits>>(*ph.header, std::vector<uint8_t>{ph.data.begin(), ph.data.end()}));
|
||||
for (const auto &sh : this->sectionHeaders) {
|
||||
if ((sh->header.offset == ph.header->offset) && (sh->header.size == ph.header->fileSz)) {
|
||||
(*this->programHeaders.rbegin())->referencedSectionData = sh.get();
|
||||
@@ -62,15 +62,20 @@ struct ElfRewriter {
|
||||
}
|
||||
|
||||
std::vector<uint8_t> encode() const {
|
||||
NEO::Elf::ElfEncoder<NumBits> encoder;
|
||||
NEO::Elf::ElfEncoder<numBits> encoder{};
|
||||
for (const auto &sh : this->sectionHeaders) {
|
||||
if (sh->header.type == SHT_STRTAB) {
|
||||
encoder.setInitialStringsTab(sh->data);
|
||||
}
|
||||
}
|
||||
encoder.getElfFileHeader() = elfFileHeader;
|
||||
std::unordered_map<MutableSectionHeader<NumBits> *, decltype(NEO::Elf::ElfSectionHeader<NumBits>::offset)> encodedSectionsOffsets;
|
||||
std::unordered_map<MutableSectionHeader<numBits> *, decltype(NEO::Elf::ElfSectionHeader<numBits>::offset)> encodedSectionsOffsets;
|
||||
for (const auto &sh : this->sectionHeaders) {
|
||||
if ((sh->header.type == SHT_NULL) || (sh->header.type == SHT_STRTAB)) {
|
||||
continue;
|
||||
}
|
||||
auto nameIdx = encoder.appendSectionName(sh->name);
|
||||
NEO::Elf::ElfSectionHeader<NumBits> header = sh->header;
|
||||
NEO::Elf::ElfSectionHeader<numBits> header = sh->header;
|
||||
header.name = nameIdx;
|
||||
encodedSectionsOffsets[sh.get()] = encoder.appendSection(header, sh->data).offset;
|
||||
}
|
||||
@@ -86,7 +91,7 @@ struct ElfRewriter {
|
||||
return encoder.encode();
|
||||
}
|
||||
|
||||
StackVec<SectionId, 16> findSections(typename ElfSectionHeaderTypes<NumBits>::Type type, ConstStringRef name) {
|
||||
StackVec<SectionId, 16> findSections(typename ElfSectionHeaderTypes<numBits>::Type type, ConstStringRef name) {
|
||||
StackVec<SectionId, 16> ret;
|
||||
for (size_t i = 0; i < this->sectionHeaders.size(); i++) {
|
||||
auto §ion = this->sectionHeaders[i];
|
||||
@@ -97,7 +102,7 @@ struct ElfRewriter {
|
||||
return ret;
|
||||
}
|
||||
|
||||
MutableSectionHeader<NumBits> &getSection(SectionId idx) {
|
||||
MutableSectionHeader<numBits> &getSection(SectionId idx) {
|
||||
return *sectionHeaders[idx];
|
||||
}
|
||||
|
||||
@@ -114,11 +119,11 @@ struct ElfRewriter {
|
||||
}
|
||||
}
|
||||
|
||||
ElfFileHeader<NumBits> elfFileHeader = {};
|
||||
ElfFileHeader<numBits> elfFileHeader = {};
|
||||
|
||||
protected:
|
||||
StackVec<std::unique_ptr<MutableSectionHeader<NumBits>>, 32> sectionHeaders;
|
||||
StackVec<std::unique_ptr<MutableProgramHeader<NumBits>>, 32> programHeaders;
|
||||
StackVec<std::unique_ptr<MutableSectionHeader<numBits>>, 32> sectionHeaders;
|
||||
StackVec<std::unique_ptr<MutableProgramHeader<numBits>>, 32> programHeaders;
|
||||
};
|
||||
|
||||
} // namespace Elf
|
||||
|
||||
@@ -501,12 +501,33 @@ TEST(ElfEncoder, WhenGetSectionHeaderIndexIsCalledThenCorrectSectionIdxIsReturne
|
||||
EXPECT_EQ(1U, elfEncoder64.getSectionHeaderIndex(sec1));
|
||||
}
|
||||
|
||||
TEST(DecodeElfNoteSection, givenZeroNotesToEncodeThenReturnsEmptyDataVector) {
|
||||
TEST(ElfEncoder, givenEmptyArrayWhenSetInitialStringTabIsUsedThenResetsStringTabToEmpty) {
|
||||
ElfEncoder<EI_CLASS_64> elfEncoder;
|
||||
elfEncoder.setInitialStringsTab({});
|
||||
EXPECT_EQ(0U, elfEncoder.appendSectionName({}));
|
||||
}
|
||||
|
||||
TEST(ElfEncoder, givenUnterminatedArrayWhenSetInitialStringTabIsUsedThenTerminateUnderlyingArray) {
|
||||
ElfEncoder<EI_CLASS_64> elfEncoder;
|
||||
char data[2] = {'\0', 's'};
|
||||
elfEncoder.setInitialStringsTab(ArrayRef<const uint8_t>::fromAny(data, sizeof(data)));
|
||||
EXPECT_EQ(1U, elfEncoder.appendSectionName("s"));
|
||||
}
|
||||
|
||||
TEST(ElfEncoder, givenArrayWhenSetInitialStringTabIsUsedThenIncorporateItToInternalStringTab) {
|
||||
ElfEncoder<EI_CLASS_64> elfEncoder;
|
||||
char data[] = "\0string0\0string1";
|
||||
elfEncoder.setInitialStringsTab(ArrayRef<const uint8_t>::fromAny(data, sizeof(data)));
|
||||
EXPECT_EQ(1U, elfEncoder.appendSectionName("string0"));
|
||||
EXPECT_EQ(9U, elfEncoder.appendSectionName("string1"));
|
||||
}
|
||||
|
||||
TEST(EncodeElfNoteSection, givenZeroNotesToEncodeThenReturnsEmptyDataVector) {
|
||||
auto encoded = NEO::Elf::encodeNoteSectionData({});
|
||||
EXPECT_TRUE(encoded.empty());
|
||||
}
|
||||
|
||||
TEST(DecodeElfNoteSection, givenValidNotesToEncodeThenReturnsProperlyEncodedData) {
|
||||
TEST(EncodeElfNoteSection, givenValidNotesToEncodeThenReturnsProperlyEncodedData) {
|
||||
std::string unalignedDescName = "note"
|
||||
"Type";
|
||||
std::string unalignedDesc = "some"
|
||||
|
||||
@@ -18,18 +18,18 @@ inline bool operator==(const ElfFileHeaderIdentity &lhs, const ElfFileHeaderIden
|
||||
return (lhs.abiVersion == rhs.abiVersion) && (lhs.data == rhs.data) && (lhs.eClass == rhs.eClass) && (lhs.osAbi == rhs.osAbi) && (lhs.version == rhs.version) && (lhs.magic[0] == rhs.magic[0]) && (lhs.magic[1] == rhs.magic[1]) && (lhs.magic[2] == rhs.magic[2]) && (lhs.magic[3] == rhs.magic[3]);
|
||||
}
|
||||
|
||||
template <ElfIdentifierClass NumBits>
|
||||
inline bool operator==(const ElfFileHeader<NumBits> &lhs, const ElfFileHeader<NumBits> &rhs) {
|
||||
template <ElfIdentifierClass numBits>
|
||||
inline bool operator==(const ElfFileHeader<numBits> &lhs, const ElfFileHeader<numBits> &rhs) {
|
||||
return (lhs.identity == rhs.identity) && (lhs.type == rhs.type) && (lhs.machine == rhs.machine) && (lhs.version == rhs.version) && (lhs.entry == rhs.entry) && (lhs.phOff == rhs.phOff) && (lhs.shOff == rhs.shOff) && (lhs.flags == rhs.flags) && (lhs.ehSize == rhs.ehSize) && (lhs.phEntSize == rhs.phEntSize) && (lhs.phNum == rhs.phNum) && (lhs.shEntSize == rhs.shEntSize) && (lhs.shNum == rhs.shNum) && (lhs.shStrNdx == rhs.shStrNdx);
|
||||
}
|
||||
|
||||
template <ElfIdentifierClass NumBits>
|
||||
inline bool operator==(const SectionHeaderAndData<NumBits> &lhs, const SectionHeaderAndData<NumBits> &rhs) {
|
||||
template <ElfIdentifierClass numBits>
|
||||
inline bool operator==(const SectionHeaderAndData<numBits> &lhs, const SectionHeaderAndData<numBits> &rhs) {
|
||||
return (lhs.header->name == rhs.header->name) && (lhs.header->type == rhs.header->type) && (lhs.header->flags == rhs.header->flags) && (lhs.header->addr == rhs.header->addr) && (lhs.header->offset == rhs.header->offset) && (lhs.header->size == rhs.header->size) && (lhs.header->link == rhs.header->link) && (lhs.header->info == rhs.header->info) && (lhs.header->addralign == rhs.header->addralign) && (lhs.header->entsize == rhs.header->entsize) && (lhs.data.size() == rhs.data.size()) && ((lhs.data.size() == 0) || (0 == memcmp(lhs.data.begin(), rhs.data.begin(), lhs.data.size())));
|
||||
}
|
||||
|
||||
template <ElfIdentifierClass NumBits>
|
||||
inline bool operator==(const ProgramHeaderAndData<NumBits> &lhs, const ProgramHeaderAndData<NumBits> &rhs) {
|
||||
template <ElfIdentifierClass numBits>
|
||||
inline bool operator==(const ProgramHeaderAndData<numBits> &lhs, const ProgramHeaderAndData<numBits> &rhs) {
|
||||
return (lhs.header->type == rhs.header->type) && (lhs.header->offset == rhs.header->offset) && (lhs.header->vAddr == rhs.header->vAddr) && (lhs.header->pAddr == rhs.header->pAddr) && (lhs.header->fileSz == rhs.header->fileSz) && (lhs.header->memSz == rhs.header->memSz) && (lhs.header->flags == rhs.header->flags) && (lhs.header->align == rhs.header->align) && (lhs.data.size() == rhs.data.size()) && ((lhs.data.size() == 0) || (0 == memcmp(lhs.data.begin(), rhs.data.begin(), lhs.data.size())));
|
||||
}
|
||||
|
||||
@@ -122,3 +122,29 @@ TEST(ElfRewriterRemoveSection, GivenSectionIndexThenRemovesThatSection) {
|
||||
EXPECT_TRUE(err.empty()) << err;
|
||||
EXPECT_TRUE(warn.empty()) << warn;
|
||||
}
|
||||
|
||||
TEST(ElfRewriter, GivenElfThenPreservesNamesOffsets) {
|
||||
NEO::Elf::ElfEncoder<> encoder;
|
||||
std::vector<uint8_t> txtData;
|
||||
txtData.resize(4096U, 7);
|
||||
auto name0Idx = encoder.appendSectionName("name0");
|
||||
auto &txtSection = encoder.appendSection(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt", txtData);
|
||||
auto name2Idx = encoder.appendSectionName("name2");
|
||||
encoder.appendProgramHeaderLoad(encoder.getSectionHeaderIndex(txtSection), 4096U, 4096U);
|
||||
auto elfBinSrc = encoder.encode();
|
||||
|
||||
std::string err, warn;
|
||||
auto decodedElfSrc = NEO::Elf::decodeElf(elfBinSrc, err, warn);
|
||||
ASSERT_TRUE(err.empty()) << err;
|
||||
ASSERT_TRUE(warn.empty()) << warn;
|
||||
NEO::Elf::ElfRewriter<> rewriter{decodedElfSrc};
|
||||
auto elfBinOut = rewriter.encode();
|
||||
|
||||
ASSERT_EQ(elfBinSrc.size(), elfBinOut.size());
|
||||
auto decodedElfOut = NEO::Elf::decodeElf(elfBinOut, err, warn);
|
||||
ASSERT_TRUE(err.empty()) << err;
|
||||
ASSERT_TRUE(warn.empty()) << warn;
|
||||
EXPECT_EQ(1U, rewriter.findSections(NEO::Elf::SectionHeaderType::SHT_PROGBITS, ".txt").size());
|
||||
EXPECT_EQ("name0", decodedElfOut.getName(name0Idx));
|
||||
EXPECT_EQ("name2", decodedElfOut.getName(name2Idx));
|
||||
}
|
||||
Reference in New Issue
Block a user