forked from OSchip/llvm-project
parent
edfd276cbc
commit
8455294f2a
|
@ -1901,26 +1901,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
|
||||||
markLive<ELFT>();
|
markLive<ELFT>();
|
||||||
demoteSharedSymbols();
|
demoteSharedSymbols();
|
||||||
mergeSections();
|
mergeSections();
|
||||||
|
|
||||||
// Make copies of any input sections that need to be copied into each
|
|
||||||
// partition.
|
|
||||||
copySectionsIntoPartitions();
|
|
||||||
|
|
||||||
// Create synthesized sections such as .got and .plt. This is called before
|
|
||||||
// processSectionCommands() so that they can be placed by SECTIONS commands.
|
|
||||||
createSyntheticSections<ELFT>();
|
|
||||||
|
|
||||||
// Some input sections that are used for exception handling need to be moved
|
|
||||||
// into synthetic sections. Do that now so that they aren't assigned to
|
|
||||||
// output sections in the usual way.
|
|
||||||
if (!config->relocatable)
|
|
||||||
combineEhSections();
|
|
||||||
|
|
||||||
// Create output sections described by SECTIONS commands.
|
|
||||||
script->processSectionCommands();
|
|
||||||
|
|
||||||
// Two input sections with different output sections should not be folded.
|
|
||||||
// ICF runs after processSectionCommands() so that we know the output sections.
|
|
||||||
if (config->icf != ICFLevel::None) {
|
if (config->icf != ICFLevel::None) {
|
||||||
findKeepUniqueSections<ELFT>(args);
|
findKeepUniqueSections<ELFT>(args);
|
||||||
doIcf<ELFT>();
|
doIcf<ELFT>();
|
||||||
|
|
|
@ -74,8 +74,6 @@
|
||||||
|
|
||||||
#include "ICF.h"
|
#include "ICF.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "LinkerScript.h"
|
|
||||||
#include "OutputSections.h"
|
|
||||||
#include "SymbolTable.h"
|
#include "SymbolTable.h"
|
||||||
#include "Symbols.h"
|
#include "Symbols.h"
|
||||||
#include "SyntheticSections.h"
|
#include "SyntheticSections.h"
|
||||||
|
@ -306,8 +304,10 @@ bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If two sections have different output sections, we cannot merge them.
|
// If two sections have different output sections, we cannot merge them.
|
||||||
if (getOutputSectionName(a) != getOutputSectionName(b) ||
|
// FIXME: This doesn't do the right thing in the case where there is a linker
|
||||||
a->getParent() != b->getParent())
|
// script. We probably need to move output section assignment before ICF to
|
||||||
|
// get the correct behaviour here.
|
||||||
|
if (getOutputSectionName(a) != getOutputSectionName(b))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (a->areRelocsRela)
|
if (a->areRelocsRela)
|
||||||
|
@ -499,15 +499,6 @@ template <class ELFT> void ICF<ELFT>::run() {
|
||||||
isec->markDead();
|
isec->markDead();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// InputSectionDescription::sections is populated by processSectionCommands().
|
|
||||||
// ICF may fold some input sections assigned to output sections. Remove them.
|
|
||||||
for (BaseCommand *base : script->sectionCommands)
|
|
||||||
if (auto *sec = dyn_cast<OutputSection>(base))
|
|
||||||
for (BaseCommand *sub_base : sec->sectionCommands)
|
|
||||||
if (auto *isd = dyn_cast<InputSectionDescription>(sub_base))
|
|
||||||
llvm::erase_if(isd->sections,
|
|
||||||
[](InputSection *isec) { return !isec->isLive(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ICF entry point function.
|
// ICF entry point function.
|
||||||
|
|
|
@ -48,22 +48,24 @@ using namespace lld::elf;
|
||||||
|
|
||||||
LinkerScript *elf::script;
|
LinkerScript *elf::script;
|
||||||
|
|
||||||
static uint64_t getOutputSectionVA(SectionBase *sec) {
|
static uint64_t getOutputSectionVA(SectionBase *inputSec, StringRef loc) {
|
||||||
OutputSection *os = sec->getOutputSection();
|
if (OutputSection *os = inputSec->getOutputSection())
|
||||||
assert(os && "input section has no output section assigned");
|
return os->addr;
|
||||||
return os ? os->addr : 0;
|
error(loc + ": unable to evaluate expression: input section " +
|
||||||
|
inputSec->name + " has no output section assigned");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ExprValue::getValue() const {
|
uint64_t ExprValue::getValue() const {
|
||||||
if (sec)
|
if (sec)
|
||||||
return alignTo(sec->getOffset(val) + getOutputSectionVA(sec),
|
return alignTo(sec->getOffset(val) + getOutputSectionVA(sec, loc),
|
||||||
alignment);
|
alignment);
|
||||||
return alignTo(val, alignment);
|
return alignTo(val, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ExprValue::getSecAddr() const {
|
uint64_t ExprValue::getSecAddr() const {
|
||||||
if (sec)
|
if (sec)
|
||||||
return sec->getOffset(0) + getOutputSectionVA(sec);
|
return sec->getOffset(0) + getOutputSectionVA(sec, loc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ uint64_t ExprValue::getSectionOffset() const {
|
||||||
// If the alignment is trivial, we don't have to compute the full
|
// If the alignment is trivial, we don't have to compute the full
|
||||||
// value to know the offset. This allows this function to succeed in
|
// value to know the offset. This allows this function to succeed in
|
||||||
// cases where the output section is not yet known.
|
// cases where the output section is not yet known.
|
||||||
if (alignment == 1 && !sec)
|
if (alignment == 1 && (!sec || !sec->getOutputSection()))
|
||||||
return val;
|
return val;
|
||||||
return getValue() - getSecAddr();
|
return getValue() - getSecAddr();
|
||||||
}
|
}
|
||||||
|
@ -155,8 +157,8 @@ static bool shouldDefineSym(SymbolAssignment *cmd) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by processSymbolAssignments() to assign definitions to
|
// This function is called from processSectionCommands,
|
||||||
// linker-script-defined symbols.
|
// while we are fixing the output section layout.
|
||||||
void LinkerScript::addSymbol(SymbolAssignment *cmd) {
|
void LinkerScript::addSymbol(SymbolAssignment *cmd) {
|
||||||
if (!shouldDefineSym(cmd))
|
if (!shouldDefineSym(cmd))
|
||||||
return;
|
return;
|
||||||
|
@ -476,10 +478,36 @@ LinkerScript::createInputSectionList(OutputSection &outCmd) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create output sections described by SECTIONS commands.
|
|
||||||
void LinkerScript::processSectionCommands() {
|
void LinkerScript::processSectionCommands() {
|
||||||
|
// A symbol can be assigned before any section is mentioned in the linker
|
||||||
|
// script. In an DSO, the symbol values are addresses, so the only important
|
||||||
|
// section values are:
|
||||||
|
// * SHN_UNDEF
|
||||||
|
// * SHN_ABS
|
||||||
|
// * Any value meaning a regular section.
|
||||||
|
// To handle that, create a dummy aether section that fills the void before
|
||||||
|
// the linker scripts switches to another section. It has an index of one
|
||||||
|
// which will map to whatever the first actual section is.
|
||||||
|
aether = make<OutputSection>("", 0, SHF_ALLOC);
|
||||||
|
aether->sectionIndex = 1;
|
||||||
|
|
||||||
|
// Ctx captures the local AddressState and makes it accessible deliberately.
|
||||||
|
// This is needed as there are some cases where we cannot just
|
||||||
|
// thread the current state through to a lambda function created by the
|
||||||
|
// script parser.
|
||||||
|
auto deleter = std::make_unique<AddressState>();
|
||||||
|
ctx = deleter.get();
|
||||||
|
ctx->outSec = aether;
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
// Add input sections to output sections.
|
||||||
for (BaseCommand *base : sectionCommands) {
|
for (BaseCommand *base : sectionCommands) {
|
||||||
|
// Handle symbol assignments outside of any output section.
|
||||||
|
if (auto *cmd = dyn_cast<SymbolAssignment>(base)) {
|
||||||
|
addSymbol(cmd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto *sec = dyn_cast<OutputSection>(base)) {
|
if (auto *sec = dyn_cast<OutputSection>(base)) {
|
||||||
std::vector<InputSection *> v = createInputSectionList(*sec);
|
std::vector<InputSection *> v = createInputSectionList(*sec);
|
||||||
|
|
||||||
|
@ -505,6 +533,12 @@ void LinkerScript::processSectionCommands() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A directive may contain symbol definitions like this:
|
||||||
|
// ".foo : { ...; bar = .; }". Handle them.
|
||||||
|
for (BaseCommand *base : sec->sectionCommands)
|
||||||
|
if (auto *outCmd = dyn_cast<SymbolAssignment>(base))
|
||||||
|
addSymbol(outCmd);
|
||||||
|
|
||||||
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
|
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
|
||||||
// is given, input sections are aligned to that value, whether the
|
// is given, input sections are aligned to that value, whether the
|
||||||
// given value is larger or smaller than the original section alignment.
|
// given value is larger or smaller than the original section alignment.
|
||||||
|
@ -514,7 +548,7 @@ void LinkerScript::processSectionCommands() {
|
||||||
s->alignment = subalign;
|
s->alignment = subalign;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some input sections may be removed from the list after ICF.
|
// Add input sections to an output section.
|
||||||
for (InputSection *s : v)
|
for (InputSection *s : v)
|
||||||
sec->addSection(s);
|
sec->addSection(s);
|
||||||
|
|
||||||
|
@ -525,32 +559,6 @@ void LinkerScript::processSectionCommands() {
|
||||||
sec->flags &= ~(uint64_t)SHF_ALLOC;
|
sec->flags &= ~(uint64_t)SHF_ALLOC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void LinkerScript::processSymbolAssignments() {
|
|
||||||
// Dot outside an output section still represents a relative address, whose
|
|
||||||
// sh_shndx should not be SHN_UNDEF or SHN_ABS. Create a dummy aether section
|
|
||||||
// that fills the void outside a section. It has an index of one, which is
|
|
||||||
// indistinguishable from any other regular section index.
|
|
||||||
aether = make<OutputSection>("", 0, SHF_ALLOC);
|
|
||||||
aether->sectionIndex = 1;
|
|
||||||
|
|
||||||
// ctx captures the local AddressState and makes it accessible deliberately.
|
|
||||||
// This is needed as there are some cases where we cannot just thread the
|
|
||||||
// current state through to a lambda function created by the script parser.
|
|
||||||
AddressState state;
|
|
||||||
ctx = &state;
|
|
||||||
ctx->outSec = aether;
|
|
||||||
|
|
||||||
for (BaseCommand *base : sectionCommands) {
|
|
||||||
if (auto *cmd = dyn_cast<SymbolAssignment>(base))
|
|
||||||
addSymbol(cmd);
|
|
||||||
else
|
|
||||||
for (BaseCommand *sub_base : cast<OutputSection>(base)->sectionCommands)
|
|
||||||
if (auto *cmd = dyn_cast<SymbolAssignment>(sub_base))
|
|
||||||
addSymbol(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = nullptr;
|
ctx = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,7 +274,6 @@ public:
|
||||||
const Defined *assignAddresses();
|
const Defined *assignAddresses();
|
||||||
void allocateHeaders(std::vector<PhdrEntry *> &phdrs);
|
void allocateHeaders(std::vector<PhdrEntry *> &phdrs);
|
||||||
void processSectionCommands();
|
void processSectionCommands();
|
||||||
void processSymbolAssignments();
|
|
||||||
void declareSymbols();
|
void declareSymbols();
|
||||||
|
|
||||||
// Used to handle INSERT AFTER statements.
|
// Used to handle INSERT AFTER statements.
|
||||||
|
|
|
@ -152,7 +152,7 @@ static void removeEmptyPTLoad(std::vector<PhdrEntry *> &phdrs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void elf::copySectionsIntoPartitions() {
|
static void copySectionsIntoPartitions() {
|
||||||
std::vector<InputSectionBase *> newSections;
|
std::vector<InputSectionBase *> newSections;
|
||||||
for (unsigned part = 2; part != partitions.size() + 1; ++part) {
|
for (unsigned part = 2; part != partitions.size() + 1; ++part) {
|
||||||
for (InputSectionBase *s : inputSections) {
|
for (InputSectionBase *s : inputSections) {
|
||||||
|
@ -308,7 +308,8 @@ static OutputSection *findSection(StringRef name, unsigned partition = 1) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT> void elf::createSyntheticSections() {
|
// Initialize Out members.
|
||||||
|
template <class ELFT> static void createSyntheticSections() {
|
||||||
// Initialize all pointers with NULL. This is needed because
|
// Initialize all pointers with NULL. This is needed because
|
||||||
// you can call lld::elf::main more than once as a library.
|
// you can call lld::elf::main more than once as a library.
|
||||||
memset(&Out::first, 0, sizeof(Out));
|
memset(&Out::first, 0, sizeof(Out));
|
||||||
|
@ -534,6 +535,24 @@ template <class ELFT> void elf::createSyntheticSections() {
|
||||||
|
|
||||||
// The main function of the writer.
|
// The main function of the writer.
|
||||||
template <class ELFT> void Writer<ELFT>::run() {
|
template <class ELFT> void Writer<ELFT>::run() {
|
||||||
|
// Make copies of any input sections that need to be copied into each
|
||||||
|
// partition.
|
||||||
|
copySectionsIntoPartitions();
|
||||||
|
|
||||||
|
// Create linker-synthesized sections such as .got or .plt.
|
||||||
|
// Such sections are of type input section.
|
||||||
|
createSyntheticSections<ELFT>();
|
||||||
|
|
||||||
|
// Some input sections that are used for exception handling need to be moved
|
||||||
|
// into synthetic sections. Do that now so that they aren't assigned to
|
||||||
|
// output sections in the usual way.
|
||||||
|
if (!config->relocatable)
|
||||||
|
combineEhSections();
|
||||||
|
|
||||||
|
// We want to process linker script commands. When SECTIONS command
|
||||||
|
// is given we let it create sections.
|
||||||
|
script->processSectionCommands();
|
||||||
|
|
||||||
// Linker scripts controls how input sections are assigned to output sections.
|
// Linker scripts controls how input sections are assigned to output sections.
|
||||||
// Input sections that were not handled by scripts are called "orphans", and
|
// Input sections that were not handled by scripts are called "orphans", and
|
||||||
// they are assigned to output sections by the default rule. Process that.
|
// they are assigned to output sections by the default rule. Process that.
|
||||||
|
@ -1718,14 +1737,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||||
symtab->forEachSymbol(
|
symtab->forEachSymbol(
|
||||||
[](Symbol *s) { s->isPreemptible = computeIsPreemptible(*s); });
|
[](Symbol *s) { s->isPreemptible = computeIsPreemptible(*s); });
|
||||||
|
|
||||||
// Change values of linker-script-defined symbols from placeholders (assigned
|
|
||||||
// by declareSymbols) to actual definitions.
|
|
||||||
script->processSymbolAssignments();
|
|
||||||
|
|
||||||
// Scan relocations. This must be done after every symbol is declared so that
|
// Scan relocations. This must be done after every symbol is declared so that
|
||||||
// we can correctly decide if a dynamic relocation is needed. This is called
|
// we can correctly decide if a dynamic relocation is needed.
|
||||||
// after processSymbolAssignments() because it needs to know whether a
|
|
||||||
// linker-script-defined symbol is absolute.
|
|
||||||
if (!config->relocatable) {
|
if (!config->relocatable) {
|
||||||
forEachRelSec(scanRelocations<ELFT>);
|
forEachRelSec(scanRelocations<ELFT>);
|
||||||
reportUndefinedSymbols<ELFT>();
|
reportUndefinedSymbols<ELFT>();
|
||||||
|
@ -2718,11 +2731,6 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||||
part.buildId->writeBuildId(buildId);
|
part.buildId->writeBuildId(buildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template void elf::createSyntheticSections<ELF32LE>();
|
|
||||||
template void elf::createSyntheticSections<ELF32BE>();
|
|
||||||
template void elf::createSyntheticSections<ELF64LE>();
|
|
||||||
template void elf::createSyntheticSections<ELF64BE>();
|
|
||||||
|
|
||||||
template void elf::writeResult<ELF32LE>();
|
template void elf::writeResult<ELF32LE>();
|
||||||
template void elf::writeResult<ELF32BE>();
|
template void elf::writeResult<ELF32BE>();
|
||||||
template void elf::writeResult<ELF64LE>();
|
template void elf::writeResult<ELF64LE>();
|
||||||
|
|
|
@ -20,8 +20,6 @@ namespace elf {
|
||||||
class InputFile;
|
class InputFile;
|
||||||
class OutputSection;
|
class OutputSection;
|
||||||
class InputSectionBase;
|
class InputSectionBase;
|
||||||
void copySectionsIntoPartitions();
|
|
||||||
template <class ELFT> void createSyntheticSections();
|
|
||||||
void combineEhSections();
|
void combineEhSections();
|
||||||
template <class ELFT> void writeResult();
|
template <class ELFT> void writeResult();
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
# REQUIRES: x86
|
# REQUIRES: x86
|
||||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||||
|
|
||||||
## The definitions of symbol assignments may reference other symbols.
|
|
||||||
## Test we can handle them.
|
|
||||||
|
|
||||||
# RUN: echo "SECTIONS { aaa = foo | 1; .text : { *(.text*) } }" > %t3.script
|
# RUN: echo "SECTIONS { aaa = foo | 1; .text : { *(.text*) } }" > %t3.script
|
||||||
# RUN: ld.lld -o %t --script %t3.script %t.o
|
# RUN: not ld.lld -o %t --script %t3.script %t.o 2>&1 | FileCheck %s
|
||||||
# RUN: llvm-objdump -t %t | FileCheck --check-prefix=VAL1 %s
|
|
||||||
|
|
||||||
# VAL1: 0000000000000000 .text 00000000 foo
|
# CHECK: error: {{.*}}.script:1: unable to evaluate expression: input section .text has no output section assigned
|
||||||
# VAL1: 0000000000000001 .text 00000000 aaa
|
|
||||||
|
# Simple cases that we can handle.
|
||||||
|
|
||||||
# RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text : { *(.text*) } }" > %t.script
|
# RUN: echo "SECTIONS { aaa = ABSOLUTE(foo - 1) + 1; .text : { *(.text*) } }" > %t.script
|
||||||
# RUN: ld.lld -o %t --script %t.script %t.o
|
# RUN: ld.lld -o %t --script %t.script %t.o
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
# REQUIRES: x86
|
|
||||||
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
|
|
||||||
# RUN: echo 'SECTIONS { .text : { *(.text*) } }' > %t1.script
|
|
||||||
|
|
||||||
## Sections within the same output section can be freely folded.
|
|
||||||
# RUN: ld.lld %t.o --script %t1.script --icf=all --print-icf-sections -o %t | FileCheck --check-prefix=ICF1 %s
|
|
||||||
# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC1 %s --implicit-check-not=.text
|
|
||||||
|
|
||||||
# ICF1: selected section {{.*}}.o:(.text.foo0)
|
|
||||||
# ICF1-NEXT: removing identical section {{.*}}.o:(.text.foo1)
|
|
||||||
# ICF1-NEXT: removing identical section {{.*}}.o:(.text.bar0)
|
|
||||||
# ICF1-NEXT: removing identical section {{.*}}.o:(.text.bar1)
|
|
||||||
|
|
||||||
# SEC1: .text PROGBITS 0000000000000000 001000 000001
|
|
||||||
|
|
||||||
## Sections with different output sections cannot be folded. Without the
|
|
||||||
## linker script, .text.foo* and .text.bar* go to the same output section
|
|
||||||
## .text and they will be folded.
|
|
||||||
# RUN: echo 'SECTIONS { .text.foo : {*(.text.foo*)} .text.bar : {*(.text.bar*)} }' > %t2.script
|
|
||||||
# RUN: ld.lld %t.o --script %t2.script --icf=all --print-icf-sections -o %t | FileCheck --check-prefix=ICF2 %s
|
|
||||||
# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC2 %s
|
|
||||||
|
|
||||||
# ICF2: selected section {{.*}}.o:(.text.foo0)
|
|
||||||
# ICF2-NEXT: removing identical section {{.*}}.o:(.text.foo1)
|
|
||||||
# ICF2-NEXT: selected section {{.*}}.o:(.text.bar0)
|
|
||||||
# ICF2-NEXT: removing identical section {{.*}}.o:(.text.bar1)
|
|
||||||
|
|
||||||
# SEC2: .text.foo PROGBITS 0000000000000000 001000 000001
|
|
||||||
# SEC2-NEXT: .text.bar PROGBITS 0000000000000001 001001 000001
|
|
||||||
|
|
||||||
## .text.bar* are orphans that get assigned to .text.
|
|
||||||
# RUN: echo 'SECTIONS { .text.foo : {*(.text.foo*)} }' > %t3.script
|
|
||||||
# RUN: ld.lld %t.o --script %t3.script --icf=all --print-icf-sections -o %t | FileCheck --check-prefix=ICF2 %s
|
|
||||||
# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC3 %s
|
|
||||||
|
|
||||||
# SEC3: .text.foo PROGBITS 0000000000000000 001000 000001
|
|
||||||
# SEC3-NEXT: .text PROGBITS 0000000000000004 001004 000001
|
|
||||||
|
|
||||||
.section .text.foo0,"ax"
|
|
||||||
ret
|
|
||||||
.section .text.foo1,"ax"
|
|
||||||
ret
|
|
||||||
.section .text.bar0,"ax"
|
|
||||||
ret
|
|
||||||
.section .text.bar1,"ax"
|
|
||||||
ret
|
|
|
@ -23,11 +23,11 @@
|
||||||
# SUBALIGN: 03000000 00000000 04000000 00000000
|
# SUBALIGN: 03000000 00000000 04000000 00000000
|
||||||
|
|
||||||
## Test we do not assert or crash when dot(.) is used inside SUBALIGN.
|
## Test we do not assert or crash when dot(.) is used inside SUBALIGN.
|
||||||
## Value of dot is undefined. Some versions of ld.bfd do not allow to use dot
|
## ld.bfd does not allow to use dot in such expressions, our behavior is
|
||||||
## in such expressions.
|
## different for simplicity of implementation. Value of dot is undefined.
|
||||||
# RUN: echo "SECTIONS { . = 0x32; .aaa : SUBALIGN(.) { *(.aaa*) } }" > %t3.script
|
# RUN: echo "SECTIONS { . = 0x32; .aaa : SUBALIGN(.) { *(.aaa*) } }" > %t3.script
|
||||||
# RUN: not ld.lld %t1.o --script %t3.script -o /dev/null 2>&1 | FileCheck --check-prefix=ERR1 %s
|
# RUN: ld.lld %t1.o --script %t3.script -o %t3
|
||||||
# ERR1: {{.*}}.script:1: unable to get location counter value
|
# RUN: llvm-objdump -s %t3 > /dev/null
|
||||||
|
|
||||||
## Test we are able to link with zero alignment, this is consistent with bfd 2.26.1.
|
## Test we are able to link with zero alignment, this is consistent with bfd 2.26.1.
|
||||||
# RUN: echo "SECTIONS { .aaa : SUBALIGN(0) { *(.aaa*) } }" > %t4.script
|
# RUN: echo "SECTIONS { .aaa : SUBALIGN(0) { *(.aaa*) } }" > %t4.script
|
||||||
|
@ -36,8 +36,8 @@
|
||||||
|
|
||||||
## Test we fail gracefuly when alignment value is not a power of 2.
|
## Test we fail gracefuly when alignment value is not a power of 2.
|
||||||
# RUN: echo "SECTIONS { .aaa : SUBALIGN(3) { *(.aaa*) } }" > %t5.script
|
# RUN: echo "SECTIONS { .aaa : SUBALIGN(3) { *(.aaa*) } }" > %t5.script
|
||||||
# RUN: not ld.lld %t1.o --script %t5.script -o /dev/null 2>&1 | FileCheck --check-prefix=ERR2 %s
|
# RUN: not ld.lld %t1.o --script %t5.script -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s
|
||||||
# ERR2: {{.*}}.script:1: alignment must be power of 2
|
# ERR: {{.*}}.script:1: alignment must be power of 2
|
||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
|
|
Loading…
Reference in New Issue