From b8878874573413bb7367599ef24937b37a1bcf82 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/Module.h | 4 ++ include/eld/PluginAPI/LinkerWrapper.h | 10 +++- lib/Core/Linker.cpp | 1 + lib/Core/Module.cpp | 29 +++++----- 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, 101 insertions(+), 42 deletions(-) diff --git a/include/eld/Core/Module.h b/include/eld/Core/Module.h index 3343daa10..7e6562b64 100644 --- a/include/eld/Core/Module.h +++ b/include/eld/Core/Module.h @@ -159,10 +159,14 @@ class Module { enum LinkState : uint8_t { Unknown, Initializing, + ActBeforeRuleMatching, BeforeLayout, + ActBeforeSectionMerging, CreatingSections, + ActBeforePerformingLayout, CreatingSegments, AfterLayout, + ActBeforeWritingOutput }; public: 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 bbaf23828..14c843cdb 100644 --- a/lib/Core/Linker.cpp +++ b/lib/Core/Linker.cpp @@ -468,6 +468,7 @@ bool Linker::resolve() { } PluginManager &PM = ThisModule->getPluginManager(); + ThisModule->setLinkState(Module::LinkState::ActBeforeRuleMatching); PM.callActBeforeRuleMatchingHook(); // Assign output sections. diff --git a/lib/Core/Module.cpp b/lib/Core/Module.cpp index 6b04ae941..e6f2728c8 100644 --- a/lib/Core/Module.cpp +++ b/lib/Core/Module.cpp @@ -501,20 +501,22 @@ bool Module::updateOutputSectionsWithPlugins() { } llvm::StringRef Module::getStateStr() const { +#define ADD_CASE(S) \ + case LinkState::S: \ + return #S; switch (getState()) { - case LinkState::Unknown: - return "Unknown"; - case LinkState::Initializing: - return "Initializing"; - case LinkState::BeforeLayout: - return "BeforeLayout"; - case LinkState::CreatingSections: - return "CreatingSections"; - case LinkState::AfterLayout: - return "AfterLayout"; - case LinkState::CreatingSegments: - return "CreatingSegments"; + 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 } void Module::addSymbolCreatedByPluginToFragment(Fragment *F, std::string Symbol, @@ -522,7 +524,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 03e81c69d..d635fb720 100644 --- a/lib/LayoutMap/TextLayoutPrinter.cpp +++ b/lib/LayoutMap/TextLayoutPrinter.cpp @@ -693,7 +693,7 @@ void TextLayoutPrinter::printFragInfo(Fragment *Frag, LayoutFragmentInfo *Info, std::optional AddressOrOffset; bool HasFragInfo = - (M.isLinkStateCreatingSegments() || M.isLinkStateAfterLayout()); + (M.getState() >= Module::LinkState::ActBeforePerformingLayout); if (llvm::isa(Frag) && !M.isLinkStateBeforeLayout()) { auto *Strings = llvm::cast(Frag); for (MergeableString *S : Strings->getStrings()) { @@ -850,8 +850,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() >= Module::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 f7282bc22..a35ad0fd5 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) { - bool b = S == "Initializing" || S == "BeforeLayout" || - S == "CreatingSections" || S == "CreatingSegments" || - S == "AfterLayout"; + 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 4bfeb69c3..ad38eae62 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 {}; } @@ -964,10 +972,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!"); @@ -979,7 +991,9 @@ bool LinkerWrapper::isVerbose() const { eld::Expected> LinkerWrapper::getAllOutputSections() const { - CHECK_LINK_STATE(*this, "CreatingSections", "CreatingSegments", "AfterLayout"); + CHECK_LINK_STATE(*this, "ActBeforeSectionMerging", "CreatingSections", + "ActBeforePerformingLayout", "CreatingSegments", + "ActBeforeWritingOutput", "AfterLayout"); SectionMap sectMap = m_Module.getScript().sectionMap(); std::vector outputSects; @@ -991,7 +1005,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())) @@ -1171,18 +1186,34 @@ bool LinkerWrapper::isLinkStateInitializing() const { return m_Module.getState() == Module::LinkState::Initializing; } +bool LinkerWrapper::isLinkStateActBeforeRuleMatching() const { + return m_Module.getState() == Module::LinkState::ActBeforeRuleMatching; +} + bool LinkerWrapper::isLinkStateBeforeLayout() const { return m_Module.getState() == Module::LinkState::BeforeLayout; } +bool LinkerWrapper::isLinkStateActBeforeSectionMerging() const { + return m_Module.getState() == Module::LinkState::ActBeforeSectionMerging; +} + bool LinkerWrapper::isLinkStateCreatingSections() const { return m_Module.getState() == Module::LinkState::CreatingSections; } +bool LinkerWrapper::isLinkStateCreatingSegments() const { + return m_Module.getState() == Module::LinkState::CreatingSegments; +} + +bool LinkerWrapper::isLinkStateActBeforePerformingLayout() const { + return m_Module.getState() == Module::LinkState::ActBeforePerformingLayout; +} + bool LinkerWrapper::isLinkStateAfterLayout() const { return m_Module.getState() == Module::LinkState::AfterLayout; } -bool LinkerWrapper::isLinkStateCreatingSegments() const { - return m_Module.getState() == Module::LinkState::CreatingSegments; -} +bool LinkerWrapper::isLinkStateActBeforeWritingOutput() const { + return m_Module.getState() == Module::LinkState::ActBeforeWritingOutput; +} \ No newline at end of file diff --git a/lib/LinkerWrapper/PluginADT.cpp b/lib/LinkerWrapper/PluginADT.cpp index ce44f5856..61ea6b1aa 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 dc1077ed5..a822d5632 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -1141,6 +1141,7 @@ bool ObjectLinker::mergeSections() { eld::RegisterTimer T("Universal Plugin", "Merge Sections", ThisConfig.options().printTimingStats()); auto &PM = ThisModule->getPluginManager(); + ThisModule->setLinkState(Module::LinkState::ActBeforeSectionMerging); if (!PM.callActBeforeSectionMergingHook()) return false; } @@ -1150,8 +1151,11 @@ bool ObjectLinker::mergeSections() { eld::RegisterTimer T("Plugin: Output Section Iterator Before Layout", "Merge Sections", ThisConfig.options().printTimingStats()); + // For backward compatibility + ThisModule->setLinkState(Module::LinkState::BeforeLayout); if (!runOutputSectionIteratorPlugin()) return false; + ThisModule->setLinkState(Module::LinkState::ActBeforeSectionMerging); } // Merge all the input sections. diff --git a/lib/Writers/ELFObjectWriter.cpp b/lib/Writers/ELFObjectWriter.cpp index 6c33f4de6..34cac6d17 100644 --- a/lib/Writers/ELFObjectWriter.cpp +++ b/lib/Writers/ELFObjectWriter.cpp @@ -195,6 +195,7 @@ ELFObjectWriter::writeObject(llvm::FileOutputBuffer &CurOutput) { { PluginManager &PM = ThisModule.getPluginManager(); + ThisModule.setLinkState(Module::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 7c812fd68..00282b72d 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: [CreatingSections, CreatingSegments, AfterLayout] \ No newline at end of file +#INVALID_STATE: InvalidStateFindOutSectAddresses:Error: Link state 'BeforeLayout' is invalid for the API '{{.*}}eld::plugin::LinkerWrapper::getAllOutputSections({{.*}}) const'. Valid link states: [ActBeforeSectionMerging, CreatingSections, ActBeforePerformingLayout, CreatingSegments, ActBeforeWritingOutput, AfterLayout] \ No newline at end of file