From 767f4453192542b3569116a37e9dbb73ef529c31 Mon Sep 17 00:00:00 2001 From: Parth Arora Date: Fri, 5 Dec 2025 03:01:10 -0800 Subject: [PATCH] Update CHECK_LINK_STATES to account for ActBefore states This commit updates CHECK_LINK_STATE functionality in the plugin framework to account for the ActBefore states. Until now, these link states did not exist in the linker and thus the plugin framework could not have checks for these states. Resolves #655 Signed-off-by: Parth Arora --- include/eld/Core/LinkState.h | 8 +++ include/eld/PluginAPI/LinkerWrapper.h | 10 +++- lib/Core/Linker.cpp | 1 + lib/Core/Module.cpp | 3 +- lib/LayoutMap/TextLayoutPrinter.cpp | 6 +- lib/LinkerWrapper/CheckLinkState.h | 19 ++++++- lib/LinkerWrapper/LinkerWrapper.cpp | 57 ++++++++++++++----- lib/LinkerWrapper/PluginADT.cpp | 8 +-- lib/Object/ObjectLinker.cpp | 4 ++ lib/Writers/ELFObjectWriter.cpp | 1 + .../InvalidStateOverrideLSRule.test | 2 +- .../AllOutSectAddresses.test | 2 +- 12 files changed, 91 insertions(+), 30 deletions(-) diff --git a/include/eld/Core/LinkState.h b/include/eld/Core/LinkState.h index 7e1bf0396..44fff6c18 100644 --- a/include/eld/Core/LinkState.h +++ b/include/eld/Core/LinkState.h @@ -30,10 +30,14 @@ namespace eld { enum LinkState : uint8_t { Unknown, Initializing, + ActBeforeRuleMatching, BeforeLayout, + ActBeforeSectionMerging, CreatingSections, + ActBeforePerformingLayout, CreatingSegments, AfterLayout, + ActBeforeWritingOutput }; static inline llvm::StringRef getLinkStateStrRef(LinkState State) { @@ -43,10 +47,14 @@ static inline llvm::StringRef getLinkStateStrRef(LinkState State) { switch (State) { ADD_CASE(Unknown) ADD_CASE(Initializing) + ADD_CASE(ActBeforeRuleMatching) ADD_CASE(BeforeLayout) + ADD_CASE(ActBeforeSectionMerging) ADD_CASE(CreatingSections) + ADD_CASE(ActBeforePerformingLayout) ADD_CASE(CreatingSegments) ADD_CASE(AfterLayout) + ADD_CASE(ActBeforeWritingOutput) } #undef ADD_CASE llvm_unreachable("Invalid LinkState"); diff --git a/include/eld/PluginAPI/LinkerWrapper.h b/include/eld/PluginAPI/LinkerWrapper.h index 2a2e24c07..39581b14c 100644 --- a/include/eld/PluginAPI/LinkerWrapper.h +++ b/include/eld/PluginAPI/LinkerWrapper.h @@ -805,14 +805,22 @@ class DLL_A_EXPORT LinkerWrapper { bool doNotUseRMName = false); bool isLinkStateInitializing() const; + bool isLinkStateActBeforeRuleMatching() const; + bool isLinkStateBeforeLayout() const; + bool isLinkStateActBeforeSectionMerging() const; + bool isLinkStateCreatingSections() const; - bool isLinkStateAfterLayout() const; + bool isLinkStateActBeforePerformingLayout() const; bool isLinkStateCreatingSegments() const; + bool isLinkStateAfterLayout() const; + + bool isLinkStateActBeforeWritingOutput() const; + private: uint8_t getLinkState() const; diff --git a/lib/Core/Linker.cpp b/lib/Core/Linker.cpp index 02029e81e..67a7ffc86 100644 --- a/lib/Core/Linker.cpp +++ b/lib/Core/Linker.cpp @@ -471,6 +471,7 @@ bool Linker::resolve() { } PluginManager &PM = ThisModule->getPluginManager(); + ThisModule->setLinkState(LinkState::ActBeforeRuleMatching); PM.callActBeforeRuleMatchingHook(); // Assign output sections. diff --git a/lib/Core/Module.cpp b/lib/Core/Module.cpp index 298c0a16a..71afa0adb 100644 --- a/lib/Core/Module.cpp +++ b/lib/Core/Module.cpp @@ -508,7 +508,8 @@ void Module::addSymbolCreatedByPluginToFragment(Fragment *F, std::string Symbol, const eld::Plugin *Plugin) { LayoutInfo *layoutInfo = getLayoutInfo(); LDSymbol *S = SymbolNamePool.createPluginSymbol( - getInternalInput(Module::InternalInputType::Plugin), Symbol, F, Val, layoutInfo); + getInternalInput(Module::InternalInputType::Plugin), Symbol, F, Val, + layoutInfo); if (S && layoutInfo && layoutInfo->showSymbolResolution()) SymbolNamePool.getSRI().recordPluginSymbol(S, Plugin); PluginFragmentToSymbols[F]; diff --git a/lib/LayoutMap/TextLayoutPrinter.cpp b/lib/LayoutMap/TextLayoutPrinter.cpp index 354f3d8fc..4acda18c2 100644 --- a/lib/LayoutMap/TextLayoutPrinter.cpp +++ b/lib/LayoutMap/TextLayoutPrinter.cpp @@ -699,7 +699,7 @@ void TextLayoutPrinter::printFragInfo(Fragment *Frag, LayoutFragmentInfo *Info, std::optional AddressOrOffset; bool HasFragInfo = - (M.isLinkStateCreatingSegments() || M.isLinkStateAfterLayout()); + (M.getState() >= LinkState::ActBeforePerformingLayout); if (llvm::isa(Frag) && !M.isLinkStateBeforeLayout()) { auto *Strings = llvm::cast(Frag); for (MergeableString &S : Strings->getStrings()) { @@ -856,8 +856,8 @@ void TextLayoutPrinter::printFrag(eld::Module &CurModule, ELFSection *Section, const LayoutInfo::RemoveSymbolOpsMapT RemovedSymbols = ThisLayoutInfo->getRemovedSymbols(); - bool HasFragOffsets = (CurModule.isLinkStateCreatingSegments() || - CurModule.isLinkStateAfterLayout()); + bool HasFragOffsets = + (CurModule.getState() >= LinkState::ActBeforePerformingLayout); for (Syms = FragmentInfo->Symbols.begin(); Syms != EndSymbols; ++Syms) { // Handle weak symbols. diff --git a/lib/LinkerWrapper/CheckLinkState.h b/lib/LinkerWrapper/CheckLinkState.h index dc807db9d..19a74aa31 100644 --- a/lib/LinkerWrapper/CheckLinkState.h +++ b/lib/LinkerWrapper/CheckLinkState.h @@ -26,20 +26,33 @@ static inline bool isValidLinkState(const eld::plugin::LinkerWrapper &LW, std::initializer_list ValidLinkStates) { for (const auto &S : ValidLinkStates) { - [[maybe_unused]] bool b = S == "Initializing" || S == "BeforeLayout" || - S == "CreatingSections" || - S == "CreatingSegments" || S == "AfterLayout"; + [[maybe_unused]] bool b = S == "Initializing" || S == "ActBeforeRuleMatching" || + S == "BeforeLayout" || S == "ActBeforeSectionMerging" || + S == "CreatingSections" || S == "ActBeforePerformingLayout" || + S == "CreatingSegments" || S == "AfterLayout" || + S == "ActBeforeWritingOutput"; ASSERT(b, "Invalid link state: " + std::string(S)); if (S == "Initializing" && LW.isLinkStateInitializing()) return true; + if (S == "ActBeforeRuleMatching" && LW.isLinkStateActBeforeRuleMatching()) + return true; if (S == "BeforeLayout" && LW.isLinkStateBeforeLayout()) return true; + if (S == "ActBeforeSectionMerging" && + LW.isLinkStateActBeforeSectionMerging()) + return true; if (S == "CreatingSections" && LW.isLinkStateCreatingSections()) return true; + if (S == "PerformingLayout" && LW.isLinkStateBeforeLayout()) + return true; if (S == "CreatingSegments" && LW.isLinkStateCreatingSegments()) return true; + if (S == "ActBeforePerformingLayout" && LW.isLinkStateActBeforePerformingLayout()) + return true; if (S == "AfterLayout" && LW.isLinkStateAfterLayout()) return true; + if (S == "ActBeforeWritingOutput" && LW.isLinkStateActBeforeWritingOutput()) + return true; } return false; } diff --git a/lib/LinkerWrapper/LinkerWrapper.cpp b/lib/LinkerWrapper/LinkerWrapper.cpp index d107368c0..d7da176dd 100644 --- a/lib/LinkerWrapper/LinkerWrapper.cpp +++ b/lib/LinkerWrapper/LinkerWrapper.cpp @@ -176,7 +176,8 @@ LinkerWrapper::getOutputSection(Section &S) const { eld::Expected> LinkerWrapper::getOutputSectionContents(OutputSection &O) const { - CHECK_LINK_STATE(*this, "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "CreatingSegments", "AfterLayout", + "ActBeforeWritingOutput"); if (O.getOutputSection()->getSection()->isNoBits()) return std::make_unique( Diag::error_nobits_unsupported, std::vector{O.getName()}); @@ -218,7 +219,8 @@ eld::Expected LinkerWrapper::reassignVirtualAddresses() { } eld::Expected> LinkerWrapper::getSegmentTable() const { - CHECK_LINK_STATE(*this, "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "CreatingSegments", "AfterLayout", + "ActBeforeWritingOutput"); std::vector Segments; for (auto *S : m_Module.getBackend().elfSegmentTable()) Segments.push_back(Segment(S)); @@ -263,7 +265,9 @@ eld::Expected LinkerWrapper::doRelocation() { } eld::Expected LinkerWrapper::addChunkToOutput(Chunk C) { - CHECK_LINK_STATE(*this, "CreatingSections", "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "ActBeforeSectionMerging", "CreatingSections", + "ActBeforePerformingLayout", "CreatingSegments", + "AfterLayout"); auto ExpMapping = getOutputSectionAndRule(C.getSection()); if (!ExpMapping) @@ -290,7 +294,8 @@ eld::Expected LinkerWrapper::addChunkToOutput(Chunk C) { } eld::Expected LinkerWrapper::resetOffset(OutputSection O) { - CHECK_LINK_STATE(*this, "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "ActBeforePerformingLayout", "CreatingSegments", + "AfterLayout"); if (auto *layoutInfo = m_Module.getLayoutInfo()) { auto OldOffset = O.getOffset(); ELDEXP_RETURN_DIAGENTRY_IF_ERROR(OldOffset); @@ -304,7 +309,9 @@ eld::Expected LinkerWrapper::resetOffset(OutputSection O) { eld::Expected> LinkerWrapper::getOutputSectionAndRule(Section S) { - CHECK_LINK_STATE(*this, "CreatingSections", "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "ActBeforeSectionMerging", "CreatingSections", + "ActBeforePerformingLayout", "CreatingSegments", + "AfterLayout", "ActBeforeWritingOutput"); InputFile F = S.getInputFile(); @@ -339,9 +346,10 @@ LinkerWrapper::getOutputSectionAndRule(Section S) { eld::Expected LinkerWrapper::linkSections(OutputSection A, OutputSection B) const { - CHECK_LINK_STATE(*this, "CreatingSections", "CreatingSegments"); + CHECK_LINK_STATE(*this, "ActBeforeSectionMerging", "CreatingSections", + "ActBeforePerformingLayout", "CreatingSegments"); m_Module.getBackend().pluginLinkSections(A.getOutputSection(), - B.getOutputSection()); + B.getOutputSection()); return {}; } @@ -962,10 +970,14 @@ std::string_view LinkerWrapper::getCurrentLinkStateAsStr() const { return #linkerState; ADD_CASE(Unknown); ADD_CASE(Initializing); + ADD_CASE(ActBeforeRuleMatching); ADD_CASE(BeforeLayout); + ADD_CASE(ActBeforeSectionMerging); ADD_CASE(CreatingSections); - ADD_CASE(AfterLayout); + ADD_CASE(ActBeforePerformingLayout); ADD_CASE(CreatingSegments); + ADD_CASE(AfterLayout); + ADD_CASE(ActBeforeWritingOutput); #undef ADD_CASE } llvm_unreachable("Invalid link state!"); @@ -977,8 +989,10 @@ bool LinkerWrapper::isVerbose() const { eld::Expected> LinkerWrapper::getAllOutputSections() const { - CHECK_LINK_STATE(*this, "Initializing", "CreatingSections", - "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "ActBeforeRuleMatching", "BeforeLayout", + "ActBeforeSectionMerging", "CreatingSections", + "ActBeforePerformingLayout", "CreatingSegments", + "ActBeforeWritingOutput", "AfterLayout"); SectionMap sectMap = m_Module.getScript().sectionMap(); std::vector outputSects; @@ -990,7 +1004,8 @@ LinkerWrapper::getAllOutputSections() const { eld::Expected> LinkerWrapper::getSegmentsForOutputSection(const OutputSection &O) const { - CHECK_LINK_STATE(*this, "CreatingSections", "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "CreatingSections", "ActBeforePerformingLayout", + "CreatingSegments", "AfterLayout", "ActBeforeWritingOutput"); std::vector Segments; for (auto *S : m_Module.getBackend().getSegmentsForSection(O.getOutputSection())) @@ -1170,18 +1185,34 @@ bool LinkerWrapper::isLinkStateInitializing() const { return m_Module.getState() == LinkState::Initializing; } +bool LinkerWrapper::isLinkStateActBeforeRuleMatching() const { + return m_Module.getState() == LinkState::ActBeforeRuleMatching; +} + bool LinkerWrapper::isLinkStateBeforeLayout() const { return m_Module.getState() == LinkState::BeforeLayout; } +bool LinkerWrapper::isLinkStateActBeforeSectionMerging() const { + return m_Module.getState() == LinkState::ActBeforeSectionMerging; +} + bool LinkerWrapper::isLinkStateCreatingSections() const { return m_Module.getState() == LinkState::CreatingSections; } +bool LinkerWrapper::isLinkStateCreatingSegments() const { + return m_Module.getState() == LinkState::CreatingSegments; +} + +bool LinkerWrapper::isLinkStateActBeforePerformingLayout() const { + return m_Module.getState() == LinkState::ActBeforePerformingLayout; +} + bool LinkerWrapper::isLinkStateAfterLayout() const { return m_Module.getState() == LinkState::AfterLayout; } -bool LinkerWrapper::isLinkStateCreatingSegments() const { - return m_Module.getState() == LinkState::CreatingSegments; +bool LinkerWrapper::isLinkStateActBeforeWritingOutput() const { + return m_Module.getState() == LinkState::ActBeforeWritingOutput; } diff --git a/lib/LinkerWrapper/PluginADT.cpp b/lib/LinkerWrapper/PluginADT.cpp index bcd9635c7..a36b6e34e 100644 --- a/lib/LinkerWrapper/PluginADT.cpp +++ b/lib/LinkerWrapper/PluginADT.cpp @@ -30,7 +30,6 @@ #include "llvm/Support/Timer.h" #include #include - using namespace eld; using namespace eld::plugin; @@ -679,12 +678,7 @@ eld::Expected plugin::Section::overrideLinkerScriptRule(LinkerWrapper &LW, plugin::LinkerScriptRule R, const std::string &Annotation) { - if (!LW.isLinkStateInitializing()) { - return std::make_unique( - Diag::error_invalid_link_state, - std::vector{std::string(LW.getCurrentLinkStateAsStr()), - __FUNCTION__, ""}); - } + CHECK_LINK_STATE(LW, "Initializing", "ActBeforeRuleMatching"); if (!m_Section) return {}; ELFSection *S = llvm::dyn_cast(m_Section); diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index a95c2a68a..21de69bdd 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -1259,6 +1259,7 @@ bool ObjectLinker::mergeSections() { eld::RegisterTimer T("Universal Plugin", "Merge Sections", ThisConfig.options().printTimingStats()); auto &PM = ThisModule->getPluginManager(); + ThisModule->setLinkState(LinkState::ActBeforeSectionMerging); if (!PM.callActBeforeSectionMergingHook()) return false; } @@ -1268,8 +1269,11 @@ bool ObjectLinker::mergeSections() { eld::RegisterTimer T("Plugin: Output Section Iterator Before Layout", "Merge Sections", ThisConfig.options().printTimingStats()); + // For backward compatibility + ThisModule->setLinkState(LinkState::BeforeLayout); if (!runOutputSectionIteratorPlugin()) return false; + ThisModule->setLinkState(LinkState::ActBeforeSectionMerging); } // Merge all the input sections. diff --git a/lib/Writers/ELFObjectWriter.cpp b/lib/Writers/ELFObjectWriter.cpp index 982e3d586..f0181c4e3 100644 --- a/lib/Writers/ELFObjectWriter.cpp +++ b/lib/Writers/ELFObjectWriter.cpp @@ -206,6 +206,7 @@ ELFObjectWriter::writeObject(llvm::FileOutputBuffer &CurOutput) { { PluginManager &PM = ThisModule.getPluginManager(); + ThisModule.setLinkState(LinkState::ActBeforePerformingLayout); if (!PM.callActBeforeWritingOutputHook()) { // Return generic error-code. Actual error is already reported! return make_error_code(std::errc::not_supported); diff --git a/test/Common/Plugin/InvalidStateOverrideLSRule/InvalidStateOverrideLSRule.test b/test/Common/Plugin/InvalidStateOverrideLSRule/InvalidStateOverrideLSRule.test index 51b5ba845..b650735f6 100644 --- a/test/Common/Plugin/InvalidStateOverrideLSRule/InvalidStateOverrideLSRule.test +++ b/test/Common/Plugin/InvalidStateOverrideLSRule/InvalidStateOverrideLSRule.test @@ -8,6 +8,6 @@ RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.1.o -ffunction-sections RUN: %not %link %linkopts %t1.1.o -T %p/Inputs/script.t -o %t2.out --plugin-config %p/Inputs/plugin.config 2>&1 | %filecheck %s -#CHECK: Error: Link state 'BeforeLayout' is invalid for the API '{{.*}}overrideLinkerScriptRule{{.*}}'. Valid link states: [] +#CHECK: Error: Link state 'ActBeforeSectionMerging' is invalid for the API '{{.*}}overrideLinkerScriptRule{{.*}}'. Valid link states: [Initializing, ActBeforeRuleMatching] #CHECK: Fatal: Linking had errors. diff --git a/test/Hexagon/Plugin/AllOutSectAddresses/AllOutSectAddresses.test b/test/Hexagon/Plugin/AllOutSectAddresses/AllOutSectAddresses.test index 7efecb614..69ac0fb98 100644 --- a/test/Hexagon/Plugin/AllOutSectAddresses/AllOutSectAddresses.test +++ b/test/Hexagon/Plugin/AllOutSectAddresses/AllOutSectAddresses.test @@ -19,4 +19,4 @@ RUN: %not %link %linkopts -o %t1.1.out %t1.1.o -L%libsdir/test -T %p/Inputs/scri #CHECK: Virtual address: {{.*}} #CHECK: Physical address: 0 #INVALID_STATE: InvalidStateFindOutSectAddresses:Error: Link state 'BeforeLayout' is invalid for the API '{{.*}}getVirtualAddress{{.*}}'. Valid link states: [CreatingSegments, AfterLayout] -#INVALID_STATE: InvalidStateFindOutSectAddresses:Error: Link state 'BeforeLayout' is invalid for the API '{{.*}}eld::plugin::LinkerWrapper::getAllOutputSections({{.*}}) const'. Valid link states: [Initializing, CreatingSections, CreatingSegments, AfterLayout] \ No newline at end of file +