-
Notifications
You must be signed in to change notification settings - Fork 14.6k
lld: add support for NOCROSSREFS(_TO) #95714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2358,3 +2358,45 @@ template void elf::scanRelocations<ELF32LE>(); | |
template void elf::scanRelocations<ELF32BE>(); | ||
template void elf::scanRelocations<ELF64LE>(); | ||
template void elf::scanRelocations<ELF64BE>(); | ||
|
||
static void forEachAllocInputSectionDescription( | ||
ArrayRef<OutputSection *> outputSections, | ||
llvm::function_ref<void(OutputSection *, InputSectionDescription *)> fn) { | ||
for (OutputSection *os : outputSections) { | ||
if (!(os->flags & SHF_ALLOC)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GNU ld reports violations due to non-SHF_ALLOC sections. I'll fix it in my branch. |
||
continue; | ||
for (SectionCommand *bc : os->commands) | ||
if (auto *isd = dyn_cast<InputSectionDescription>(bc)) | ||
fn(os, isd); | ||
} | ||
} | ||
|
||
static void checkSectionNoCrossRefs(OutputSection *outSec, | ||
InputSectionDescription *inSecDescr) { | ||
for (const auto &list : script->noCrossRefLists) { | ||
if (!list.matchesRefFromSection(outSec)) | ||
continue; | ||
|
||
for (const auto &inSection : inSecDescr->sections) { | ||
for (const auto &relocation : inSection->relocations) { | ||
auto *destOutSec = relocation.sym->getOutputSection(); | ||
if (!destOutSec) | ||
continue; | ||
|
||
// Relocations from section to itself are allowed. | ||
if (destOutSec->name == outSec->name || | ||
!list.matchesRefToSection(destOutSec)) | ||
continue; | ||
|
||
error(inSection->getLocation(relocation.offset) + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my branch I'll use this:
I think |
||
": prohibited cross reference from " + inSection->name.str() + | ||
" to " + relocation.sym->getName().str() + " in " + | ||
destOutSec->name.str()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
void elf::checkNoCrossRefs() { | ||
forEachAllocInputSectionDescription(outputSections, checkSectionNoCrossRefs); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,7 @@ class ScriptParser final : ScriptLexer { | |
void readTarget(); | ||
void readVersion(); | ||
void readVersionScriptCommand(); | ||
void readNoCrossRefs(bool to); | ||
|
||
SymbolAssignment *readSymbolAssignment(StringRef name); | ||
ByteCommand *readByteCommand(StringRef tok); | ||
|
@@ -235,6 +236,26 @@ void ScriptParser::readVersionScriptCommand() { | |
} | ||
} | ||
|
||
void ScriptParser::readNoCrossRefs(bool to) { | ||
expect("("); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our code style is quite terse. We only blank lines when there is a significant "pause" need. |
||
script->noCrossRefLists.push_back({}); | ||
auto &list = script->noCrossRefLists.back(); | ||
|
||
if (to && peek() != ")") | ||
list.toSection = next(); | ||
|
||
while (!atEOF() && !errorCount() && peek() != ")") | ||
list.outputSections.push_back(next()); | ||
|
||
// Discard meaningless lists | ||
if ((to && list.outputSections.empty()) || | ||
(!to && list.outputSections.size() < 2)) | ||
script->noCrossRefLists.pop_back(); | ||
|
||
expect(")"); | ||
} | ||
|
||
void ScriptParser::readVersion() { | ||
expect("{"); | ||
readVersionScriptCommand(); | ||
|
@@ -279,6 +300,10 @@ void ScriptParser::readLinkerScript() { | |
readTarget(); | ||
} else if (tok == "VERSION") { | ||
readVersion(); | ||
} else if (tok == "NOCROSSREFS") { | ||
readNoCrossRefs(/*to=*/false); | ||
} else if (tok == "NOCROSSREFS_TO") { | ||
readNoCrossRefs(/*to=*/true); | ||
} else if (SymbolAssignment *cmd = readAssignment(tok)) { | ||
script->sectionCommands.push_back(cmd); | ||
} else { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
# REQUIRES: x86 | ||
# RUN: rm -rf %t && split-file %s %t && cd %t | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
# RUN: not ld.lld main.o -o main --script script1.ld 2>&1 | FileCheck -check-prefix=ERR %s | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
# ERR: {{.*}} error: main.o:(.text+0x6): prohibited cross reference from .text to in .text1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. something is omitted after |
||
|
||
#--- script1.ld | ||
NOCROSSREFS(.text .text1); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll clean up the tests. We actually don't need |
||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: not ld.lld main.o -o main --script script2.ld 2>&1 | FileCheck -check-prefix=ERR1 %s | ||
# ERR1: {{.*}} error: main.o:(.text+0x6): prohibited cross reference from .text to in .text1 | ||
|
||
#--- script2.ld | ||
NOCROSSREFS_TO(.text1 .text); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: not ld.lld main.o -o main --script script3.ld 2>&1 | FileCheck -check-prefix=ERR2 %s | ||
# ERR2: {{.*}} error: main.o:(.text+0x6): prohibited cross reference from .text to in .text1 | ||
|
||
#--- script3.ld | ||
NOCROSSREFS(.text1 .text .text2); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script4.ld 2>&1 | ||
|
||
#--- script4.ld | ||
NOCROSSREFS_TO(.text .text1); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script5.ld 2>&1 | ||
|
||
#--- script5.ld | ||
NOCROSSREFS_TO(); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script6.ld 2>&1 | ||
|
||
#--- script6.ld | ||
NOCROSSREFS(); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script7.ld 2>&1 | ||
|
||
#--- script7.ld | ||
NOCROSSREFS(.text); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script8.ld 2>&1 | ||
|
||
#--- script8.ld | ||
NOCROSSREFS_TO(.text); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script9.ld 2>&1 | ||
|
||
#--- script9.ld | ||
NOCROSSREFS_TO(.text2 .text); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script10.ld 2>&1 | ||
|
||
#--- script10.ld | ||
NOCROSSREFS(.text .text2); | ||
SECTIONS { | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script11.ld 2>&1 | ||
|
||
#--- script11.ld | ||
NOCROSSREFS(.text .text2); | ||
SECTIONS { | ||
foo = ABSOLUTE(.); | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: ld.lld main.o -o main --script script12.ld 2>&1 | ||
|
||
#--- script12.ld | ||
NOCROSSREFS(.text .text2); | ||
SECTIONS { | ||
foo = ABSOLUTE(.); | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
.bss : { *(.unused) } | ||
} | ||
|
||
# RUN: llvm-mc --triple=x86_64-unknown-linux -filetype=obj -o main.o main.s | ||
# RUN: not ld.lld main.o -o main --script script13.ld 2>&1 | FileCheck -check-prefix=ERR3 %s | ||
# ERR3: {{.*}} error: main.o:(.text+0x5): prohibited cross reference from .text to unused in .bss | ||
|
||
#--- script13.ld | ||
NOCROSSREFS(.text .bss); | ||
SECTIONS { | ||
foo = ABSOLUTE(.); | ||
.text : { *(.text) } | ||
.text1 : { *(.text1) } | ||
.text2 : { *(.text2) } | ||
.bss : { *(.unused) } | ||
} | ||
|
||
#--- main.s | ||
.global _start | ||
_start: | ||
call test | ||
|
||
.type unused,@object | ||
.comm unused,4,4 | ||
|
||
.section .noalloc,"",@progbits | ||
.quad unused | ||
|
||
.section .text | ||
test: | ||
.reloc ., R_X86_64_32, unused | ||
call test1 | ||
|
||
.section .text2 | ||
test2: | ||
.reloc ., R_X86_64_32, foo | ||
nop | ||
|
||
.section .text1 | ||
test1: | ||
nop |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't add code after explicit template instantiations. I would place the checks to LinkerScript.cpp.
Relocations.cpp code should minimize uses of
outputSections
.