Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/eld/Diagnostics/DiagLDScript.inc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ DIAG(error_cannot_specify_lma_and_memory_region, DiagnosticEngine::Error,
"cannot specify AT and LMA memory region for output section : %0 defined in script %1")
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")
Expand Down
2 changes: 2 additions & 0 deletions include/eld/Object/ObjectLinker.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ class ObjectLinker {

bool initializeOutputSectionsAndRunPlugin();

void applySubAlign();

// Get Plugin list for Relocation registration callback.
LinkerScript::PluginVectorT getLinkerPluginWithLinkerConfigs();

Expand Down
10 changes: 10 additions & 0 deletions lib/LayoutMap/TextLayoutPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,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";
Expand Down Expand Up @@ -277,6 +281,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());
Expand Down
57 changes: 41 additions & 16 deletions lib/Object/ObjectLinker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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"
Expand All @@ -81,6 +82,7 @@
#include <chrono>
#include <mutex>
#include <sstream>
#include <unordered_set>

using namespace llvm;
using namespace eld;
Expand Down Expand Up @@ -970,7 +972,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();
Expand All @@ -980,15 +982,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()) {
Expand Down Expand Up @@ -1030,12 +1023,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;

Expand Down Expand Up @@ -1286,6 +1273,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<OutputSectionEntry *> OutSections;
for (Out = OutBegin; Out != OutEnd; ++Out) {
OutSections.push_back(*Out);
Expand Down Expand Up @@ -1329,6 +1319,41 @@ bool ObjectLinker::initializeOutputSectionsAndRunPlugin() {
return runOutputSectionIteratorPlugin();
}

void ObjectLinker::applySubAlign() {
std::unordered_set<ELFSection *> 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<uint64_t>(inSect->getAddrAlign()), subAlign));
}
}
}
}
}

void ObjectLinker::assignOffset(OutputSectionEntry *Out) {
int64_t O = 0;
const ELFSection *OutSection = Out->getSection();
Expand Down
2 changes: 1 addition & 1 deletion test/Common/standalone/SubAlign/Inputs/1.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
int foo() { return 0; }
int bar() { return 0; }
int bar() { return foo(); }
int car() { return 0; }
8 changes: 8 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/2.c
Original file line number Diff line number Diff line change
@@ -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; }
14 changes: 14 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.2.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PHDRS {
A PT_LOAD;
}

SECTIONS {
.a : SUBALIGN(64) {
. = . + 1;
*(.text*)
}:A
.b : SUBALIGN(64) {
. = . + 1;
}:A
/DISCARD/ : { *(.ARM.exidx*) }
}
12 changes: 12 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.data.t
Original file line number Diff line number Diff line change
@@ -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*) }
}
14 changes: 14 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.discard.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PHDRS {
A PT_LOAD;
}

SECTIONS {
.keep : SUBALIGN(64) {
*(.text.foo)
*(.text.bar)
}:A
/DISCARD/ : SUBALIGN(32) {
*(.text.car)
*(.ARM.exidx*)
}
}
13 changes: 13 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.empty.t
Original file line number Diff line number Diff line change
@@ -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*) }
}
12 changes: 12 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.nonalloc.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SECTIONS {
.text : SUBALIGN(64) {
*(.text*)
}
.debug_info : SUBALIGN(32) {
*(.debug_info)
}
.comment : SUBALIGN(16) {
*(.comment)
}
/DISCARD/ : { *(.ARM.exidx*) }
}
6 changes: 6 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.partial.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SECTIONS {
.partial : SUBALIGN(64) {
*(.text*)
}
/DISCARD/ : { *(.ARM.exidx*) }
}
6 changes: 6 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.reduce.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SECTIONS {
.reduce : SUBALIGN(2) {
*(.text*)
}
/DISCARD/ : { *(.ARM.exidx*) }
}
7 changes: 7 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.relocs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
SECTIONS {
.reloc_text : SUBALIGN(64) {
*(.text*)
*(.rel.*)
}
/DISCARD/ : { *(.ARM.exidx*) }
}
6 changes: 6 additions & 0 deletions test/Common/standalone/SubAlign/Inputs/script.shared.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SECTIONS {
.shared_text (0x1000) : SUBALIGN(64) {
*(.text*)
}
/DISCARD/ : { *(.ARM.exidx*) }
}
102 changes: 95 additions & 7 deletions test/Common/standalone/SubAlign/SubAlign.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,100 @@
# 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
Loading