Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
lld/ELF/LinkerScript.cpp
Show First 20 Lines • Show All 248 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
// Process INSERT [AFTER|BEFORE] commands. For each command, we move the | // Process INSERT [AFTER|BEFORE] commands. For each command, we move the | ||||
// specified output section to the designated place. | // specified output section to the designated place. | ||||
void LinkerScript::processInsertCommands() { | void LinkerScript::processInsertCommands() { | ||||
for (const InsertCommand &cmd : insertCommands) { | for (const InsertCommand &cmd : insertCommands) { | ||||
// If cmd.os is empty, it may have been discarded by | // If cmd.os is empty, it may have been discarded by | ||||
// adjustSectionsBeforeSorting(). We do not handle such output sections. | // adjustSectionsBeforeSorting(). We do not handle such output sections. | ||||
auto from = llvm::find(sectionCommands, cmd.os); | auto from = llvm::find_if(sectionCommands, [&](BaseCommand *base) { | ||||
return isa<OutputSection>(base) && | |||||
cast<OutputSection>(base)->name == cmd.name; | |||||
}); | |||||
if (from == sectionCommands.end()) | if (from == sectionCommands.end()) | ||||
continue; | continue; | ||||
OutputSection *osec = cast<OutputSection>(*from); | |||||
sectionCommands.erase(from); | sectionCommands.erase(from); | ||||
auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) { | auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) { | ||||
auto *to = dyn_cast<OutputSection>(base); | auto *to = dyn_cast<OutputSection>(base); | ||||
return to != nullptr && to->name == cmd.where; | return to != nullptr && to->name == cmd.where; | ||||
}); | }); | ||||
if (insertPos == sectionCommands.end()) { | if (insertPos == sectionCommands.end()) { | ||||
error("unable to insert " + cmd.os->name + | error("unable to insert " + osec->name + | ||||
(cmd.isAfter ? " after " : " before ") + cmd.where); | (cmd.isAfter ? " after " : " before ") + cmd.where); | ||||
} else { | } else { | ||||
if (cmd.isAfter) | if (cmd.isAfter) | ||||
++insertPos; | ++insertPos; | ||||
sectionCommands.insert(insertPos, cmd.os); | sectionCommands.insert(insertPos, osec); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Symbols defined in script should not be inlined by LTO. At the same time | // Symbols defined in script should not be inlined by LTO. At the same time | ||||
// we don't know their final values until late stages of link. Here we scan | // we don't know their final values until late stages of link. Here we scan | ||||
// over symbol assignment commands and create placeholder symbols if needed. | // over symbol assignment commands and create placeholder symbols if needed. | ||||
void LinkerScript::declareSymbols() { | void LinkerScript::declareSymbols() { | ||||
▲ Show 20 Lines • Show All 261 Lines • ▼ Show 20 Lines | if (auto *cmd = dyn_cast<InputSectionDescription>(base)) { | ||||
ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end()); | ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end()); | ||||
} | } | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
// Create output sections described by SECTIONS commands. | // Create output sections described by SECTIONS commands. | ||||
void LinkerScript::processSectionCommands() { | void LinkerScript::processSectionCommands() { | ||||
size_t i = 0; | auto process = [this](OutputSection *osec) { | ||||
for (BaseCommand *base : sectionCommands) { | std::vector<InputSectionBase *> v = createInputSectionList(*osec); | ||||
if (auto *sec = dyn_cast<OutputSection>(base)) { | |||||
std::vector<InputSectionBase *> v = createInputSectionList(*sec); | |||||
// The output section name `/DISCARD/' is special. | // The output section name `/DISCARD/' is special. | ||||
// Any input section assigned to it is discarded. | // Any input section assigned to it is discarded. | ||||
if (sec->name == "/DISCARD/") { | if (osec->name == "/DISCARD/") { | ||||
for (InputSectionBase *s : v) | for (InputSectionBase *s : v) | ||||
discard(s); | discard(s); | ||||
discardSynthetic(*sec); | discardSynthetic(*osec); | ||||
sec->sectionCommands.clear(); | osec->sectionCommands.clear(); | ||||
continue; | return false; | ||||
} | } | ||||
// This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive | // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive | ||||
// ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input | // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input | ||||
// sections satisfy a given constraint. If not, a directive is handled | // sections satisfy a given constraint. If not, a directive is handled | ||||
// as if it wasn't present from the beginning. | // as if it wasn't present from the beginning. | ||||
// | // | ||||
// Because we'll iterate over SectionCommands many more times, the easy | // Because we'll iterate over SectionCommands many more times, the easy | ||||
// way to "make it as if it wasn't present" is to make it empty. | // way to "make it as if it wasn't present" is to make it empty. | ||||
if (!matchConstraints(v, sec->constraint)) { | if (!matchConstraints(v, osec->constraint)) { | ||||
for (InputSectionBase *s : v) | for (InputSectionBase *s : v) | ||||
s->parent = nullptr; | s->parent = nullptr; | ||||
sec->sectionCommands.clear(); | osec->sectionCommands.clear(); | ||||
continue; | return false; | ||||
} | } | ||||
// 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. | ||||
if (sec->subalignExpr) { | if (osec->subalignExpr) { | ||||
uint32_t subalign = sec->subalignExpr().getValue(); | uint32_t subalign = osec->subalignExpr().getValue(); | ||||
for (InputSectionBase *s : v) | for (InputSectionBase *s : v) | ||||
s->alignment = subalign; | s->alignment = subalign; | ||||
} | } | ||||
// Set the partition field the same way OutputSection::recordSection() | // Set the partition field the same way OutputSection::recordSection() | ||||
// does. Partitions cannot be used with the SECTIONS command, so this is | // does. Partitions cannot be used with the SECTIONS command, so this is | ||||
// always 1. | // always 1. | ||||
sec->partition = 1; | osec->partition = 1; | ||||
return true; | |||||
}; | |||||
sec->sectionIndex = i++; | // Process OVERWRITE_SECTIONS first so that it can overwrite the main script | ||||
// or orphans. | |||||
DenseMap<StringRef, OutputSection *> map; | |||||
size_t i = 0; | |||||
for (OutputSection *osec : overwriteSections) | |||||
if (process(osec) && !map.try_emplace(osec->name, osec).second) | |||||
warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name); | |||||
for (BaseCommand *&base : sectionCommands) | |||||
if (auto *osec = dyn_cast<OutputSection>(base)) { | |||||
if (OutputSection *overwrite = map.lookup(osec->name)) { | |||||
log(overwrite->location + " overwrites " + osec->name); | |||||
overwrite->sectionIndex = i++; | |||||
base = overwrite; | |||||
} else if (process(osec)) { | |||||
osec->sectionIndex = i++; | |||||
} | } | ||||
} | } | ||||
// If an OVERWRITE_SECTIONS specified output section is not in | |||||
// sectionCommands, append it to the end. The section will be inserted by | |||||
// orphan placement. | |||||
for (OutputSection *osec : overwriteSections) | |||||
if (osec->partition == 1 && osec->sectionIndex == UINT32_MAX) | |||||
sectionCommands.push_back(osec); | |||||
} | } | ||||
void LinkerScript::processSymbolAssignments() { | void LinkerScript::processSymbolAssignments() { | ||||
// Dot outside an output section still represents a relative address, whose | // 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 | // 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 | // that fills the void outside a section. It has an index of one, which is | ||||
// indistinguishable from any other regular section index. | // indistinguishable from any other regular section index. | ||||
aether = make<OutputSection>("", 0, SHF_ALLOC); | aether = make<OutputSection>("", 0, SHF_ALLOC); | ||||
▲ Show 20 Lines • Show All 725 Lines • Show Last 20 Lines |