diff --git a/include/eld/Diagnostics/DiagLDScript.inc b/include/eld/Diagnostics/DiagLDScript.inc index ab00bfa72..1ffdb2c76 100644 --- a/include/eld/Diagnostics/DiagLDScript.inc +++ b/include/eld/Diagnostics/DiagLDScript.inc @@ -124,6 +124,8 @@ DIAG(error_insert_output_section, DiagnosticEngine::Error, "Cannot INSERT output section %0 %1 %2 in script %3") DIAG(warn_non_power_of_2_value_to_align_builtin, DiagnosticEngine::Warning, "%0: non-power-of-2 value 0x%1 passed to ALIGN builtin function") +DIAG(warn_subalign_less_than_section_alignment, DiagnosticEngine::Warning, + "SUBALIGN(0x%0) is less than the section alignment (0x%1) for section '%2'") DIAG(error_non_power_of_2_value_to_align_output_section, DiagnosticEngine::Error, "%0: non-power-of-2 value 0x%1 passed to ALIGN in '%2' output section description, value must " "be 0 or a power of 2") diff --git a/include/eld/Object/ObjectLinker.h b/include/eld/Object/ObjectLinker.h index 8348828c1..1330197d2 100644 --- a/include/eld/Object/ObjectLinker.h +++ b/include/eld/Object/ObjectLinker.h @@ -315,6 +315,8 @@ class ObjectLinker { bool initializeOutputSectionsAndRunPlugin(); + void applySubAlign(); + // Get Plugin list for Relocation registration callback. LinkerScript::PluginVectorT getLinkerPluginWithLinkerConfigs(); diff --git a/lib/Fragment/StringFragment.cpp b/lib/Fragment/StringFragment.cpp index 70d5e36ea..129296c43 100644 --- a/lib/Fragment/StringFragment.cpp +++ b/lib/Fragment/StringFragment.cpp @@ -35,7 +35,10 @@ eld::Expected StringFragment::emit(MemoryRegion &Mr, Module &M) { return {}; Out = Mr.begin() + getOffset(M.getConfig().getDiagEngine()) - this->paddingSize(); - uint64_t PaddingValue = *M.getFragmentPaddingValue(this); + std::optional optPaddingValue = M.getFragmentPaddingValue(this); + if (!optPaddingValue) + return {}; + uint64_t PaddingValue = *optPaddingValue; uint32_t ValueSize = Fragment::getPaddingValueSize(PaddingValue); if (PaddingValue == 0) return {}; diff --git a/lib/LayoutMap/TextLayoutPrinter.cpp b/lib/LayoutMap/TextLayoutPrinter.cpp index 354f3d8fc..60a1d3a56 100644 --- a/lib/LayoutMap/TextLayoutPrinter.cpp +++ b/lib/LayoutMap/TextLayoutPrinter.cpp @@ -109,6 +109,10 @@ void TextLayoutPrinter::printOnlyLayoutSection(GNULDBackend const &Backend, outputStream().write_hex(Section->size()); outputStream() << "\t# Alignment: 0x"; outputStream().write_hex(Section->getAddrAlign()); + if (OS->prolog().hasSubAlign()) { + outputStream() << ", SubAlign: 0x"; + outputStream().write_hex(OS->prolog().subAlign().resultOrZero()); + } if (Section->isAlloc()) printSegments(Backend, OS); outputStream() << "\n"; @@ -297,6 +301,12 @@ void TextLayoutPrinter::printSection(GNULDBackend const &Backend, outputStream() << ", Alignment: 0x"; outputStream().write_hex(Section->getAddrAlign()); + // Print SubAlign if present + if (OS->prolog().hasSubAlign()) { + outputStream() << ", SubAlign: 0x"; + outputStream().write_hex(OS->prolog().subAlign().resultOrZero()); + } + // Print flags outputStream() << ", Flags: " << ELFSection::getELFPermissionsStr(Section->getFlags()); diff --git a/lib/Object/ObjectLinker.cpp b/lib/Object/ObjectLinker.cpp index a95c2a68a..a371e8c40 100644 --- a/lib/Object/ObjectLinker.cpp +++ b/lib/Object/ObjectLinker.cpp @@ -63,6 +63,7 @@ #include "eld/SymbolResolver/ResolveInfo.h" #include "eld/Target/ELFFileFormat.h" #include "eld/Target/GNULDBackend.h" +#include "eld/Target/LDFileFormat.h" #include "eld/Target/Relocator.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringSwitch.h" @@ -83,6 +84,7 @@ #include #include #include +#include using namespace llvm; using namespace eld; @@ -996,7 +998,7 @@ bool ObjectLinker::sortSections(RuleContainer *I, bool SortRule) { bool ObjectLinker::createOutputSection(ObjectBuilder &Builder, OutputSectionEntry *Output, bool PostLayout) { - uint64_t OutAlign = 0x0, InAlign = 0x0; + uint64_t OutAlign = 0x0; bool IsPartialLink = (LinkerConfig::Object == ThisConfig.codeGenType()); ELFSection *OutSect = Output->getSection(); @@ -1006,15 +1008,6 @@ bool ObjectLinker::createOutputSection(ObjectBuilder &Builder, OutputSectionEntry::iterator In, InBegin, InEnd; InBegin = Output->begin(); InEnd = Output->end(); - bool HasSubAlign = false; - - // force input alignment from ldscript if any - if (Output->prolog().hasSubAlign()) { - Output->prolog().subAlign().eval(); - Output->prolog().subAlign().commit(); - InAlign = Output->prolog().subAlign().result(); - HasSubAlign = true; - } // force output alignment from ldscript if any if (Output->prolog().hasAlign()) { @@ -1056,12 +1049,6 @@ bool ObjectLinker::createOutputSection(ObjectBuilder &Builder, } InSect->setAddrAlign(Alignment); } - if (HasSubAlign && (InSect->getAddrAlign() < InAlign)) { - if (InSect->getFragmentList().size()) { - InSect->getFragmentList().front()->setAlignment(InAlign); - InSect->setAddrAlign(InAlign); - } - } if (InSect->getFragmentList().size() && !FirstNonEmptyRule) FirstNonEmptyRule = *In; @@ -1313,6 +1300,9 @@ bool ObjectLinker::mergeSections() { { eld::RegisterTimer T("Create Output Section", "Merge Sections", ThisConfig.options().printTimingStats()); + // Prepass: apply SUBALIGN to first fragments per input section per output + // section serially to avoid races in parallel output creation. + applySubAlign(); std::vector OutSections; for (Out = OutBegin; Out != OutEnd; ++Out) { OutSections.push_back(*Out); @@ -1356,6 +1346,41 @@ bool ObjectLinker::initializeOutputSectionsAndRunPlugin() { return runOutputSectionIteratorPlugin(); } +void ObjectLinker::applySubAlign() { + std::unordered_set seen; + + for (auto *O : ThisModule->getScript().sectionMap()) { + auto &prolog = O->prolog(); + if (!prolog.hasSubAlign()) + continue; + uint64_t subAlign; + prolog.subAlign().eval(); + prolog.subAlign().commit(); + subAlign = prolog.subAlign().result(); + + for (RuleContainer *R : *O) { + ELFSection *inSect = R->getSection(); + for (Fragment *F : inSect->getFragmentList()) { + ELFSection *owningSect = F->getOwningSection(); + if (owningSect->getKind() == LDFileFormat::Kind::OutputSectData) { + continue; + } + if (owningSect && seen.insert(owningSect).second) { + // Warn if SUBALIGN is reducing the section alignment + if (ThisConfig.showLinkerScriptWarnings() && F->alignment() > subAlign) { + ThisConfig.raise(Diag::warn_subalign_less_than_section_alignment) + << utility::toHex(subAlign) << utility::toHex(F->alignment()) + << owningSect->getLocation(0, ThisConfig.options()); + } + F->setAlignment(subAlign); + inSect->setAddrAlign(std::max( + static_cast(inSect->getAddrAlign()), subAlign)); + } + } + } + } +} + void ObjectLinker::assignOffset(OutputSectionEntry *Out) { int64_t O = 0; const ELFSection *OutSection = Out->getSection(); diff --git a/test/Common/standalone/SubAlign/Inputs/1.c b/test/Common/standalone/SubAlign/Inputs/1.c index b7addefa7..31696a3fc 100644 --- a/test/Common/standalone/SubAlign/Inputs/1.c +++ b/test/Common/standalone/SubAlign/Inputs/1.c @@ -1,3 +1,3 @@ int foo() { return 0; } -int bar() { return 0; } +int bar() { return foo(); } int car() { return 0; } diff --git a/test/Common/standalone/SubAlign/Inputs/2.c b/test/Common/standalone/SubAlign/Inputs/2.c new file mode 100644 index 000000000..88843f88a --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/2.c @@ -0,0 +1,8 @@ +__attribute__((aligned((0x4)))) +int foo() { return 0; } + +__attribute__((aligned((0x4)))) +int bar() { return foo(); } + +__attribute__((aligned((0x4)))) +int car() { return 0; } diff --git a/test/Common/standalone/SubAlign/Inputs/script.2.t b/test/Common/standalone/SubAlign/Inputs/script.2.t new file mode 100644 index 000000000..b13b3e531 --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.2.t @@ -0,0 +1,14 @@ +PHDRS { + A PT_LOAD; +} + +SECTIONS { + .a : SUBALIGN(64) { + . = . + 1; + *(.text*) + }:A + .b : SUBALIGN(64) { + . = . + 1; + }:A + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.data.t b/test/Common/standalone/SubAlign/Inputs/script.data.t new file mode 100644 index 000000000..859e0862d --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.data.t @@ -0,0 +1,12 @@ +SECTIONS { + .explicit_data : SUBALIGN(64) { + BYTE(0x11) + SHORT(0x2222) + LONG(0x44444444) + QUAD(0x8888888888888888) + *(.text*) + BYTE(0xAA) + QUAD(0xBBBBBBBBBBBBBBBB) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.discard.t b/test/Common/standalone/SubAlign/Inputs/script.discard.t new file mode 100644 index 000000000..214f7f4f0 --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.discard.t @@ -0,0 +1,14 @@ +PHDRS { + A PT_LOAD; +} + +SECTIONS { + .keep : SUBALIGN(64) { + *(.text.foo) + *(.text.bar) + }:A + /DISCARD/ : SUBALIGN(32) { + *(.text.car) + *(.ARM.exidx*) + } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.empty.t b/test/Common/standalone/SubAlign/Inputs/script.empty.t new file mode 100644 index 000000000..e318d533e --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.empty.t @@ -0,0 +1,13 @@ +SECTIONS { + .nonempty : SUBALIGN(64) { + *(.text.foo) + } + .empty1 : SUBALIGN(32) { + *(.nonexistent1) + } + .empty2 : SUBALIGN(128) { + /* Empty section with just location counter */ + . = . + 0; + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.nonalloc.t b/test/Common/standalone/SubAlign/Inputs/script.nonalloc.t new file mode 100644 index 000000000..e5450ae2d --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.nonalloc.t @@ -0,0 +1,12 @@ +SECTIONS { + .text : SUBALIGN(64) { + *(.text*) + } + .debug_info : SUBALIGN(32) { + *(.debug_info) + } + .comment : SUBALIGN(16) { + *(.comment) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.partial.t b/test/Common/standalone/SubAlign/Inputs/script.partial.t new file mode 100644 index 000000000..9d6d97e7a --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.partial.t @@ -0,0 +1,6 @@ +SECTIONS { + .partial : SUBALIGN(64) { + *(.text*) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.reduce.t b/test/Common/standalone/SubAlign/Inputs/script.reduce.t new file mode 100644 index 000000000..79adb38ec --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.reduce.t @@ -0,0 +1,6 @@ +SECTIONS { + .reduce : SUBALIGN(2) { + *(.text*) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.relocs.t b/test/Common/standalone/SubAlign/Inputs/script.relocs.t new file mode 100644 index 000000000..14e5f8fa2 --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.relocs.t @@ -0,0 +1,7 @@ +SECTIONS { + .reloc_text : SUBALIGN(64) { + *(.text*) + *(.rel.*) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/Inputs/script.shared.t b/test/Common/standalone/SubAlign/Inputs/script.shared.t new file mode 100644 index 000000000..e4a2a1794 --- /dev/null +++ b/test/Common/standalone/SubAlign/Inputs/script.shared.t @@ -0,0 +1,6 @@ +SECTIONS { + .shared_text (0x1000) : SUBALIGN(64) { + *(.text*) + } + /DISCARD/ : { *(.ARM.exidx*) } +} diff --git a/test/Common/standalone/SubAlign/SubAlign.test b/test/Common/standalone/SubAlign/SubAlign.test index 6bd6ba0a9..d8d3a0525 100644 --- a/test/Common/standalone/SubAlign/SubAlign.test +++ b/test/Common/standalone/SubAlign/SubAlign.test @@ -4,12 +4,100 @@ UNSUPPORTED: x86 # Test for linker script SUBALIGN directive. #END_COMMENT #START_TEST + +# Basic SUBALIGN test RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.1.o -ffunction-sections -RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.t -o %t1.1.o -Map %t2.map -RUN: %filecheck %s < %t2.map -#CHECK: .a {{.*}} Alignment: 0x40 -#CHECK: .text.foo 0x40 -#CHECK: .text.bar 0x80 -#CHECK: .text.car 0xc0 -#CHECK: .b {{.*}} Alignment: 0x1 +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.t -o %t1.1.out -Map %t1.1.map.txt +RUN: %filecheck %s < %t1.1.map.txt +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.2.t -o %t1.2.out -Map %t1.2.map.txt +RUN: %filecheck %s < %t1.1.map.txt +RUN: %filecheck %s < %t1.2.map.txt +CHECK: .a {{.*}} Alignment: 0x40 +CHECK: .text.foo 0x40 +CHECK: .text.bar 0x80 +CHECK: .text.car 0xc0 +CHECK: .b {{.*}} Alignment: 0x1 + +# Test SubAlign display in map file +RUN: %filecheck %s --check-prefix=SUBALIGN-DISPLAY < %t1.1.map.txt +SUBALIGN-DISPLAY: .a {{.*}} Alignment: 0x40, SubAlign: 0x40 +SUBALIGN-DISPLAY: .b {{.*}} Alignment: 0x1, SubAlign: 0x40 + +# Test SUBALIGN with DISCARD sections +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.discard.t -o %t.discard.out -Map %t.discard.map.txt +RUN: %filecheck %s --check-prefix=DISCARD < %t.discard.map.txt +DISCARD: .keep {{.*}} Alignment: 0x40, SubAlign: 0x40 +DISCARD: .text.foo 0x0 +DISCARD: .text.bar 0x40 +DISCARD: /DISCARD/ {{.*}} Alignment: 0x1, SubAlign: 0x20 +DISCARD: # .text.car + +# Test SUBALIGN with emit-relocs +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.relocs.t -o %t.relocs.out -Map %t.relocs.map.txt --emit-relocs +RUN: %filecheck %s --check-prefix=RELOCS < %t.relocs.map.txt +RUN: %readelf -r %t.relocs.out | %filecheck %s --check-prefix=RELOCS-READELF +RELOCS: .reloc_text {{.*}} Alignment: 0x40, SubAlign: 0x40 +RELOCS: .text.foo 0x0 +RELOCS: .text.bar 0x40 +RELOCS: .text.car 0x80 +#RELOCS-READELF: Relocation section '.rel{{a?}}.reloc_text' {{.*}} + +# Test SUBALIGN with empty sections +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.empty.t -o %t.empty.out -Map %t.empty.map.txt +RUN: %filecheck %s --check-prefix=EMPTY < %t.empty.map.txt +EMPTY: .nonempty {{.*}} Alignment: 0x40, SubAlign: 0x40 +EMPTY: .text.foo 0x0 +EMPTY: .empty1 {{.*}} 0x0 {{.*}} Alignment: 0x1, SubAlign: 0x20 +EMPTY: .empty2 {{.*}} 0x0 {{.*}} Alignment: 0x1, SubAlign: 0x80 + +# Test SUBALIGN with explicit data (BYTE/QUAD/...) +RUN: %link -MapStyle txt %linkopts %t1.1.o -T %p/Inputs/script.data.t -o %t.data.out -Map %t.data.map.txt +RUN: %filecheck %s --check-prefix=DATA < %t.data.map.txt +DATA: .explicit_data {{.*}} Alignment: 0x40, SubAlign: 0x40 +DATA: BYTE (0x11) 0x0 0x1 +DATA: SHORT (0x2222) 0x1 0x3 +DATA: LONG (0x44444444) 0x3 0x7 +DATA: QUAD (0x8888888888888888) 0x7 0xf +DATA: .text.foo 0x40 +DATA: .text.bar 0x80 + +# Test SUBALIGN with partial linking +RUN: %link %linkopts %t1.1.o -T %p/Inputs/script.partial.t -o %t.partial.tmp.o -r -Map %t.partial.map.txt +RUN: %filecheck %s --check-prefix=PARTIAL < %t.partial.map.txt +PARTIAL: .partial {{.*}} Alignment: 0x40, SubAlign: 0x40 +PARTIAL: .text.foo 0x0 +PARTIAL: .text.bar 0x40 +PARTIAL: .text.car 0x80 + +# Test SUBALIGN with shared libraries +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t.shared.o -ffunction-sections -fPIC +RUN: %link -MapStyle txt %linkopts %t.shared.o -T %p/Inputs/script.shared.t -o %t.shared.so -Map %t.shared.map.txt -shared +RUN: %filecheck %s --check-prefix=SHARED < %t.shared.map.txt +#END_TEST +SHARED: .shared_text {{.*}} Alignment: 0x40, SubAlign: 0x40 +SHARED: .text.foo 0x1000 +SHARED: .text.bar 0x1040 +SHARED: .text.car 0x1080 + +# Test SUBALIGN with non-allocatable sections +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t.nonalloc.o -ffunction-sections -g +RUN: %link -MapStyle txt %linkopts %t.nonalloc.o -T %p/Inputs/script.nonalloc.t -o %t.nonalloc.out -Map %t.nonalloc.map.txt +RUN: %filecheck %s --check-prefix=NONALLOC < %t.nonalloc.map.txt +NONALLOC: .text {{.*}} Alignment: 0x40, SubAlign: 0x40 +NONALLOC: .text.foo 0x0 +NONALLOC: .text.bar 0x40 +NONALLOC: .text.car 0x80 +NONALLOC: .debug_info {{.*}} Alignment: 0x20, SubAlign: 0x20 +NONALLOC: .comment {{.*}} Alignment: 0x10, SubAlign: 0x10 + +# Test SUBALIGN reducing section alignment (should warn) +RUN: %clang %clangopts -c %p/Inputs/2.c -o %t1.reduce.o -ffunction-sections +RUN: %link -MapStyle txt %linkopts %t1.reduce.o -T %p/Inputs/script.reduce.t -o %t1.1.out -Map %t.reduce.map.txt -Wlinker-script 2>&1 | %filecheck %s --check-prefix=REDUCE-WARN +RUN: %link -MapStyle txt %linkopts %t1.reduce.o -T %p/Inputs/script.reduce.t -o %t1.1.out -Map %t.reduce.map.txt -Wno-linker-script 2>&1 | %filecheck %s --allow-empty --check-prefix=REDUCE-NOWARN +RUN: %filecheck %s --check-prefix=REDUCE < %t.reduce.map.txt +REDUCE-WARN: Warning: SUBALIGN(0x2) is less than the section alignment (0x{{.*}}) for section '{{.*reduce.o}}:(.text.foo)' +REDUCE-WARN: Warning: SUBALIGN(0x2) is less than the section alignment (0x{{.*}}) for section '{{.*reduce.o}}:(.text.bar)' +REDUCE-WARN: Warning: SUBALIGN(0x2) is less than the section alignment (0x{{.*}}) for section '{{.*reduce.o}}:(.text.car)' +REDUCE-NOWARN-NOT: Warning +REDUCE: .reduce {{.*}} Alignment: {{.*}}, SubAlign: 0x2 #END_TEST