From a97e5e6cce87c695ccc9cbac748199a611100d4c Mon Sep 17 00:00:00 2001 From: Parth Arora Date: Wed, 28 Jan 2026 03:33:13 -0800 Subject: [PATCH] Fix SUBALIGN linker script feature This commit fixes the SUBALIGN linker script feature. SUBALIGN feature is used to modify the alignment of all input sections present in an output section. Until now, we were only changing the alignment of the first fragment of each rule of the output sections with SUBALIGN specified. This commit fixes the SUBALIGN behavior. SUBALIGN affects the alignment of the first fragment as is seen by the linker when traversing the output sections for the input sections that may contain more than 1 fragment such as .eh_frame, PLT / GOT sections, and .comment section. Resolves #343 Signed-off-by: Parth Arora --- include/eld/Diagnostics/DiagLDScript.inc | 2 + include/eld/Object/ObjectLinker.h | 2 + lib/Fragment/StringFragment.cpp | 5 +- lib/LayoutMap/TextLayoutPrinter.cpp | 10 ++ lib/Object/ObjectLinker.cpp | 57 +++++++--- test/Common/standalone/SubAlign/Inputs/1.c | 2 +- test/Common/standalone/SubAlign/Inputs/2.c | 8 ++ .../standalone/SubAlign/Inputs/script.2.t | 14 +++ .../standalone/SubAlign/Inputs/script.data.t | 12 +++ .../SubAlign/Inputs/script.discard.t | 14 +++ .../standalone/SubAlign/Inputs/script.empty.t | 13 +++ .../SubAlign/Inputs/script.nonalloc.t | 12 +++ .../SubAlign/Inputs/script.partial.t | 6 ++ .../SubAlign/Inputs/script.reduce.t | 6 ++ .../SubAlign/Inputs/script.relocs.t | 7 ++ .../SubAlign/Inputs/script.shared.t | 6 ++ test/Common/standalone/SubAlign/SubAlign.test | 102 ++++++++++++++++-- 17 files changed, 253 insertions(+), 25 deletions(-) create mode 100644 test/Common/standalone/SubAlign/Inputs/2.c create mode 100644 test/Common/standalone/SubAlign/Inputs/script.2.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.data.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.discard.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.empty.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.nonalloc.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.partial.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.reduce.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.relocs.t create mode 100644 test/Common/standalone/SubAlign/Inputs/script.shared.t 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