diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 8bd05c5a253fdf9e92433015b8cf5c2a64b9e49d..8d541fe52f612714bc7b0aa60a55c785edf61a63 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1688,8 +1688,9 @@ template void SharedFileExtended::postParseForAdlt() { resolveDuplicatesForAdlt(); } + template -StringRef SharedFileExtended::addAdltPostfix(StringRef input) { +StringRef SharedFileExtended::addAdltPostfix(StringRef input) const { return markItemForAdlt(input, soName); } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index bc3d594189ee8a6b224dd854db638005b1f06191..68d76d5fb48e91a4a02905f67b3eb40bd0e286b3 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -399,7 +399,7 @@ public: void parseForAdlt(); void postParseForAdlt(); - StringRef addAdltPostfix(StringRef input); + StringRef addAdltPostfix(StringRef input) const; bool addAdltPostfix(Symbol *s); bool saveSymbol(const Defined& d) const; @@ -436,6 +436,7 @@ public: void traceSymbol(const Symbol &sym, StringRef title = "") const; void traceSection(const SectionBase &sec, StringRef title = "") const; +public: int dynSymSecIdx = 0; int symTabSecIdx = 0; int symTabShndxSecIdx = 0; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 29135ddb16d79ecc5fdafb0355797abb3f9a5b24..a03781415d6b8e92e14920810ddf2c92bc59cc26 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3950,6 +3950,8 @@ void InStruct::reset() { strTab.reset(); symTab.reset(); symTabShndx.reset(); + adltData.reset(); + adltStrTab.reset(); } constexpr char kMemtagAndroidNoteName[] = "Android"; @@ -3996,6 +3998,264 @@ size_t PackageMetadataNote::getSize() const { alignTo(config->packageMetadata.size() + 1, 4); } + +// OHOS_LOCAL begin +namespace lld { namespace elf { namespace adlt { + +template +AdltSection::AdltSection(StringTableSection& strTabSec) + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".adlt") + , strTabSec(strTabSec) +{ + assert(config->adlt); +} + +template +void AdltSection::finalizeContents() { + soInputs.clear(); + soInputs.reserve(ctx->sharedFilesExtended.size()); + for (InputFile* file : ctx->sharedFilesExtended) { + auto* soext = cast>(file); + soInputs.push_back(makeSoData(soext)); + } + + assert((soInputs.size() < 1<<16) && + "the number of input libs exeeds ELF limit on number of sections"); + const Elf64_Half soNum = soInputs.size(); + + header = AdltSectionHeader{ + {1, 0, 0}, // .schemaVersion + sizeof(PSOD), // .schemaPSODSize + soNum, // .sharedObjectsNum + HashType::MUSL_GNU_HASH, // .stringHashType + getBlobStartOffset(), // .blobStart + estimateBlobSize(), // .blobSize + }; + + buildSonameIndex(); + linkInternalDtNeeded(); + extractInitFiniArray(); +} + +template +void AdltSection::buildSonameIndex() { + for (const auto& it : llvm::enumerate(soInputs)) { + const auto& soData = it.value(); + auto res = sonameToIndexMap.try_emplace( + CachedHashStringRef(soData.soName.ref), it.index()); + if (!res.second) { + warn(Twine(".adlt-section: duplicated soname: ") + soData.soName.ref + + " at pos=" + Twine(it.index()) + + " collided with pos=" + Twine(res.first->second)); + } + } +} + +template +void AdltSection::linkInternalDtNeeded() { + for (auto it : llvm::enumerate(soInputs)) { + auto& soData = it.value(); + for (auto& needed : soData.dtNeededs) { + auto cref = CachedHashStringRef(needed.str.ref); + auto res = sonameToIndexMap.find(cref); + if (res != sonameToIndexMap.end()) { + needed.psodIndex = res->second; + } + } + } +} + +template +OutputSection* AdltSection::findOutSection(StringRef name) { + if (name.empty()) return nullptr; + const unsigned partition = 1; + + for (SectionCommand* cmd : script->sectionCommands) { + if (auto* osd = dyn_cast(cmd)) + if (osd->osec.name == name && osd->osec.partition == partition) + return &osd->osec; + } + return nullptr; +} + +template +void AdltSection::extractInitFiniArray() { + for (auto& soData : soInputs) { + auto initArrayName = soData.initArrayName; + auto finiArrayName = soData.finiArrayName; + soData.initArraySec = findOutSection(initArrayName); + soData.finiArraySec = findOutSection(finiArrayName); + } +} + +template +typename AdltSection::SoData +AdltSection::makeSoData(const SharedFileExtended* soext) { + assert(soext); + SoData data = {}; + StringRef soname = soext->soName; + data.soName = SectionString{soname, strTabSec.addString(soname)}; + + for (const auto& neededName: soext->dtNeeded) { + data.dtNeededs.push_back({ + SectionString{neededName, strTabSec.addString(neededName)}, + {}, // internal PSOD index is uknown by the moment, will be linked + }); + } + + data.initArrayName = soext->addAdltPostfix(".init_array"); + data.finiArrayName = soext->addAdltPostfix(".fini_array"); + + // TODO: + // sharedLocalIndex + // sharedGlobalIndex + + // TODO: get section index for sharedLocalIndex + // TODO: get section index for sharedGlobalIndex + + return data; +} + +template +Elf64_Xword AdltSection::calculateHash(StringRef str) const { + switch(header.stringHashType) { + case HashType::NONE: + return 0x0; + case HashType::MUSL_GNU_HASH: + return hashGnu(str); + case HashType::DEBUG_CONST: + return 0xdeadbeef1337c0de; + default: + llvm_unreachable(".adlt hash type not implemented"); + } +} + +template +PSOD AdltSection::serialize(const SoData& soData) const { + return PSOD { + soData.soName.strtabOff, // .soName + calculateHash(soData.soName.ref), // .soNameHash + soData.initArraySec ? CrossSectionVec{ // .initArray + soData.initArraySec->sectionIndex, + soData.initArraySec->size / sizeof(Elf64_Addr), // size + soData.initArraySec->addr, + } : CrossSectionVec{0, 0, 0}, + soData.finiArraySec ? CrossSectionVec{ // .finiArray + soData.finiArraySec->sectionIndex, + soData.finiArraySec->size / sizeof(Elf64_Addr), // size + soData.finiArraySec->addr, + } : CrossSectionVec{0, 0, 0}, + 0x0, // .dtNeeded // filled by blob serialization + soData.dtNeededs.size(), // .dtNeededSz + CrossSectionRef { + 0, // .sectionIndex + soData.sharedLocalIndex, // .offsetFromStart + }, // .sharedLocalSymbolIndex + CrossSectionRef { + 0, // .sectionIndex + soData.sharedGlobalIndex, // .offsetFromStart + }, // .sharedGlobalSymbolIndex + }; +} + +template +Elf64_Off AdltSection::getBlobStartOffset() const { + return sizeof(header) + sizeof(PSOD) * soInputs.size(); +} + +template +size_t AdltSection::estimateBlobSize() const { + size_t blobSize = sizeof(BlobStartMark); + + for (const auto& soData: soInputs) { + blobSize += sizeof(DtNeededIndex) * soData.dtNeededs.size(); + }; + + return blobSize; +} + +template +size_t AdltSection::writeDtNeededVec( + uint8_t* buff, const DtNeededsVec& neededVec) const { + if (neededVec.empty()) return 0; + + SmallVector needIndexes; + needIndexes.reserve(neededVec.size()); + for (const auto& need_data : neededVec) { + needIndexes.push_back(DtNeededIndex{ + need_data.psodIndex.has_value(), // .hasInternalPSOD + need_data.psodIndex.value_or(0), // .PSODindex + need_data.str.strtabOff, // .sonameOffset + }); + } + + memcpy(buff, needIndexes.data(), needIndexes.size_in_bytes()); + return needIndexes.size_in_bytes(); +} + +template +void AdltSection::writeTo(uint8_t* buf) { + // TODO: take care of endianness, use write32 / write64 etc. + // pre-serialized SoData, enriched with offsets during blob writing + SmallVector psods; + + for (const auto& it: llvm::enumerate(soInputs)) { + const SoData& soData = it.value(); + PSOD psod = serialize(soData); + psods.push_back(psod); + } + + // serialize blob data + { + uint8_t* const blob_buf = buf + header.blobStart; + size_t blob_off = 0; + memcpy(blob_buf + blob_off, &BlobStartMark, sizeof(BlobStartMark)); + blob_off += sizeof(BlobStartMark); + + // dt-needed + for(const auto& it : llvm::enumerate(soInputs)) { + const auto& soData = it.value(); + PSOD& psod = psods[it.index()]; + + psod.dtNeededSz = soData.dtNeededs.size(); + psod.dtNeeded = blob_off; + blob_off += writeDtNeededVec(blob_buf + blob_off, soData.dtNeededs); + } + + // finalize header.blobSize + assert((blob_off <= header.blobSize) && + ".adlt-section: blob output exeeds its initial estimation"); + header.blobSize = blob_off; + } + + // header + { + memcpy(buf, &header, sizeof(header)); + } + + // PSODs + { + uint8_t* const psods_buf = buf + sizeof(header); + size_t psods_off = 0; + for (const auto& it: llvm::enumerate(soInputs)) { + PSOD& psod = psods[it.index()]; + memcpy(psods_buf + psods_off, &psod, sizeof(PSOD)); + psods_off += sizeof(PSOD); + } + } +} + +template +size_t AdltSection::getSize() const { + const size_t pre_blob_size = sizeof(header) + sizeof(PSOD) * soInputs.size(); + assert(pre_blob_size <= header.blobStart); + return header.blobStart + header.blobSize; +} + +}}} // namespace lld::elf::adlt +// OHOS_LOCAL end + + InStruct elf::in; std::vector elf::partitions; @@ -4084,3 +4344,8 @@ template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; template class elf::PartitionProgramHeadersSection; + +template class elf::adlt::AdltSection; +template class elf::adlt::AdltSection; +template class elf::adlt::AdltSection; +template class elf::adlt::AdltSection; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 83a2bd7d34dfd0efd99cb12b442793d340dcfec8..48edc79a718d6822273cc7843373aac5eafa8cb9 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -34,6 +34,7 @@ namespace elf { class Defined; struct PhdrEntry; class SymbolTableBaseSection; +template class SharedFileExtended; class SyntheticSection : public InputSection { public: @@ -1220,6 +1221,149 @@ public: size_t getSize() const override; }; + +namespace adlt { + +using llvm::ELF::Elf64_Half; +using llvm::ELF::Elf64_Off; +using llvm::ELF::Elf64_Addr; +using llvm::ELF::Elf64_Word; +using llvm::ELF::Elf64_Xword; +using Elf64_Byte = uint8_t; + +struct CrossSectionRef { + Elf64_Word sectionIndex; + Elf64_Off offsetFromStart; +}; + +struct SemanticVersion { + Elf64_Half major: 6; + Elf64_Half minor: 6; + Elf64_Half patch: 4; +}; + +static_assert( + sizeof(SemanticVersion) == sizeof(Elf64_Half), + ".adlt semantic version is designed to occupy uint16_t" +); + +enum HashType : Elf64_Byte { + NONE = 0, + MUSL_GNU_HASH = 1, + MUSL_SYSV_HASH = 2, + MUSL_KEYHASH = 3, + DEBUG_CONST = 0xff, +}; + +struct DtNeededIndex { + bool hasInternalPSOD : 1; // true if soname + Elf64_Off PSODindex : 16; // PSOD in the current ADLT image + Elf64_Off sonameOffset : 47; // string start in bound strTabSec +}; + +static_assert( + sizeof(DtNeededIndex) == sizeof(Elf64_Off), + "DtNeededIndex have to be an offset with intrused flags" +); + +struct CrossSectionVec { + Elf64_Xword secIndex; + Elf64_Xword numElem; + Elf64_Addr addr; +}; + +// Serializable representation per-shared-object-data in .adlt section +struct PSOD { + Elf64_Off soName; // offset in strTabSec + Elf64_Xword soNameHash; + CrossSectionVec initArray; + CrossSectionVec finiArray; + Elf64_Off dtNeeded; // offset to DtNeededIndex[] in blob + Elf64_Xword dtNeededSz; + CrossSectionRef sharedLocalSymbolIndex; + CrossSectionRef sharedGlobalSymbolIndex; +}; + +struct AdltSectionHeader { + SemanticVersion schemaVersion = {1, 0, 0}; + Elf64_Half schemaPSODSize = sizeof(PSOD); + Elf64_Half sharedObjectsNum; + HashType stringHashType = HashType::NONE; + Elf64_Off blobStart; // binary blob start offset from the .adlt start + Elf64_Xword blobSize; +}; + +constexpr char BlobStartMark[4] = {0xA, 0xD, 0x1, 0x7}; + + +template +class AdltSection final : public SyntheticSection { +public: + struct SectionString { + StringRef ref; + Elf64_Off strtabOff; // offset in strTabSec + }; + + // will be serialized to DtNeededIndex + struct DtNeededData { + SectionString str; + llvm::Optional psodIndex; + }; + + using SectionStringVector = SmallVector; + using DtNeededsVec = SmallVector; + + // will be serialized to PSOD + struct SoData { + SectionString soName; + DtNeededsVec dtNeededs; + + StringRef initArrayName; + StringRef finiArrayName; + + OutputSection* initArraySec; + OutputSection* finiArraySec; + + Elf64_Off sharedLocalIndex; // TODO + Elf64_Off sharedGlobalIndex; // TODO + }; + + +public: + AdltSection(StringTableSection& strTabSec); + + void writeTo(uint8_t* buf) override; + size_t getSize() const override; + void finalizeContents() override; + + Elf64_Off getBlobStartOffset() const; + +private: + static OutputSection* findOutSection(StringRef name); + + void buildSonameIndex(); + void linkInternalDtNeeded(); + void extractInitFiniArray(); + + Elf64_Xword calculateHash(StringRef str) const; + SoData makeSoData(const SharedFileExtended*); + PSOD serialize(const SoData&) const; + + size_t estimateBlobSize() const; + size_t writeDtNeededVec(uint8_t* buff, const DtNeededsVec& neededVec) const; + +private: + StringTableSection& strTabSec; + + AdltSectionHeader header = {}; + SmallVector soInputs; + llvm::DenseMap sonameToIndexMap; +}; + +} // namespace adlt + + + InputSection *createInterpSection(); MergeInputSection *createCommentSection(); template void splitSections(); @@ -1295,6 +1439,8 @@ struct InStruct { std::unique_ptr strTab; std::unique_ptr symTab; std::unique_ptr symTabShndx; + std::unique_ptr adltData; + std::unique_ptr adltStrTab; void reset(); }; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index de16dec8e6098c52d90dce222ea2b6bd438acc57..318a9bf2d86d0a0372e9d812464ae65409ac83fb 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -312,6 +312,13 @@ template void elf::createSyntheticSections() { in.symTabShndx = std::make_unique(); } + if (config->adlt) { + in.adltStrTab = std::make_unique(".adlt.strtab", false); + in.adltData = std::make_unique>(*in.adltStrTab); + add(*in.adltStrTab); + add(*in.adltData); + } + in.bss = std::make_unique(".bss", 0, 1); add(*in.bss); @@ -2127,6 +2134,11 @@ template void Writer::finalizeSections() { finalizeSynthetic(in.iplt.get()); finalizeSynthetic(in.ppc32Got2.get()); finalizeSynthetic(in.partIndex.get()); + + if (config->adlt) { + finalizeSynthetic(in.adltData.get()); + finalizeSynthetic(in.adltStrTab.get()); + } // Dynamic section must be the last one in this list and dynamic // symbol table section (dynSymTab) must be the first one.