2017-04-05 05:07:39 +00:00
|
|
|
//===- ScriptParser.cpp ---------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-04-05 05:07:39 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2017-04-05 05:50:08 +00:00
|
|
|
//
|
|
|
|
// This file contains a recursive-descendent parser for linker scripts.
|
|
|
|
// Parsed results are stored to Config and Script global objects.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
#include "ScriptParser.h"
|
|
|
|
#include "Config.h"
|
|
|
|
#include "Driver.h"
|
2022-02-23 19:18:24 -08:00
|
|
|
#include "InputFiles.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include "LinkerScript.h"
|
|
|
|
#include "OutputSections.h"
|
|
|
|
#include "ScriptLexer.h"
|
2022-02-07 21:53:34 -08:00
|
|
|
#include "SymbolTable.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include "Symbols.h"
|
|
|
|
#include "Target.h"
|
2022-01-20 14:53:18 -05:00
|
|
|
#include "lld/Common/CommonLinkerContext.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2017-06-07 03:48:56 +00:00
|
|
|
#include "llvm/BinaryFormat/ELF.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
2020-07-27 11:49:24 +03:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include "llvm/Support/Path.h"
|
2022-06-25 20:25:34 -07:00
|
|
|
#include "llvm/Support/SaveAndRestore.h"
|
2020-11-03 14:41:09 +00:00
|
|
|
#include "llvm/Support/TimeProfiler.h"
|
2017-04-05 05:07:39 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <limits>
|
2024-03-25 16:11:21 -07:00
|
|
|
#include <optional>
|
2017-04-05 05:07:39 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::ELF;
|
2017-04-11 22:45:57 +00:00
|
|
|
using namespace llvm::support::endian;
|
2020-05-14 22:18:58 -07:00
|
|
|
using namespace lld;
|
|
|
|
using namespace lld::elf;
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2017-04-05 05:08:01 +00:00
|
|
|
namespace {
|
|
|
|
class ScriptParser final : ScriptLexer {
|
2017-04-05 05:07:39 +00:00
|
|
|
public:
|
2024-09-21 11:51:02 -07:00
|
|
|
ScriptParser(Ctx &ctx, MemoryBufferRef mb) : ScriptLexer(ctx, mb), ctx(ctx) {}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
void readLinkerScript();
|
|
|
|
void readVersionScript();
|
|
|
|
void readDynamicList();
|
2024-07-28 12:38:10 -07:00
|
|
|
void readDefsym();
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
void addFile(StringRef path);
|
|
|
|
|
|
|
|
void readAsNeeded();
|
|
|
|
void readEntry();
|
|
|
|
void readExtern();
|
|
|
|
void readGroup();
|
|
|
|
void readInclude();
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
void readInput();
|
2017-04-05 05:07:39 +00:00
|
|
|
void readMemory();
|
|
|
|
void readOutput();
|
|
|
|
void readOutputArch();
|
|
|
|
void readOutputFormat();
|
2021-06-13 12:41:11 -07:00
|
|
|
void readOverwriteSections();
|
2017-04-05 05:07:39 +00:00
|
|
|
void readPhdrs();
|
2017-09-08 08:23:15 +00:00
|
|
|
void readRegionAlias();
|
2017-04-05 05:07:39 +00:00
|
|
|
void readSearchDir();
|
|
|
|
void readSections();
|
2018-08-06 21:29:41 +00:00
|
|
|
void readTarget();
|
2017-04-05 05:07:39 +00:00
|
|
|
void readVersion();
|
|
|
|
void readVersionScriptCommand();
|
2024-07-17 10:45:59 -07:00
|
|
|
void readNoCrossRefs(bool to);
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2024-07-27 16:19:57 -07:00
|
|
|
StringRef readName();
|
2018-04-25 11:16:31 +00:00
|
|
|
SymbolAssignment *readSymbolAssignment(StringRef name);
|
2017-10-11 04:22:09 +00:00
|
|
|
ByteCommand *readByteCommand(StringRef tok);
|
2018-11-14 21:05:20 +00:00
|
|
|
std::array<uint8_t, 4> readFill();
|
2024-07-20 16:35:38 -07:00
|
|
|
bool readSectionDirective(OutputSection *cmd, StringRef tok);
|
2017-07-27 19:22:43 +00:00
|
|
|
void readSectionAddressType(OutputSection *cmd);
|
2022-03-08 11:23:41 -08:00
|
|
|
OutputDesc *readOverlaySectionDescription();
|
|
|
|
OutputDesc *readOutputSectionDescription(StringRef outSec);
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionCommand *, 0> readOverlay();
|
2024-08-05 13:06:45 -07:00
|
|
|
SectionClassDesc *readSectionClassDescription();
|
|
|
|
StringRef readSectionClassName();
|
2021-12-26 13:53:47 -08:00
|
|
|
SmallVector<StringRef, 0> readOutputSectionPhdrs();
|
2020-01-15 09:38:00 +00:00
|
|
|
std::pair<uint64_t, uint64_t> readInputSectionFlags();
|
2017-04-05 05:07:39 +00:00
|
|
|
InputSectionDescription *readInputSectionDescription(StringRef tok);
|
|
|
|
StringMatcher readFilePatterns();
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionPattern, 0> readInputSectionsList();
|
2020-01-15 09:38:00 +00:00
|
|
|
InputSectionDescription *readInputSectionRules(StringRef filePattern,
|
|
|
|
uint64_t withFlags,
|
|
|
|
uint64_t withoutFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
unsigned readPhdrType();
|
2020-11-12 08:46:53 -08:00
|
|
|
SortSectionPolicy peekSortKind();
|
2017-04-05 05:07:39 +00:00
|
|
|
SortSectionPolicy readSortKind();
|
|
|
|
SymbolAssignment *readProvideHidden(bool provide, bool hidden);
|
2018-04-25 11:16:31 +00:00
|
|
|
SymbolAssignment *readAssignment(StringRef tok);
|
2017-04-05 05:07:39 +00:00
|
|
|
void readSort();
|
2018-04-25 11:16:31 +00:00
|
|
|
Expr readAssert();
|
2017-08-03 16:05:08 +00:00
|
|
|
Expr readConstant();
|
|
|
|
Expr getPageSize();
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2020-03-06 11:49:58 -08:00
|
|
|
Expr readMemoryAssignment(StringRef, StringRef, StringRef);
|
2021-11-24 12:17:03 +07:00
|
|
|
void readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
|
|
|
|
uint32_t &negFlags, uint32_t &negInvFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2018-03-05 10:02:44 +00:00
|
|
|
Expr combine(StringRef op, Expr l, Expr r);
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr readExpr();
|
|
|
|
Expr readExpr1(Expr lhs, int minPrec);
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef readParenName();
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr readPrimary();
|
|
|
|
Expr readTernary(Expr cond);
|
|
|
|
Expr readParenExpr();
|
|
|
|
|
|
|
|
// For parsing version script.
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> readVersionExtern();
|
2017-04-05 05:07:39 +00:00
|
|
|
void readAnonymousDeclaration();
|
|
|
|
void readVersionDeclaration(StringRef verStr);
|
|
|
|
|
2021-12-26 20:12:55 -08:00
|
|
|
std::pair<SmallVector<SymbolVersion, 0>, SmallVector<SymbolVersion, 0>>
|
2017-04-05 05:07:39 +00:00
|
|
|
readSymbols();
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
Ctx &ctx;
|
|
|
|
|
2024-03-25 16:11:21 -07:00
|
|
|
// If we are currently parsing a PROVIDE|PROVIDE_HIDDEN command,
|
|
|
|
// then this member is set to the PROVIDE symbol name.
|
|
|
|
std::optional<llvm::StringRef> activeProvideSym;
|
2017-04-05 05:07:39 +00:00
|
|
|
};
|
2017-04-05 05:08:01 +00:00
|
|
|
} // namespace
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2017-07-13 20:30:35 +00:00
|
|
|
static StringRef unquote(StringRef s) {
|
2023-06-05 14:36:19 -07:00
|
|
|
if (s.starts_with("\""))
|
2017-07-13 20:30:35 +00:00
|
|
|
return s.substr(1, s.size() - 2);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
// Some operations only support one non absolute value. Move the
|
|
|
|
// absolute one to the right hand side for convenience.
|
2024-09-21 11:51:02 -07:00
|
|
|
static void moveAbsRight(LinkerScript &s, ExprValue &a, ExprValue &b) {
|
2017-09-20 19:24:57 +00:00
|
|
|
if (a.sec == nullptr || (a.forceAbsolute && !b.isAbsolute()))
|
2017-04-05 05:07:39 +00:00
|
|
|
std::swap(a, b);
|
|
|
|
if (!b.isAbsolute())
|
2024-09-21 11:51:02 -07:00
|
|
|
s.recordError(a.loc +
|
|
|
|
": at least one side of the expression must be absolute");
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
static ExprValue add(LinkerScript &s, ExprValue a, ExprValue b) {
|
|
|
|
moveAbsRight(s, a, b);
|
2017-09-12 00:06:00 +00:00
|
|
|
return {a.sec, a.forceAbsolute, a.getSectionOffset() + b.getValue(), a.loc};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static ExprValue sub(ExprValue a, ExprValue b) {
|
2017-12-26 18:11:14 +00:00
|
|
|
// The distance between two symbols in sections is absolute.
|
2017-12-22 21:55:28 +00:00
|
|
|
if (!a.isAbsolute() && !b.isAbsolute())
|
|
|
|
return a.getValue() - b.getValue();
|
2017-10-11 00:06:27 +00:00
|
|
|
return {a.sec, false, a.getSectionOffset() - b.getValue(), a.loc};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
static ExprValue bitAnd(LinkerScript &s, ExprValue a, ExprValue b) {
|
|
|
|
moveAbsRight(s, a, b);
|
2017-04-05 05:07:39 +00:00
|
|
|
return {a.sec, a.forceAbsolute,
|
2017-06-07 08:54:43 +00:00
|
|
|
(a.getValue() & b.getValue()) - a.getSecAddr(), a.loc};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
static ExprValue bitXor(LinkerScript &s, ExprValue a, ExprValue b) {
|
|
|
|
moveAbsRight(s, a, b);
|
2023-07-15 14:10:40 -07:00
|
|
|
return {a.sec, a.forceAbsolute,
|
|
|
|
(a.getValue() ^ b.getValue()) - a.getSecAddr(), a.loc};
|
|
|
|
}
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
static ExprValue bitOr(LinkerScript &s, ExprValue a, ExprValue b) {
|
|
|
|
moveAbsRight(s, a, b);
|
2017-04-05 05:07:39 +00:00
|
|
|
return {a.sec, a.forceAbsolute,
|
2017-06-07 08:54:43 +00:00
|
|
|
(a.getValue() | b.getValue()) - a.getSecAddr(), a.loc};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readDynamicList() {
|
|
|
|
expect("{");
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> locals;
|
|
|
|
SmallVector<SymbolVersion, 0> globals;
|
2017-09-08 18:16:59 +00:00
|
|
|
std::tie(locals, globals) = readSymbols();
|
|
|
|
expect(";");
|
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
StringRef tok = peek();
|
|
|
|
if (tok.size()) {
|
|
|
|
setError("EOF expected, but got " + tok);
|
2017-09-08 18:16:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!locals.empty()) {
|
|
|
|
setError("\"local:\" scope not supported in --dynamic-list");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (SymbolVersion v : globals)
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.dynamicList.push_back(v);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readVersionScript() {
|
|
|
|
readVersionScriptCommand();
|
2024-07-26 14:26:38 -07:00
|
|
|
StringRef tok = peek();
|
|
|
|
if (tok.size())
|
|
|
|
setError("EOF expected, but got " + tok);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readVersionScriptCommand() {
|
|
|
|
if (consume("{")) {
|
|
|
|
readAnonymousDeclaration();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
if (atEOF())
|
|
|
|
setError("unexpected EOF");
|
|
|
|
while (peek() != "}" && !atEOF()) {
|
2017-04-05 05:07:39 +00:00
|
|
|
StringRef verStr = next();
|
|
|
|
if (verStr == "{") {
|
|
|
|
setError("anonymous version definition is used in "
|
|
|
|
"combination with other version definitions");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
expect("{");
|
|
|
|
readVersionDeclaration(verStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readVersion() {
|
|
|
|
expect("{");
|
|
|
|
readVersionScriptCommand();
|
|
|
|
expect("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readLinkerScript() {
|
|
|
|
while (!atEOF()) {
|
|
|
|
StringRef tok = next();
|
2024-07-26 14:26:38 -07:00
|
|
|
if (atEOF())
|
|
|
|
break;
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == ";")
|
|
|
|
continue;
|
|
|
|
|
2018-04-25 11:16:31 +00:00
|
|
|
if (tok == "ENTRY") {
|
2017-04-05 05:07:39 +00:00
|
|
|
readEntry();
|
|
|
|
} else if (tok == "EXTERN") {
|
|
|
|
readExtern();
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
} else if (tok == "GROUP") {
|
2017-04-05 05:07:39 +00:00
|
|
|
readGroup();
|
|
|
|
} else if (tok == "INCLUDE") {
|
|
|
|
readInclude();
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
} else if (tok == "INPUT") {
|
|
|
|
readInput();
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "MEMORY") {
|
|
|
|
readMemory();
|
|
|
|
} else if (tok == "OUTPUT") {
|
|
|
|
readOutput();
|
|
|
|
} else if (tok == "OUTPUT_ARCH") {
|
|
|
|
readOutputArch();
|
|
|
|
} else if (tok == "OUTPUT_FORMAT") {
|
|
|
|
readOutputFormat();
|
2021-06-13 12:41:11 -07:00
|
|
|
} else if (tok == "OVERWRITE_SECTIONS") {
|
|
|
|
readOverwriteSections();
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "PHDRS") {
|
|
|
|
readPhdrs();
|
2017-09-08 08:23:15 +00:00
|
|
|
} else if (tok == "REGION_ALIAS") {
|
|
|
|
readRegionAlias();
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "SEARCH_DIR") {
|
|
|
|
readSearchDir();
|
|
|
|
} else if (tok == "SECTIONS") {
|
|
|
|
readSections();
|
2018-08-06 21:29:41 +00:00
|
|
|
} else if (tok == "TARGET") {
|
|
|
|
readTarget();
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "VERSION") {
|
|
|
|
readVersion();
|
2024-07-17 10:45:59 -07:00
|
|
|
} else if (tok == "NOCROSSREFS") {
|
|
|
|
readNoCrossRefs(/*to=*/false);
|
|
|
|
} else if (tok == "NOCROSSREFS_TO") {
|
|
|
|
readNoCrossRefs(/*to=*/true);
|
2018-04-25 11:16:31 +00:00
|
|
|
} else if (SymbolAssignment *cmd = readAssignment(tok)) {
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->sectionCommands.push_back(cmd);
|
2017-04-05 05:07:39 +00:00
|
|
|
} else {
|
|
|
|
setError("unknown directive: " + tok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-28 12:38:10 -07:00
|
|
|
void ScriptParser::readDefsym() {
|
2024-11-07 09:06:01 -08:00
|
|
|
if (errCount(ctx))
|
2018-11-26 12:29:56 +00:00
|
|
|
return;
|
2025-02-01 15:49:08 -08:00
|
|
|
SaveAndRestore saved(lexState, State::Expr);
|
2024-07-28 12:38:10 -07:00
|
|
|
StringRef name = readName();
|
|
|
|
expect("=");
|
2017-11-04 02:03:58 +00:00
|
|
|
Expr e = readExpr();
|
|
|
|
if (!atEOF())
|
|
|
|
setError("EOF expected, but got " + next());
|
2024-01-22 09:09:46 -08:00
|
|
|
auto *cmd = make<SymbolAssignment>(
|
|
|
|
name, e, 0, getCurrentMB().getBufferIdentifier().str());
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->sectionCommands.push_back(cmd);
|
2017-11-04 02:03:58 +00:00
|
|
|
}
|
|
|
|
|
2024-07-17 10:45:59 -07:00
|
|
|
void ScriptParser::readNoCrossRefs(bool to) {
|
|
|
|
expect("(");
|
|
|
|
NoCrossRefCommand cmd{{}, to};
|
2024-07-26 17:25:23 -07:00
|
|
|
while (auto tok = till(")"))
|
|
|
|
cmd.outputSections.push_back(unquote(tok));
|
2024-07-17 10:45:59 -07:00
|
|
|
if (cmd.outputSections.size() < 2)
|
2024-11-06 22:19:31 -08:00
|
|
|
Warn(ctx) << getCurrentLocation()
|
|
|
|
<< ": ignored with fewer than 2 output sections";
|
2024-07-17 10:45:59 -07:00
|
|
|
else
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->noCrossRefs.push_back(std::move(cmd));
|
2024-07-17 10:45:59 -07:00
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
void ScriptParser::addFile(StringRef s) {
|
2024-07-28 11:43:27 -07:00
|
|
|
if (curBuf.isUnderSysroot && s.starts_with("/")) {
|
2017-04-05 05:07:39 +00:00
|
|
|
SmallString<128> pathData;
|
2024-09-21 11:06:06 -07:00
|
|
|
StringRef path = (ctx.arg.sysroot + s).toStringRef(pathData);
|
2021-06-25 12:52:39 -07:00
|
|
|
if (sys::fs::exists(path))
|
2024-11-16 22:34:12 -08:00
|
|
|
ctx.driver.addFile(ctx.saver.save(path), /*withLOption=*/false);
|
2021-06-25 12:52:39 -07:00
|
|
|
else
|
2024-09-21 11:06:06 -07:00
|
|
|
setError("cannot find " + s + " inside " + ctx.arg.sysroot);
|
2021-06-25 12:52:39 -07:00
|
|
|
return;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2023-06-05 14:36:19 -07:00
|
|
|
if (s.starts_with("/")) {
|
2020-04-08 21:45:21 -07:00
|
|
|
// Case 1: s is an absolute path. Just open it.
|
2022-10-01 15:12:50 -07:00
|
|
|
ctx.driver.addFile(s, /*withLOption=*/false);
|
2023-06-05 14:36:19 -07:00
|
|
|
} else if (s.starts_with("=")) {
|
2020-04-08 21:45:21 -07:00
|
|
|
// Case 2: relative to the sysroot.
|
2024-09-21 11:06:06 -07:00
|
|
|
if (ctx.arg.sysroot.empty())
|
2022-10-01 15:12:50 -07:00
|
|
|
ctx.driver.addFile(s.substr(1), /*withLOption=*/false);
|
2017-04-05 05:07:39 +00:00
|
|
|
else
|
2024-11-16 22:34:12 -08:00
|
|
|
ctx.driver.addFile(ctx.saver.save(ctx.arg.sysroot + "/" + s.substr(1)),
|
2022-10-01 15:12:50 -07:00
|
|
|
/*withLOption=*/false);
|
2023-06-05 14:36:19 -07:00
|
|
|
} else if (s.starts_with("-l")) {
|
2020-04-08 21:45:21 -07:00
|
|
|
// Case 3: search in the list of library paths.
|
2022-10-01 15:12:50 -07:00
|
|
|
ctx.driver.addLibrary(s.substr(2));
|
2017-04-05 05:07:39 +00:00
|
|
|
} else {
|
2020-04-08 21:45:21 -07:00
|
|
|
// Case 4: s is a relative path. Search in the directory of the script file.
|
|
|
|
std::string filename = std::string(getCurrentMB().getBufferIdentifier());
|
|
|
|
StringRef directory = sys::path::parent_path(filename);
|
|
|
|
if (!directory.empty()) {
|
|
|
|
SmallString<0> path(directory);
|
|
|
|
sys::path::append(path, s);
|
|
|
|
if (sys::fs::exists(path)) {
|
2022-10-01 15:12:50 -07:00
|
|
|
ctx.driver.addFile(path, /*withLOption=*/false);
|
2020-04-08 21:45:21 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Then search in the current working directory.
|
|
|
|
if (sys::fs::exists(s)) {
|
2022-10-01 15:12:50 -07:00
|
|
|
ctx.driver.addFile(s, /*withLOption=*/false);
|
2020-04-08 21:45:21 -07:00
|
|
|
} else {
|
|
|
|
// Finally, search in the list of library paths.
|
2024-10-06 11:27:24 -07:00
|
|
|
if (std::optional<std::string> path = findFromSearchPaths(ctx, s))
|
2024-11-16 22:34:12 -08:00
|
|
|
ctx.driver.addFile(ctx.saver.save(*path), /*withLOption=*/true);
|
2020-04-08 21:45:21 -07:00
|
|
|
else
|
|
|
|
setError("unable to find " + s);
|
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readAsNeeded() {
|
|
|
|
expect("(");
|
2024-09-21 11:06:06 -07:00
|
|
|
bool orig = ctx.arg.asNeeded;
|
|
|
|
ctx.arg.asNeeded = true;
|
2024-07-26 17:19:04 -07:00
|
|
|
while (auto tok = till(")"))
|
|
|
|
addFile(unquote(tok));
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.asNeeded = orig;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readEntry() {
|
|
|
|
// -e <symbol> takes predecence over ENTRY(<symbol>).
|
|
|
|
expect("(");
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readName();
|
2024-09-21 11:06:06 -07:00
|
|
|
if (ctx.arg.entry.empty())
|
|
|
|
ctx.arg.entry = name;
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readExtern() {
|
|
|
|
expect("(");
|
2024-07-26 17:19:04 -07:00
|
|
|
while (auto tok = till(")"))
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.undefined.push_back(unquote(tok));
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readGroup() {
|
2024-10-06 17:38:35 -07:00
|
|
|
SaveAndRestore saved(ctx.driver.isInGroup, true);
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
readInput();
|
2024-10-06 17:38:35 -07:00
|
|
|
if (!saved.get())
|
|
|
|
++ctx.driver.nextGroupId;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readInclude() {
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef name = readName();
|
2024-07-27 17:25:13 -07:00
|
|
|
if (!activeFilenames.insert(name).second) {
|
2017-09-06 18:14:08 +00:00
|
|
|
setError("there is a cycle in linker script INCLUDEs");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-10-06 11:27:24 -07:00
|
|
|
if (std::optional<std::string> path = searchScript(ctx, name)) {
|
|
|
|
if (std::optional<MemoryBufferRef> mb = readFile(ctx, *path)) {
|
2024-07-26 14:26:38 -07:00
|
|
|
buffers.push_back(curBuf);
|
2024-09-21 11:06:06 -07:00
|
|
|
curBuf = Buffer(ctx, *mb);
|
2024-07-26 14:26:38 -07:00
|
|
|
mbs.push_back(*mb);
|
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-07-27 16:27:05 -07:00
|
|
|
setError("cannot find linker script " + name);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
void ScriptParser::readInput() {
|
|
|
|
expect("(");
|
2024-07-26 17:19:04 -07:00
|
|
|
while (auto tok = till(")")) {
|
|
|
|
if (tok == "AS_NEEDED")
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
readAsNeeded();
|
|
|
|
else
|
2024-07-26 17:19:04 -07:00
|
|
|
addFile(unquote(tok));
|
Add --warn-backrefs to maintain compatibility with other linkers
I'm proposing a new command line flag, --warn-backrefs in this patch.
The flag and the feature proposed below don't exist in GNU linkers
nor the current lld.
--warn-backrefs is an option to detect reverse or cyclic dependencies
between static archives, and it can be used to keep your program
compatible with GNU linkers after you switch to lld. I'll explain the
feature and why you may find it useful below.
lld's symbol resolution semantics is more relaxed than traditional
Unix linkers. Therefore,
ld.lld foo.a bar.o
succeeds even if bar.o contains an undefined symbol that have to be
resolved by some object file in foo.a. Traditional Unix linkers
don't allow this kind of backward reference, as they visit each
file only once from left to right in the command line while
resolving all undefined symbol at the moment of visiting.
In the above case, since there's no undefined symbol when a linker
visits foo.a, no files are pulled out from foo.a, and because the
linker forgets about foo.a after visiting, it can't resolve
undefined symbols that could have been resolved otherwise.
That lld accepts more relaxed form means (besides it makes more
sense) that you can accidentally write a command line or a build
file that works only with lld, even if you have a plan to
distribute it to wider users who may be using GNU linkers. With
--check-library-dependency, you can detect a library order that
doesn't work with other Unix linkers.
The option is also useful to detect cyclic dependencies between
static archives. Again, lld accepts
ld.lld foo.a bar.a
even if foo.a and bar.a depend on each other. With --warn-backrefs
it is handled as an error.
Here is how the option works. We assign a group ID to each file. A
file with a smaller group ID can pull out object files from an
archive file with an equal or greater group ID. Otherwise, it is a
reverse dependency and an error.
A file outside --{start,end}-group gets a fresh ID when
instantiated. All files within the same --{start,end}-group get the
same group ID. E.g.
ld.lld A B --start-group C D --end-group E
A and B form group 0, C, D and their member object files form group
1, and E forms group 2. I think that you can see how this group
assignment rule simulates the traditional linker's semantics.
Differential Revision: https://reviews.llvm.org/D45195
llvm-svn: 329636
2018-04-09 23:05:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
void ScriptParser::readOutput() {
|
|
|
|
// -o <file> takes predecence over OUTPUT(<file>).
|
|
|
|
expect("(");
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readName();
|
2024-09-21 11:06:06 -07:00
|
|
|
if (ctx.arg.outputFile.empty())
|
|
|
|
ctx.arg.outputFile = name;
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readOutputArch() {
|
|
|
|
// OUTPUT_ARCH is ignored for now.
|
|
|
|
expect("(");
|
2024-07-27 16:52:47 -07:00
|
|
|
while (till(")"))
|
2024-07-26 14:26:38 -07:00
|
|
|
;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 21:45:50 +00:00
|
|
|
static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
|
|
|
|
return StringSwitch<std::pair<ELFKind, uint16_t>>(s)
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf32-i386", {ELF32LEKind, EM_386})
|
2022-05-12 13:26:15 +00:00
|
|
|
.Case("elf32-avr", {ELF32LEKind, EM_AVR})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf32-iamcu", {ELF32LEKind, EM_IAMCU})
|
|
|
|
.Case("elf32-littlearm", {ELF32LEKind, EM_ARM})
|
2023-02-20 13:31:45 +00:00
|
|
|
.Case("elf32-bigarm", {ELF32BEKind, EM_ARM})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf32-x86-64", {ELF32LEKind, EM_X86_64})
|
Recognize FreeBSD specific BFD names in OUTPUT_FORMAT
Summary:
After rLLD344952 ("Add OUTPUT_FORMAT linker script directive support"),
using BFD names such as `elf64-x86-64-freebsd` the `OUTPUT_FORMAT`
linker script command does not work anymore, resulting in errors like:
```
ld: error: /home/dim/src/clang800-import/stand/efi/loader/arch/amd64/ldscript.amd64:2: unknown output format name: elf64-x86-64-freebsd
>>> OUTPUT_FORMAT("elf64-x86-64-freebsd", "elf64-x86-64-freebsd", "elf64-x86-64-freebsd")
>>> ^
```
To fix this, recognize a `-freebsd` suffix in BFD names, and also set
`Configuration::OSABI` to `ELFOSABI_FREEBSD` for those cases.
Add and/or update several test cases to check for the correct results of
these new `OUTPUT_FORMAT` arguments.
Reviewers: ruiu, atanasyan, grimar, hokein, emaste, espindola
Reviewed By: ruiu
Subscribers: nemanjai, javed.absar, arichardson, krytarowski, kristof.beyls, kbarton, llvm-commits
Differential Revision: https://reviews.llvm.org/D57283
llvm-svn: 352606
2019-01-30 06:31:52 +00:00
|
|
|
.Case("elf64-aarch64", {ELF64LEKind, EM_AARCH64})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf64-littleaarch64", {ELF64LEKind, EM_AARCH64})
|
2021-02-08 08:55:28 -08:00
|
|
|
.Case("elf64-bigaarch64", {ELF64BEKind, EM_AARCH64})
|
2019-02-13 18:51:15 +00:00
|
|
|
.Case("elf32-powerpc", {ELF32BEKind, EM_PPC})
|
2021-01-02 12:18:05 -06:00
|
|
|
.Case("elf32-powerpcle", {ELF32LEKind, EM_PPC})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf64-powerpc", {ELF64BEKind, EM_PPC64})
|
|
|
|
.Case("elf64-powerpcle", {ELF64LEKind, EM_PPC64})
|
|
|
|
.Case("elf64-x86-64", {ELF64LEKind, EM_X86_64})
|
2019-02-13 18:51:15 +00:00
|
|
|
.Cases("elf32-tradbigmips", "elf32-bigmips", {ELF32BEKind, EM_MIPS})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Case("elf32-ntradbigmips", {ELF32BEKind, EM_MIPS})
|
|
|
|
.Case("elf32-tradlittlemips", {ELF32LEKind, EM_MIPS})
|
|
|
|
.Case("elf32-ntradlittlemips", {ELF32LEKind, EM_MIPS})
|
|
|
|
.Case("elf64-tradbigmips", {ELF64BEKind, EM_MIPS})
|
|
|
|
.Case("elf64-tradlittlemips", {ELF64LEKind, EM_MIPS})
|
2019-06-10 08:09:55 +00:00
|
|
|
.Case("elf32-littleriscv", {ELF32LEKind, EM_RISCV})
|
|
|
|
.Case("elf64-littleriscv", {ELF64LEKind, EM_RISCV})
|
2020-04-17 07:58:15 -07:00
|
|
|
.Case("elf64-sparc", {ELF64BEKind, EM_SPARCV9})
|
2020-12-14 09:38:12 -08:00
|
|
|
.Case("elf32-msp430", {ELF32LEKind, EM_MSP430})
|
2023-07-25 17:03:28 +08:00
|
|
|
.Case("elf32-loongarch", {ELF32LEKind, EM_LOONGARCH})
|
|
|
|
.Case("elf64-loongarch", {ELF64LEKind, EM_LOONGARCH})
|
2024-02-13 11:29:21 +01:00
|
|
|
.Case("elf64-s390", {ELF64BEKind, EM_S390})
|
2024-07-16 15:01:27 -05:00
|
|
|
.Cases("elf32-hexagon", "elf32-littlehexagon", {ELF32LEKind, EM_HEXAGON})
|
2019-01-28 19:11:52 +00:00
|
|
|
.Default({ELFNoneKind, EM_NONE});
|
Add OUTPUT_FORMAT linker script directive support.
This patch adds a support for OUTPUT_FORMAT linker script directive.
Since I'm not 100% confident with BFD names you can use in the directive
for all architectures, I added only a few in this patch. We can add
other names for other archtiectures later.
We still do not support triple-style OUTPUT_FORMAT directive, namely,
OUTPUT_FORMAT(bfdname, big, little). If you pass -EL (little endian)
or -EB (big endian) to the linker, GNU linkers pick up big or little
as a BFD name, correspondingly, so that you can use a single linker
script for bi-endian processor. I'm not sure if we really need to
support that, so I'll leave it alone for now.
Note that -m takes precedence over OUTPUT_FORAMT, but we always parse
a BFD name given to OUTPUT_FORMAT for error checking. You cannot write
an invalid name in the OUTPUT_FORMAT directive.
Differential Revision: https://reviews.llvm.org/D53495
llvm-svn: 344952
2018-10-22 20:50:01 +00:00
|
|
|
}
|
|
|
|
|
2021-02-08 10:34:57 -08:00
|
|
|
// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(default, big, little). Choose
|
|
|
|
// big if -EB is specified, little if -EL is specified, or default if neither is
|
|
|
|
// specified.
|
2017-04-05 05:07:39 +00:00
|
|
|
void ScriptParser::readOutputFormat() {
|
|
|
|
expect("(");
|
Add OUTPUT_FORMAT linker script directive support.
This patch adds a support for OUTPUT_FORMAT linker script directive.
Since I'm not 100% confident with BFD names you can use in the directive
for all architectures, I added only a few in this patch. We can add
other names for other archtiectures later.
We still do not support triple-style OUTPUT_FORMAT directive, namely,
OUTPUT_FORMAT(bfdname, big, little). If you pass -EL (little endian)
or -EB (big endian) to the linker, GNU linkers pick up big or little
as a BFD name, correspondingly, so that you can use a single linker
script for bi-endian processor. I'm not sure if we really need to
support that, so I'll leave it alone for now.
Note that -m takes precedence over OUTPUT_FORAMT, but we always parse
a BFD name given to OUTPUT_FORMAT for error checking. You cannot write
an invalid name in the OUTPUT_FORMAT directive.
Differential Revision: https://reviews.llvm.org/D53495
llvm-svn: 344952
2018-10-22 20:50:01 +00:00
|
|
|
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef s = readName();
|
2021-02-08 10:34:57 -08:00
|
|
|
if (!consume(")")) {
|
|
|
|
expect(",");
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef tmp = readName();
|
2024-09-21 11:06:06 -07:00
|
|
|
if (ctx.arg.optEB)
|
2024-07-16 10:28:09 -07:00
|
|
|
s = tmp;
|
2021-02-08 10:34:57 -08:00
|
|
|
expect(",");
|
2024-07-27 16:27:05 -07:00
|
|
|
tmp = readName();
|
2024-09-21 11:06:06 -07:00
|
|
|
if (ctx.arg.optEL)
|
2024-07-16 10:28:09 -07:00
|
|
|
s = tmp;
|
2021-02-08 10:34:57 -08:00
|
|
|
consume(")");
|
|
|
|
}
|
2024-07-16 10:28:09 -07:00
|
|
|
// If more than one OUTPUT_FORMAT is specified, only the first is checked.
|
2024-09-21 11:06:06 -07:00
|
|
|
if (!ctx.arg.bfdname.empty())
|
2024-07-16 10:28:09 -07:00
|
|
|
return;
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.bfdname = s;
|
2024-07-16 10:28:09 -07:00
|
|
|
|
|
|
|
if (s == "binary") {
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.oFormatBinary = true;
|
2024-07-16 10:28:09 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Recognize FreeBSD specific BFD names in OUTPUT_FORMAT
Summary:
After rLLD344952 ("Add OUTPUT_FORMAT linker script directive support"),
using BFD names such as `elf64-x86-64-freebsd` the `OUTPUT_FORMAT`
linker script command does not work anymore, resulting in errors like:
```
ld: error: /home/dim/src/clang800-import/stand/efi/loader/arch/amd64/ldscript.amd64:2: unknown output format name: elf64-x86-64-freebsd
>>> OUTPUT_FORMAT("elf64-x86-64-freebsd", "elf64-x86-64-freebsd", "elf64-x86-64-freebsd")
>>> ^
```
To fix this, recognize a `-freebsd` suffix in BFD names, and also set
`Configuration::OSABI` to `ELFOSABI_FREEBSD` for those cases.
Add and/or update several test cases to check for the correct results of
these new `OUTPUT_FORMAT` arguments.
Reviewers: ruiu, atanasyan, grimar, hokein, emaste, espindola
Reviewed By: ruiu
Subscribers: nemanjai, javed.absar, arichardson, krytarowski, kristof.beyls, kbarton, llvm-commits
Differential Revision: https://reviews.llvm.org/D57283
llvm-svn: 352606
2019-01-30 06:31:52 +00:00
|
|
|
if (s.consume_back("-freebsd"))
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.osabi = ELFOSABI_FREEBSD;
|
2019-01-28 19:11:52 +00:00
|
|
|
|
2024-09-21 11:06:06 -07:00
|
|
|
std::tie(ctx.arg.ekind, ctx.arg.emachine) = parseBfdName(s);
|
|
|
|
if (ctx.arg.emachine == EM_NONE)
|
|
|
|
setError("unknown output format name: " + ctx.arg.bfdname);
|
2019-01-28 19:11:52 +00:00
|
|
|
if (s == "elf32-ntradlittlemips" || s == "elf32-ntradbigmips")
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.mipsN32Abi = true;
|
|
|
|
if (ctx.arg.emachine == EM_MSP430)
|
|
|
|
ctx.arg.osabi = ELFOSABI_STANDALONE;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readPhdrs() {
|
|
|
|
expect("{");
|
2024-07-26 17:13:37 -07:00
|
|
|
while (auto tok = till("}")) {
|
2017-10-08 03:45:49 +00:00
|
|
|
PhdrsCommand cmd;
|
2024-07-26 17:13:37 -07:00
|
|
|
cmd.name = tok;
|
2017-10-08 03:45:49 +00:00
|
|
|
cmd.type = readPhdrType();
|
2017-04-05 05:40:21 +00:00
|
|
|
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx) && !consume(";")) {
|
2017-04-05 05:40:21 +00:00
|
|
|
if (consume("FILEHDR"))
|
2017-10-08 03:45:49 +00:00
|
|
|
cmd.hasFilehdr = true;
|
2017-04-05 05:40:21 +00:00
|
|
|
else if (consume("PHDRS"))
|
2017-10-08 03:45:49 +00:00
|
|
|
cmd.hasPhdrs = true;
|
2017-04-05 05:40:21 +00:00
|
|
|
else if (consume("AT"))
|
2017-10-08 03:45:49 +00:00
|
|
|
cmd.lmaExpr = readParenExpr();
|
2017-04-05 05:40:21 +00:00
|
|
|
else if (consume("FLAGS"))
|
2017-10-08 03:45:49 +00:00
|
|
|
cmd.flags = readParenExpr()().getValue();
|
2017-04-05 05:40:21 +00:00
|
|
|
else
|
|
|
|
setError("unexpected header attribute: " + next());
|
|
|
|
}
|
2017-10-08 03:45:49 +00:00
|
|
|
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->phdrsCommands.push_back(cmd);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 08:23:15 +00:00
|
|
|
void ScriptParser::readRegionAlias() {
|
|
|
|
expect("(");
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef alias = readName();
|
2017-09-08 08:23:15 +00:00
|
|
|
expect(",");
|
2024-07-27 16:29:43 -07:00
|
|
|
StringRef name = readName();
|
2017-09-08 08:23:15 +00:00
|
|
|
expect(")");
|
|
|
|
|
2024-08-21 21:23:28 -07:00
|
|
|
if (ctx.script->memoryRegions.count(alias))
|
2017-09-08 08:23:15 +00:00
|
|
|
setError("redefinition of memory region '" + alias + "'");
|
2024-08-21 21:23:28 -07:00
|
|
|
if (!ctx.script->memoryRegions.count(name))
|
2017-09-08 08:23:15 +00:00
|
|
|
setError("memory region '" + name + "' is not defined");
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->memoryRegions.insert({alias, ctx.script->memoryRegions[name]});
|
2017-09-08 08:23:15 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
void ScriptParser::readSearchDir() {
|
|
|
|
expect("(");
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef name = readName();
|
2024-09-21 11:06:06 -07:00
|
|
|
if (!ctx.arg.nostdlib)
|
|
|
|
ctx.arg.searchPaths.push_back(name);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
|
|
|
}
|
|
|
|
|
2018-06-27 08:08:12 +00:00
|
|
|
// This reads an overlay description. Overlays are used to describe output
|
|
|
|
// sections that use the same virtual memory range and normally would trigger
|
|
|
|
// linker's sections sanity check failures.
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
|
2024-01-08 16:12:49 -08:00
|
|
|
Expr addrExpr;
|
2025-03-31 10:44:40 -07:00
|
|
|
if (!consume(":")) {
|
2024-01-08 16:12:49 -08:00
|
|
|
addrExpr = readExpr();
|
|
|
|
expect(":");
|
|
|
|
}
|
2025-04-02 09:25:18 -07:00
|
|
|
bool noCrossRefs = consume("NOCROSSREFS");
|
2025-03-31 10:44:40 -07:00
|
|
|
Expr lmaExpr = consume("AT") ? readParenExpr() : Expr{};
|
2018-06-27 08:08:12 +00:00
|
|
|
expect("{");
|
|
|
|
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionCommand *, 0> v;
|
2018-06-27 08:08:12 +00:00
|
|
|
OutputSection *prev = nullptr;
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx) && !consume("}")) {
|
2018-06-27 08:08:12 +00:00
|
|
|
// VA is the same for all sections. The LMAs are consecutive in memory
|
2025-03-31 10:44:40 -07:00
|
|
|
// starting from the base load address.
|
2022-03-08 11:23:41 -08:00
|
|
|
OutputDesc *osd = readOverlaySectionDescription();
|
|
|
|
osd->osec.addrExpr = addrExpr;
|
2024-01-08 16:12:49 -08:00
|
|
|
if (prev) {
|
2022-03-08 11:23:41 -08:00
|
|
|
osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; };
|
2024-01-08 16:12:49 -08:00
|
|
|
} else {
|
2022-03-08 11:23:41 -08:00
|
|
|
osd->osec.lmaExpr = lmaExpr;
|
2025-03-31 10:44:40 -07:00
|
|
|
// Use first section address for subsequent sections. Ensure the first
|
|
|
|
// section, even if empty, is not discarded.
|
2024-01-08 16:12:49 -08:00
|
|
|
osd->osec.usedInExpression = true;
|
|
|
|
addrExpr = [=]() -> ExprValue { return {&osd->osec, false, 0, ""}; };
|
|
|
|
}
|
2022-03-08 11:23:41 -08:00
|
|
|
v.push_back(osd);
|
|
|
|
prev = &osd->osec;
|
2018-06-27 08:08:12 +00:00
|
|
|
}
|
2025-03-31 10:44:40 -07:00
|
|
|
if (!v.empty())
|
|
|
|
static_cast<OutputDesc *>(v.front())->osec.firstInOverlay = true;
|
|
|
|
if (consume(">")) {
|
|
|
|
StringRef regionName = readName();
|
|
|
|
for (SectionCommand *od : v)
|
|
|
|
static_cast<OutputDesc *>(od)->osec.memoryRegionName =
|
|
|
|
std::string(regionName);
|
|
|
|
}
|
2025-04-02 09:25:18 -07:00
|
|
|
if (noCrossRefs) {
|
|
|
|
NoCrossRefCommand cmd;
|
|
|
|
for (SectionCommand *od : v)
|
|
|
|
cmd.outputSections.push_back(static_cast<OutputDesc *>(od)->osec.name);
|
|
|
|
ctx.script->noCrossRefs.push_back(std::move(cmd));
|
|
|
|
}
|
2018-06-27 08:08:12 +00:00
|
|
|
|
|
|
|
// According to the specification, at the end of the overlay, the location
|
|
|
|
// counter should be equal to the overlay base address plus size of the
|
|
|
|
// largest section seen in the overlay.
|
|
|
|
// Here we want to create the Dot assignment command to achieve that.
|
|
|
|
Expr moveDot = [=] {
|
|
|
|
uint64_t max = 0;
|
2021-11-25 20:24:23 -08:00
|
|
|
for (SectionCommand *cmd : v)
|
2022-03-08 11:23:41 -08:00
|
|
|
max = std::max(max, cast<OutputDesc>(cmd)->osec.size);
|
2018-06-27 08:08:12 +00:00
|
|
|
return addrExpr().getValue() + max;
|
|
|
|
};
|
2023-09-09 14:46:51 -07:00
|
|
|
v.push_back(make<SymbolAssignment>(".", moveDot, 0, getCurrentLocation()));
|
2018-06-27 08:08:12 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2024-08-05 13:06:45 -07:00
|
|
|
SectionClassDesc *ScriptParser::readSectionClassDescription() {
|
|
|
|
StringRef name = readSectionClassName();
|
|
|
|
SectionClassDesc *desc = make<SectionClassDesc>(name);
|
2024-08-21 21:23:28 -07:00
|
|
|
if (!ctx.script->sectionClasses.insert({CachedHashStringRef(name), desc})
|
|
|
|
.second)
|
2024-08-05 13:06:45 -07:00
|
|
|
setError("section class '" + name + "' already defined");
|
|
|
|
expect("{");
|
|
|
|
while (auto tok = till("}")) {
|
|
|
|
if (tok == "(" || tok == ")") {
|
|
|
|
setError("expected filename pattern");
|
|
|
|
} else if (peek() == "(") {
|
|
|
|
InputSectionDescription *isd = readInputSectionDescription(tok);
|
|
|
|
if (!isd->classRef.empty())
|
|
|
|
setError("section class '" + name + "' references class '" +
|
|
|
|
isd->classRef + "'");
|
|
|
|
desc->sc.commands.push_back(isd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ScriptParser::readSectionClassName() {
|
|
|
|
expect("(");
|
|
|
|
StringRef name = unquote(next());
|
|
|
|
expect(")");
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2021-06-13 12:41:11 -07:00
|
|
|
void ScriptParser::readOverwriteSections() {
|
|
|
|
expect("{");
|
2024-07-26 17:13:37 -07:00
|
|
|
while (auto tok = till("}"))
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->overwriteSections.push_back(readOutputSectionDescription(tok));
|
2021-06-13 12:41:11 -07:00
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
void ScriptParser::readSections() {
|
|
|
|
expect("{");
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionCommand *, 0> v;
|
2024-07-26 17:13:37 -07:00
|
|
|
while (auto tok = till("}")) {
|
2018-06-27 08:08:12 +00:00
|
|
|
if (tok == "OVERLAY") {
|
2021-11-25 20:24:23 -08:00
|
|
|
for (SectionCommand *cmd : readOverlay())
|
2018-06-27 08:08:12 +00:00
|
|
|
v.push_back(cmd);
|
|
|
|
continue;
|
2024-08-05 13:06:45 -07:00
|
|
|
}
|
|
|
|
if (tok == "CLASS") {
|
|
|
|
v.push_back(readSectionClassDescription());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (tok == "INCLUDE") {
|
2018-10-12 17:07:32 +00:00
|
|
|
readInclude();
|
|
|
|
continue;
|
2018-06-27 08:08:12 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 20:24:23 -08:00
|
|
|
if (SectionCommand *cmd = readAssignment(tok))
|
2018-04-25 11:16:31 +00:00
|
|
|
v.push_back(cmd);
|
|
|
|
else
|
2023-07-05 15:08:53 -07:00
|
|
|
v.push_back(readOutputSectionDescription(tok));
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2022-05-04 01:10:45 -07:00
|
|
|
|
|
|
|
// If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN,
|
|
|
|
// the relro fields should be cleared.
|
2024-08-21 21:23:28 -07:00
|
|
|
if (!ctx.script->seenRelroEnd)
|
2022-05-04 01:10:45 -07:00
|
|
|
for (SectionCommand *cmd : v)
|
|
|
|
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
|
|
|
osd->osec.relro = false;
|
|
|
|
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->sectionCommands.insert(ctx.script->sectionCommands.end(),
|
|
|
|
v.begin(), v.end());
|
2018-03-08 14:54:38 +00:00
|
|
|
|
2020-02-10 15:58:29 -08:00
|
|
|
if (atEOF() || !consume("INSERT")) {
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->hasSectionsCommand = true;
|
2018-03-08 14:54:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-10 15:58:29 -08:00
|
|
|
bool isAfter = false;
|
|
|
|
if (consume("AFTER"))
|
|
|
|
isAfter = true;
|
|
|
|
else if (!consume("BEFORE"))
|
|
|
|
setError("expected AFTER/BEFORE, but got '" + next() + "'");
|
2024-07-27 17:34:37 -07:00
|
|
|
StringRef where = readName();
|
2021-12-26 13:53:47 -08:00
|
|
|
SmallVector<StringRef, 0> names;
|
2021-11-25 20:24:23 -08:00
|
|
|
for (SectionCommand *cmd : v)
|
2022-03-08 11:23:41 -08:00
|
|
|
if (auto *os = dyn_cast<OutputDesc>(cmd))
|
|
|
|
names.push_back(os->osec.name);
|
2021-06-30 11:35:50 -07:00
|
|
|
if (!names.empty())
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->insertCommands.push_back({std::move(names), isAfter, where});
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2018-08-06 21:29:41 +00:00
|
|
|
void ScriptParser::readTarget() {
|
|
|
|
// TARGET(foo) is an alias for "--format foo". Unlike GNU linkers,
|
|
|
|
// we accept only a limited set of BFD names (i.e. "elf" or "binary")
|
|
|
|
// for --format. We recognize only /^elf/ and "binary" in the linker
|
|
|
|
// script as well.
|
|
|
|
expect("(");
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef tok = readName();
|
2018-08-06 21:29:41 +00:00
|
|
|
expect(")");
|
|
|
|
|
2023-06-05 14:36:19 -07:00
|
|
|
if (tok.starts_with("elf"))
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.formatBinary = false;
|
2018-08-06 21:29:41 +00:00
|
|
|
else if (tok == "binary")
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.formatBinary = true;
|
2018-08-06 21:29:41 +00:00
|
|
|
else
|
|
|
|
setError("unknown target: " + tok);
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
static int precedence(StringRef op) {
|
|
|
|
return StringSwitch<int>(op)
|
2023-07-15 14:10:40 -07:00
|
|
|
.Cases("*", "/", "%", 11)
|
|
|
|
.Cases("+", "-", 10)
|
|
|
|
.Cases("<<", ">>", 9)
|
|
|
|
.Cases("<", "<=", ">", ">=", 8)
|
|
|
|
.Cases("==", "!=", 7)
|
|
|
|
.Case("&", 6)
|
|
|
|
.Case("^", 5)
|
2022-06-25 13:47:32 -07:00
|
|
|
.Case("|", 4)
|
|
|
|
.Case("&&", 3)
|
|
|
|
.Case("||", 2)
|
2022-06-25 13:48:52 -07:00
|
|
|
.Case("?", 1)
|
2017-04-05 05:07:39 +00:00
|
|
|
.Default(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringMatcher ScriptParser::readFilePatterns() {
|
[lld/ELF] PR44498: Support input filename in double quote
Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.
Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline@2.
To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.
Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap
Reviewed By: MaskRay
Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72517
2020-01-10 16:56:07 +00:00
|
|
|
StringMatcher Matcher;
|
2024-07-26 17:19:04 -07:00
|
|
|
while (auto tok = till(")"))
|
|
|
|
Matcher.addPattern(SingleStringMatcher(tok));
|
[lld/ELF] PR44498: Support input filename in double quote
Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.
Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline@2.
To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.
Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap
Reviewed By: MaskRay
Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72517
2020-01-10 16:56:07 +00:00
|
|
|
return Matcher;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 08:46:53 -08:00
|
|
|
SortSectionPolicy ScriptParser::peekSortKind() {
|
|
|
|
return StringSwitch<SortSectionPolicy>(peek())
|
2023-03-06 09:35:39 -05:00
|
|
|
.Case("REVERSE", SortSectionPolicy::Reverse)
|
2020-11-12 08:46:53 -08:00
|
|
|
.Cases("SORT", "SORT_BY_NAME", SortSectionPolicy::Name)
|
|
|
|
.Case("SORT_BY_ALIGNMENT", SortSectionPolicy::Alignment)
|
|
|
|
.Case("SORT_BY_INIT_PRIORITY", SortSectionPolicy::Priority)
|
|
|
|
.Case("SORT_NONE", SortSectionPolicy::None)
|
|
|
|
.Default(SortSectionPolicy::Default);
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
SortSectionPolicy ScriptParser::readSortKind() {
|
2020-11-12 08:46:53 -08:00
|
|
|
SortSectionPolicy ret = peekSortKind();
|
|
|
|
if (ret != SortSectionPolicy::Default)
|
|
|
|
skip();
|
|
|
|
return ret;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 19:20:54 +00:00
|
|
|
// Reads SECTIONS command contents in the following form:
|
|
|
|
//
|
|
|
|
// <contents> ::= <elem>*
|
|
|
|
// <elem> ::= <exclude>? <glob-pattern>
|
|
|
|
// <exclude> ::= "EXCLUDE_FILE" "(" <glob-pattern>+ ")"
|
|
|
|
//
|
|
|
|
// For example,
|
|
|
|
//
|
|
|
|
// *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz)
|
|
|
|
//
|
|
|
|
// is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o".
|
|
|
|
// The semantics of that is section .foo in any file, section .bar in
|
|
|
|
// any file but a.o, and section .baz in any file but b.o.
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionPattern, 0> ScriptParser::readInputSectionsList() {
|
|
|
|
SmallVector<SectionPattern, 0> ret;
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx) && peek() != ")") {
|
2017-04-05 05:07:39 +00:00
|
|
|
StringMatcher excludeFilePat;
|
|
|
|
if (consume("EXCLUDE_FILE")) {
|
|
|
|
expect("(");
|
|
|
|
excludeFilePat = readFilePatterns();
|
|
|
|
}
|
|
|
|
|
[lld/ELF] PR44498: Support input filename in double quote
Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.
Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline@2.
To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.
Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap
Reviewed By: MaskRay
Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72517
2020-01-10 16:56:07 +00:00
|
|
|
StringMatcher SectionMatcher;
|
2020-11-12 08:46:53 -08:00
|
|
|
// Break if the next token is ), EXCLUDE_FILE, or SORT*.
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx) && peekSortKind() == SortSectionPolicy::Default) {
|
2024-03-06 17:19:59 -08:00
|
|
|
StringRef s = peek();
|
|
|
|
if (s == ")" || s == "EXCLUDE_FILE")
|
|
|
|
break;
|
|
|
|
// Detect common mistakes when certain non-wildcard meta characters are
|
|
|
|
// used without a closing ')'.
|
|
|
|
if (!s.empty() && strchr("(){}", s[0])) {
|
|
|
|
skip();
|
|
|
|
setError("section pattern is expected");
|
|
|
|
break;
|
|
|
|
}
|
2024-07-27 16:27:05 -07:00
|
|
|
SectionMatcher.addPattern(readName());
|
2024-03-06 17:19:59 -08:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
[lld/ELF] PR44498: Support input filename in double quote
Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.
Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline@2.
To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.
Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap
Reviewed By: MaskRay
Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72517
2020-01-10 16:56:07 +00:00
|
|
|
if (!SectionMatcher.empty())
|
|
|
|
ret.push_back({std::move(excludeFilePat), std::move(SectionMatcher)});
|
2020-11-12 08:46:53 -08:00
|
|
|
else if (excludeFilePat.empty())
|
|
|
|
break;
|
2017-04-05 05:07:39 +00:00
|
|
|
else
|
|
|
|
setError("section pattern is expected");
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads contents of "SECTIONS" directive. That directive contains a
|
|
|
|
// list of glob patterns for input sections. The grammar is as follows.
|
|
|
|
//
|
|
|
|
// <patterns> ::= <section-list>
|
|
|
|
// | <sort> "(" <section-list> ")"
|
|
|
|
// | <sort> "(" <sort> "(" <section-list> ")" ")"
|
|
|
|
//
|
|
|
|
// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
|
|
|
|
// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
|
|
|
|
//
|
|
|
|
// <section-list> is parsed by readInputSectionsList().
|
|
|
|
InputSectionDescription *
|
2020-01-15 09:38:00 +00:00
|
|
|
ScriptParser::readInputSectionRules(StringRef filePattern, uint64_t withFlags,
|
|
|
|
uint64_t withoutFlags) {
|
|
|
|
auto *cmd =
|
|
|
|
make<InputSectionDescription>(filePattern, withFlags, withoutFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect("(");
|
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
while (peek() != ")" && !atEOF()) {
|
2017-04-05 05:07:39 +00:00
|
|
|
SortSectionPolicy outer = readSortKind();
|
|
|
|
SortSectionPolicy inner = SortSectionPolicy::Default;
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SectionPattern, 0> v;
|
2017-04-05 05:07:39 +00:00
|
|
|
if (outer != SortSectionPolicy::Default) {
|
|
|
|
expect("(");
|
|
|
|
inner = readSortKind();
|
|
|
|
if (inner != SortSectionPolicy::Default) {
|
|
|
|
expect("(");
|
|
|
|
v = readInputSectionsList();
|
|
|
|
expect(")");
|
|
|
|
} else {
|
|
|
|
v = readInputSectionsList();
|
|
|
|
}
|
|
|
|
expect(")");
|
|
|
|
} else {
|
|
|
|
v = readInputSectionsList();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (SectionPattern &pat : v) {
|
|
|
|
pat.sortInner = inner;
|
|
|
|
pat.sortOuter = outer;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::move(v.begin(), v.end(), std::back_inserter(cmd->sectionPatterns));
|
|
|
|
}
|
2024-07-26 14:26:38 -07:00
|
|
|
expect(")");
|
2017-04-05 05:07:39 +00:00
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
InputSectionDescription *
|
|
|
|
ScriptParser::readInputSectionDescription(StringRef tok) {
|
|
|
|
// Input section wildcard can be surrounded by KEEP.
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
|
2020-01-15 09:38:00 +00:00
|
|
|
uint64_t withFlags = 0;
|
|
|
|
uint64_t withoutFlags = 0;
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == "KEEP") {
|
|
|
|
expect("(");
|
2020-01-15 09:38:00 +00:00
|
|
|
if (consume("INPUT_SECTION_FLAGS"))
|
|
|
|
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
|
2024-08-05 13:06:45 -07:00
|
|
|
|
|
|
|
tok = next();
|
|
|
|
InputSectionDescription *cmd;
|
|
|
|
if (tok == "CLASS")
|
|
|
|
cmd = make<InputSectionDescription>(StringRef{}, withFlags, withoutFlags,
|
|
|
|
readSectionClassName());
|
|
|
|
else
|
|
|
|
cmd = readInputSectionRules(tok, withFlags, withoutFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->keptSections.push_back(cmd);
|
2017-04-05 05:07:39 +00:00
|
|
|
return cmd;
|
|
|
|
}
|
2020-01-15 09:38:00 +00:00
|
|
|
if (tok == "INPUT_SECTION_FLAGS") {
|
|
|
|
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
|
|
|
|
tok = next();
|
|
|
|
}
|
2024-08-05 13:06:45 -07:00
|
|
|
if (tok == "CLASS")
|
|
|
|
return make<InputSectionDescription>(StringRef{}, withFlags, withoutFlags,
|
|
|
|
readSectionClassName());
|
2020-01-15 09:38:00 +00:00
|
|
|
return readInputSectionRules(tok, withFlags, withoutFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScriptParser::readSort() {
|
|
|
|
expect("(");
|
|
|
|
expect("CONSTRUCTORS");
|
|
|
|
expect(")");
|
|
|
|
}
|
|
|
|
|
2018-04-25 11:16:31 +00:00
|
|
|
Expr ScriptParser::readAssert() {
|
2017-04-05 05:07:39 +00:00
|
|
|
expect("(");
|
|
|
|
Expr e = readExpr();
|
|
|
|
expect(",");
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef msg = readName();
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
2017-04-05 05:40:21 +00:00
|
|
|
|
2024-11-06 22:33:51 -08:00
|
|
|
return [=, s = ctx.script, &ctx = ctx]() -> ExprValue {
|
2017-04-05 05:07:39 +00:00
|
|
|
if (!e().getValue())
|
2024-11-06 22:33:51 -08:00
|
|
|
Err(ctx) << msg;
|
2024-09-21 11:51:02 -07:00
|
|
|
return s->getDot();
|
2017-04-05 05:07:39 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-02-17 12:10:58 -08:00
|
|
|
#define ECase(X) \
|
|
|
|
{ #X, X }
|
|
|
|
constexpr std::pair<const char *, unsigned> typeMap[] = {
|
|
|
|
ECase(SHT_PROGBITS), ECase(SHT_NOTE), ECase(SHT_NOBITS),
|
|
|
|
ECase(SHT_INIT_ARRAY), ECase(SHT_FINI_ARRAY), ECase(SHT_PREINIT_ARRAY),
|
|
|
|
};
|
|
|
|
#undef ECase
|
|
|
|
|
2018-08-28 08:39:21 +00:00
|
|
|
// Tries to read the special directive for an output section definition which
|
2022-02-17 12:10:58 -08:00
|
|
|
// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)", "(OVERLAY)", and
|
|
|
|
// "(TYPE=<value>)".
|
2024-07-20 16:35:38 -07:00
|
|
|
bool ScriptParser::readSectionDirective(OutputSection *cmd, StringRef tok) {
|
|
|
|
if (tok != "NOLOAD" && tok != "COPY" && tok != "INFO" && tok != "OVERLAY" &&
|
|
|
|
tok != "TYPE")
|
2018-08-28 08:39:21 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (consume("NOLOAD")) {
|
2020-03-28 09:54:06 -07:00
|
|
|
cmd->type = SHT_NOBITS;
|
2022-02-17 12:10:58 -08:00
|
|
|
cmd->typeIsSet = true;
|
|
|
|
} else if (consume("TYPE")) {
|
|
|
|
expect("=");
|
|
|
|
StringRef value = peek();
|
|
|
|
auto it = llvm::find_if(typeMap, [=](auto e) { return e.first == value; });
|
|
|
|
if (it != std::end(typeMap)) {
|
|
|
|
// The value is a recognized literal SHT_*.
|
|
|
|
cmd->type = it->second;
|
|
|
|
skip();
|
2023-06-05 14:36:19 -07:00
|
|
|
} else if (value.starts_with("SHT_")) {
|
2022-02-17 12:10:58 -08:00
|
|
|
setError("unknown section type " + value);
|
|
|
|
} else {
|
|
|
|
// Otherwise, read an expression.
|
|
|
|
cmd->type = readExpr()().getValue();
|
|
|
|
}
|
|
|
|
cmd->typeIsSet = true;
|
2018-08-28 08:39:21 +00:00
|
|
|
} else {
|
|
|
|
skip(); // This is "COPY", "INFO" or "OVERLAY".
|
|
|
|
cmd->nonAlloc = true;
|
|
|
|
}
|
|
|
|
expect(")");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:42:58 +00:00
|
|
|
// Reads an expression and/or the special directive for an output
|
|
|
|
// section definition. Directive is one of following: "(NOLOAD)",
|
|
|
|
// "(COPY)", "(INFO)" or "(OVERLAY)".
|
2017-06-08 19:47:16 +00:00
|
|
|
//
|
|
|
|
// An output section name can be followed by an address expression
|
2018-02-16 10:42:58 +00:00
|
|
|
// and/or directive. This grammar is not LL(1) because "(" can be
|
2018-02-16 10:46:50 +00:00
|
|
|
// interpreted as either the beginning of some expression or beginning
|
2018-02-16 10:42:58 +00:00
|
|
|
// of directive.
|
2017-06-08 19:47:16 +00:00
|
|
|
//
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
|
2017-07-27 19:22:43 +00:00
|
|
|
void ScriptParser::readSectionAddressType(OutputSection *cmd) {
|
2024-07-20 16:35:38 -07:00
|
|
|
if (consume("(")) {
|
2025-02-01 15:49:08 -08:00
|
|
|
// Temporarily set lexState to support TYPE=<value> without spaces.
|
|
|
|
SaveAndRestore saved(lexState, State::Expr);
|
2024-07-20 16:35:38 -07:00
|
|
|
if (readSectionDirective(cmd, peek()))
|
2024-07-20 14:13:02 -07:00
|
|
|
return;
|
2024-07-20 16:35:38 -07:00
|
|
|
cmd->addrExpr = readExpr();
|
|
|
|
expect(")");
|
|
|
|
} else {
|
|
|
|
cmd->addrExpr = readExpr();
|
2024-07-20 14:13:02 -07:00
|
|
|
}
|
|
|
|
|
2024-07-20 16:35:38 -07:00
|
|
|
if (consume("(")) {
|
2025-02-01 15:49:08 -08:00
|
|
|
SaveAndRestore saved(lexState, State::Expr);
|
2024-07-20 16:35:38 -07:00
|
|
|
StringRef tok = peek();
|
|
|
|
if (!readSectionDirective(cmd, tok))
|
|
|
|
setError("unknown section directive: " + tok);
|
2024-07-20 14:13:02 -07:00
|
|
|
}
|
2017-06-08 19:47:16 +00:00
|
|
|
}
|
|
|
|
|
2024-11-14 22:17:10 -08:00
|
|
|
static Expr checkAlignment(Ctx &ctx, Expr e, std::string &loc) {
|
|
|
|
return [=, &ctx] {
|
2017-10-25 14:50:51 +00:00
|
|
|
uint64_t alignment = std::max((uint64_t)1, e().getValue());
|
|
|
|
if (!isPowerOf2_64(alignment)) {
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << loc << ": alignment must be power of 2";
|
2017-10-25 14:50:51 +00:00
|
|
|
return (uint64_t)1; // Return a dummy value.
|
|
|
|
}
|
|
|
|
return alignment;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-03-08 11:23:41 -08:00
|
|
|
OutputDesc *ScriptParser::readOverlaySectionDescription() {
|
2024-07-27 16:33:18 -07:00
|
|
|
OutputDesc *osd =
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->createOutputSection(readName(), getCurrentLocation());
|
2022-03-08 11:23:41 -08:00
|
|
|
osd->osec.inOverlay = true;
|
2018-06-27 08:08:12 +00:00
|
|
|
expect("{");
|
2025-03-11 19:58:14 +01:00
|
|
|
while (auto tok = till("}"))
|
|
|
|
osd->osec.commands.push_back(readInputSectionDescription(tok));
|
2023-05-11 12:00:19 +01:00
|
|
|
osd->osec.phdrs = readOutputSectionPhdrs();
|
2022-03-08 11:23:41 -08:00
|
|
|
return osd;
|
2018-06-27 08:08:12 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 11:23:41 -08:00
|
|
|
OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
2023-02-03 11:03:00 -08:00
|
|
|
OutputDesc *cmd =
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->createOutputSection(unquote(outSec), getCurrentLocation());
|
2022-03-08 11:23:41 -08:00
|
|
|
OutputSection *osec = &cmd->osec;
|
2022-05-04 01:10:45 -07:00
|
|
|
// Maybe relro. Will reset to false if DATA_SEGMENT_RELRO_END is absent.
|
2024-08-21 21:23:28 -07:00
|
|
|
osec->relro = ctx.script->seenDataAlign && !ctx.script->seenRelroEnd;
|
2017-06-08 19:47:16 +00:00
|
|
|
|
2024-08-21 21:23:28 -07:00
|
|
|
size_t symbolsReferenced = ctx.script->referencedSymbols.size();
|
2018-03-01 12:27:04 +00:00
|
|
|
|
2017-06-08 19:47:16 +00:00
|
|
|
if (peek() != ":")
|
2022-03-08 11:23:41 -08:00
|
|
|
readSectionAddressType(osec);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(":");
|
|
|
|
|
2017-10-25 14:50:51 +00:00
|
|
|
std::string location = getCurrentLocation();
|
2017-04-05 05:07:39 +00:00
|
|
|
if (consume("AT"))
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->lmaExpr = readParenExpr();
|
2017-04-05 05:07:39 +00:00
|
|
|
if (consume("ALIGN"))
|
2024-11-14 22:17:10 -08:00
|
|
|
osec->alignExpr = checkAlignment(ctx, readParenExpr(), location);
|
2017-04-05 05:07:39 +00:00
|
|
|
if (consume("SUBALIGN"))
|
2024-11-14 22:17:10 -08:00
|
|
|
osec->subalignExpr = checkAlignment(ctx, readParenExpr(), location);
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
// Parse constraints.
|
|
|
|
if (consume("ONLY_IF_RO"))
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->constraint = ConstraintKind::ReadOnly;
|
2017-04-05 05:07:39 +00:00
|
|
|
if (consume("ONLY_IF_RW"))
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->constraint = ConstraintKind::ReadWrite;
|
2017-04-05 05:07:39 +00:00
|
|
|
expect("{");
|
|
|
|
|
2024-07-26 17:13:37 -07:00
|
|
|
while (auto tok = till("}")) {
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == ";") {
|
|
|
|
// Empty commands are allowed. Do nothing here.
|
2018-04-25 11:16:31 +00:00
|
|
|
} else if (SymbolAssignment *assign = readAssignment(tok)) {
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->commands.push_back(assign);
|
2017-10-11 04:22:09 +00:00
|
|
|
} else if (ByteCommand *data = readByteCommand(tok)) {
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->commands.push_back(data);
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "CONSTRUCTORS") {
|
|
|
|
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
|
|
|
|
// by name. This is for very old file formats such as ECOFF/XCOFF.
|
|
|
|
// For ELF, we should ignore.
|
|
|
|
} else if (tok == "FILL") {
|
2019-07-04 14:17:31 +00:00
|
|
|
// We handle the FILL command as an alias for =fillexp section attribute,
|
|
|
|
// which is different from what GNU linkers do.
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
|
2020-02-16 14:17:26 +03:00
|
|
|
if (peek() != "(")
|
|
|
|
setError("( expected, but got " + peek());
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->filler = readFill();
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (tok == "SORT") {
|
|
|
|
readSort();
|
2018-10-12 17:07:32 +00:00
|
|
|
} else if (tok == "INCLUDE") {
|
|
|
|
readInclude();
|
2022-05-13 11:06:01 -07:00
|
|
|
} else if (tok == "(" || tok == ")") {
|
|
|
|
setError("expected filename pattern");
|
2017-04-05 05:07:39 +00:00
|
|
|
} else if (peek() == "(") {
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->commands.push_back(readInputSectionDescription(tok));
|
2017-04-05 05:07:39 +00:00
|
|
|
} else {
|
2018-12-06 08:34:52 +00:00
|
|
|
// We have a file name and no input sections description. It is not a
|
|
|
|
// commonly used syntax, but still acceptable. In that case, all sections
|
|
|
|
// from the file will be included.
|
2020-01-15 09:38:00 +00:00
|
|
|
// FIXME: GNU ld permits INPUT_SECTION_FLAGS to be used here. We do not
|
|
|
|
// handle this case here as it will already have been matched by the
|
|
|
|
// case above.
|
2018-12-06 10:56:11 +00:00
|
|
|
auto *isd = make<InputSectionDescription>(tok);
|
[lld/ELF] PR44498: Support input filename in double quote
Summary:
Linker scripts allow filenames to be put in double quotes to prevent
characters in filenames that are part of the linker script syntax from
having their special meaning. Case in point the * wildcard character.
Availability of double quoting filenames also allows to fix a failure in
ELF/linkerscript/filename-spec.s when the path contain a @ which the
lexer consider as a special characters and thus break up a filename
containing it. This may happens under Jenkins which createspath such as
pipeline@2.
To avoid the need for escaping GlobPattern metacharacters in filename
in double quotes, GlobPattern::create is augmented with a new parameter
to request literal matching instead of relying on the presence of a
wildcard character in the pattern.
Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap
Reviewed By: MaskRay
Subscribers: peter.smith, grimar, ruiu, emaste, arichardson, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D72517
2020-01-10 16:56:07 +00:00
|
|
|
isd->sectionPatterns.push_back({{}, StringMatcher("*")});
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->commands.push_back(isd);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (consume(">"))
|
2024-07-27 16:39:14 -07:00
|
|
|
osec->memoryRegionName = std::string(readName());
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2018-01-12 09:07:35 +00:00
|
|
|
if (consume("AT")) {
|
|
|
|
expect(">");
|
2024-07-27 16:39:14 -07:00
|
|
|
osec->lmaRegionName = std::string(readName());
|
2018-01-12 09:07:35 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 11:23:41 -08:00
|
|
|
if (osec->lmaExpr && !osec->lmaRegionName.empty())
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << "section can't have both LMA and a load region";
|
2018-01-12 09:07:35 +00:00
|
|
|
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->phdrs = readOutputSectionPhdrs();
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2023-06-05 14:36:19 -07:00
|
|
|
if (peek() == "=" || peek().starts_with("=")) {
|
2025-02-01 15:49:08 -08:00
|
|
|
lexState = State::Expr;
|
2019-07-04 14:17:31 +00:00
|
|
|
consume("=");
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->filler = readFill();
|
2025-02-01 15:49:08 -08:00
|
|
|
lexState = State::Script;
|
2019-07-04 14:17:31 +00:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
// Consume optional comma following output section command.
|
|
|
|
consume(",");
|
|
|
|
|
2024-08-21 21:23:28 -07:00
|
|
|
if (ctx.script->referencedSymbols.size() > symbolsReferenced)
|
2022-03-08 11:23:41 -08:00
|
|
|
osec->expressionsUseSymbols = true;
|
2017-04-05 05:07:39 +00:00
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
2019-07-04 14:17:31 +00:00
|
|
|
// Reads a `=<fillexp>` expression and returns its value as a big-endian number.
|
2017-04-05 05:07:39 +00:00
|
|
|
// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
|
2019-07-04 14:17:31 +00:00
|
|
|
// We do not support using symbols in such expressions.
|
2017-04-05 05:07:39 +00:00
|
|
|
//
|
2017-04-13 23:40:19 +00:00
|
|
|
// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
|
|
|
|
// size, while ld.gold always handles it as a 32-bit big-endian number.
|
|
|
|
// We are compatible with ld.gold because it's easier to implement.
|
2020-02-16 14:17:26 +03:00
|
|
|
// Also, we require that expressions with operators must be wrapped into
|
|
|
|
// round brackets. We did it to resolve the ambiguity when parsing scripts like:
|
|
|
|
// SECTIONS { .foo : { ... } =120+3 /DISCARD/ : { ... } }
|
2019-07-04 14:17:31 +00:00
|
|
|
std::array<uint8_t, 4> ScriptParser::readFill() {
|
2020-02-16 14:17:26 +03:00
|
|
|
uint64_t value = readPrimary()().val;
|
2019-07-04 14:17:31 +00:00
|
|
|
if (value > UINT32_MAX)
|
|
|
|
setError("filler expression result does not fit 32-bit: 0x" +
|
|
|
|
Twine::utohexstr(value));
|
2017-04-11 22:45:57 +00:00
|
|
|
|
2018-11-14 21:05:20 +00:00
|
|
|
std::array<uint8_t, 4> buf;
|
2019-07-04 14:17:31 +00:00
|
|
|
write32be(buf.data(), (uint32_t)value);
|
2017-04-11 22:45:57 +00:00
|
|
|
return buf;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
|
|
|
|
expect("(");
|
2024-07-27 16:19:57 -07:00
|
|
|
StringRef name = readName(), eq = peek();
|
2022-06-25 20:26:47 -07:00
|
|
|
if (eq != "=") {
|
|
|
|
setError("= expected, but got " + next());
|
2024-07-27 14:16:12 -07:00
|
|
|
while (till(")"))
|
2022-06-25 20:26:47 -07:00
|
|
|
;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2024-03-25 16:11:21 -07:00
|
|
|
llvm::SaveAndRestore saveActiveProvideSym(activeProvideSym);
|
|
|
|
if (provide)
|
|
|
|
activeProvideSym = name;
|
2022-06-25 20:26:47 -07:00
|
|
|
SymbolAssignment *cmd = readSymbolAssignment(name);
|
2017-04-05 05:07:39 +00:00
|
|
|
cmd->provide = provide;
|
|
|
|
cmd->hidden = hidden;
|
|
|
|
expect(")");
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
// Replace whitespace sequence (including \n) with one single space. The output
|
|
|
|
// is used by -Map.
|
|
|
|
static void squeezeSpaces(std::string &str) {
|
|
|
|
char prev = '\0';
|
|
|
|
auto it = str.begin();
|
|
|
|
for (char c : str)
|
|
|
|
if (!isSpace(c) || (c = ' ') != prev)
|
|
|
|
*it++ = prev = c;
|
|
|
|
str.erase(it, str.end());
|
|
|
|
}
|
|
|
|
|
2018-04-25 11:16:31 +00:00
|
|
|
SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
|
|
|
|
// Assert expression returns Dot, so this is equal to ".=."
|
|
|
|
if (tok == "ASSERT")
|
2023-09-09 14:46:51 -07:00
|
|
|
return make<SymbolAssignment>(".", readAssert(), 0, getCurrentLocation());
|
2018-04-25 11:16:31 +00:00
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
const char *oldS = prevTok.data();
|
2017-04-05 05:07:39 +00:00
|
|
|
SymbolAssignment *cmd = nullptr;
|
2024-08-21 21:23:28 -07:00
|
|
|
bool savedSeenRelroEnd = ctx.script->seenRelroEnd;
|
2022-06-25 22:22:59 -07:00
|
|
|
const StringRef op = peek();
|
2024-07-27 16:04:38 -07:00
|
|
|
{
|
2025-02-01 15:49:08 -08:00
|
|
|
SaveAndRestore saved(lexState, State::Expr);
|
2024-07-27 16:04:38 -07:00
|
|
|
if (op.starts_with("=")) {
|
|
|
|
// Support = followed by an expression without whitespace.
|
2024-07-27 16:19:57 -07:00
|
|
|
cmd = readSymbolAssignment(unquote(tok));
|
2024-07-27 16:04:38 -07:00
|
|
|
} else if ((op.size() == 2 && op[1] == '=' && strchr("+-*/&^|", op[0])) ||
|
|
|
|
op == "<<=" || op == ">>=") {
|
2024-07-27 16:19:57 -07:00
|
|
|
cmd = readSymbolAssignment(unquote(tok));
|
2024-07-27 16:04:38 -07:00
|
|
|
} else if (tok == "PROVIDE") {
|
|
|
|
cmd = readProvideHidden(true, false);
|
|
|
|
} else if (tok == "HIDDEN") {
|
|
|
|
cmd = readProvideHidden(false, true);
|
|
|
|
} else if (tok == "PROVIDE_HIDDEN") {
|
|
|
|
cmd = readProvideHidden(true, true);
|
|
|
|
}
|
2022-06-25 20:25:34 -07:00
|
|
|
}
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 05:00:37 +00:00
|
|
|
|
2018-04-05 11:25:58 +00:00
|
|
|
if (cmd) {
|
2024-08-21 21:23:28 -07:00
|
|
|
cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && ctx.script->seenRelroEnd;
|
2024-07-26 14:26:38 -07:00
|
|
|
cmd->commandString = StringRef(oldS, curTok.data() - oldS).str();
|
|
|
|
squeezeSpaces(cmd->commandString);
|
2018-04-05 11:25:58 +00:00
|
|
|
expect(";");
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
2024-07-27 16:19:57 -07:00
|
|
|
StringRef ScriptParser::readName() { return unquote(next()); }
|
|
|
|
|
2018-04-25 11:16:31 +00:00
|
|
|
SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) {
|
2017-04-05 05:07:39 +00:00
|
|
|
StringRef op = next();
|
2022-06-25 22:22:59 -07:00
|
|
|
assert(op == "=" || op == "*=" || op == "/=" || op == "+=" || op == "-=" ||
|
2023-07-15 14:10:40 -07:00
|
|
|
op == "&=" || op == "^=" || op == "|=" || op == "<<=" || op == ">>=");
|
2023-09-15 17:52:48 -07:00
|
|
|
// Note: GNU ld does not support %=.
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr e = readExpr();
|
2022-06-25 22:22:59 -07:00
|
|
|
if (op != "=") {
|
2017-04-05 05:07:39 +00:00
|
|
|
std::string loc = getCurrentLocation();
|
2024-11-06 22:04:52 -08:00
|
|
|
e = [=, s = ctx.script, c = op[0], &ctx = ctx]() -> ExprValue {
|
2024-09-21 11:51:02 -07:00
|
|
|
ExprValue lhs = s->getSymbolValue(name, loc);
|
2022-06-25 22:22:59 -07:00
|
|
|
switch (c) {
|
|
|
|
case '*':
|
|
|
|
return lhs.getValue() * e().getValue();
|
|
|
|
case '/':
|
|
|
|
if (uint64_t rv = e().getValue())
|
|
|
|
return lhs.getValue() / rv;
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << loc << ": division by zero";
|
2022-06-25 22:22:59 -07:00
|
|
|
return 0;
|
|
|
|
case '+':
|
2024-09-21 11:51:02 -07:00
|
|
|
return add(*s, lhs, e());
|
2022-06-25 22:22:59 -07:00
|
|
|
case '-':
|
|
|
|
return sub(lhs, e());
|
|
|
|
case '<':
|
2023-06-15 10:34:33 -07:00
|
|
|
return lhs.getValue() << e().getValue() % 64;
|
2022-06-25 22:22:59 -07:00
|
|
|
case '>':
|
2023-06-15 10:34:33 -07:00
|
|
|
return lhs.getValue() >> e().getValue() % 64;
|
2022-06-25 22:22:59 -07:00
|
|
|
case '&':
|
|
|
|
return lhs.getValue() & e().getValue();
|
2023-07-15 14:10:40 -07:00
|
|
|
case '^':
|
|
|
|
return lhs.getValue() ^ e().getValue();
|
2022-06-25 22:22:59 -07:00
|
|
|
case '|':
|
|
|
|
return lhs.getValue() | e().getValue();
|
|
|
|
default:
|
|
|
|
llvm_unreachable("");
|
|
|
|
}
|
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2023-09-09 14:46:51 -07:00
|
|
|
return make<SymbolAssignment>(name, e, ctx.scriptSymOrderCounter++,
|
|
|
|
getCurrentLocation());
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This is an operator-precedence parser to parse a linker
|
|
|
|
// script expression.
|
|
|
|
Expr ScriptParser::readExpr() {
|
|
|
|
// Our lexer is context-aware. Set the in-expression bit so that
|
|
|
|
// they apply different tokenization rules.
|
2025-02-01 15:49:08 -08:00
|
|
|
SaveAndRestore saved(lexState, State::Expr);
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr e = readExpr1(readPrimary(), 0);
|
|
|
|
return e;
|
|
|
|
}
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 05:00:37 +00:00
|
|
|
|
2018-03-05 10:02:44 +00:00
|
|
|
Expr ScriptParser::combine(StringRef op, Expr l, Expr r) {
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "+")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return add(*s, l(), r()); };
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "-")
|
|
|
|
return [=] { return sub(l(), r()); };
|
2017-04-05 05:40:21 +00:00
|
|
|
if (op == "*")
|
2018-02-28 18:25:00 +00:00
|
|
|
return [=] { return l().getValue() * r().getValue(); };
|
2018-03-05 10:02:44 +00:00
|
|
|
if (op == "/") {
|
|
|
|
std::string loc = getCurrentLocation();
|
2024-11-06 22:04:52 -08:00
|
|
|
return [=, &ctx = ctx]() -> uint64_t {
|
2018-03-05 10:02:44 +00:00
|
|
|
if (uint64_t rv = r().getValue())
|
|
|
|
return l().getValue() / rv;
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << loc << ": division by zero";
|
2018-03-05 23:50:45 +00:00
|
|
|
return 0;
|
2018-03-05 10:02:44 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
if (op == "%") {
|
|
|
|
std::string loc = getCurrentLocation();
|
2024-11-06 22:04:52 -08:00
|
|
|
return [=, &ctx = ctx]() -> uint64_t {
|
2018-03-05 10:02:44 +00:00
|
|
|
if (uint64_t rv = r().getValue())
|
|
|
|
return l().getValue() % rv;
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << loc << ": modulo by zero";
|
2018-03-05 23:50:45 +00:00
|
|
|
return 0;
|
2018-03-05 10:02:44 +00:00
|
|
|
};
|
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "<<")
|
2023-06-15 10:34:33 -07:00
|
|
|
return [=] { return l().getValue() << r().getValue() % 64; };
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == ">>")
|
2023-06-15 10:34:33 -07:00
|
|
|
return [=] { return l().getValue() >> r().getValue() % 64; };
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "<")
|
|
|
|
return [=] { return l().getValue() < r().getValue(); };
|
|
|
|
if (op == ">")
|
|
|
|
return [=] { return l().getValue() > r().getValue(); };
|
|
|
|
if (op == ">=")
|
|
|
|
return [=] { return l().getValue() >= r().getValue(); };
|
|
|
|
if (op == "<=")
|
|
|
|
return [=] { return l().getValue() <= r().getValue(); };
|
|
|
|
if (op == "==")
|
|
|
|
return [=] { return l().getValue() == r().getValue(); };
|
|
|
|
if (op == "!=")
|
|
|
|
return [=] { return l().getValue() != r().getValue(); };
|
2018-07-03 14:02:52 +00:00
|
|
|
if (op == "||")
|
|
|
|
return [=] { return l().getValue() || r().getValue(); };
|
|
|
|
if (op == "&&")
|
|
|
|
return [=] { return l().getValue() && r().getValue(); };
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "&")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return bitAnd(*s, l(), r()); };
|
2023-07-15 14:10:40 -07:00
|
|
|
if (op == "^")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return bitXor(*s, l(), r()); };
|
2017-04-05 05:07:39 +00:00
|
|
|
if (op == "|")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return bitOr(*s, l(), r()); };
|
2017-04-05 05:07:39 +00:00
|
|
|
llvm_unreachable("invalid operator");
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a part of the operator-precedence parser. This function
|
|
|
|
// assumes that the remaining token stream starts with an operator.
|
|
|
|
Expr ScriptParser::readExpr1(Expr lhs, int minPrec) {
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!atEOF() && !errCount(ctx)) {
|
2017-04-05 05:07:39 +00:00
|
|
|
// Read an operator and an expression.
|
|
|
|
StringRef op1 = peek();
|
|
|
|
if (precedence(op1) < minPrec)
|
|
|
|
break;
|
|
|
|
skip();
|
2024-07-20 14:36:55 -07:00
|
|
|
if (op1 == "?")
|
|
|
|
return readTernary(lhs);
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr rhs = readPrimary();
|
|
|
|
|
|
|
|
// Evaluate the remaining part of the expression first if the
|
|
|
|
// next operator has greater precedence than the previous one.
|
|
|
|
// For example, if we have read "+" and "3", and if the next
|
|
|
|
// operator is "*", then we'll evaluate 3 * ... part first.
|
|
|
|
while (!atEOF()) {
|
|
|
|
StringRef op2 = peek();
|
|
|
|
if (precedence(op2) <= precedence(op1))
|
|
|
|
break;
|
|
|
|
rhs = readExpr1(rhs, precedence(op2));
|
|
|
|
}
|
|
|
|
|
|
|
|
lhs = combine(op1, lhs, rhs);
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
2017-08-03 16:05:08 +00:00
|
|
|
Expr ScriptParser::getPageSize() {
|
|
|
|
std::string location = getCurrentLocation();
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, &ctx = this->ctx]() -> uint64_t {
|
2024-08-21 23:53:36 -07:00
|
|
|
if (ctx.target)
|
2024-09-21 11:06:06 -07:00
|
|
|
return ctx.arg.commonPageSize;
|
2024-11-06 22:04:52 -08:00
|
|
|
ErrAlways(ctx) << location << ": unable to calculate page size";
|
2017-08-03 16:05:08 +00:00
|
|
|
return 4096; // Return a dummy value.
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr ScriptParser::readConstant() {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef s = readParenName();
|
2017-04-05 05:07:39 +00:00
|
|
|
if (s == "COMMONPAGESIZE")
|
2017-08-03 16:05:08 +00:00
|
|
|
return getPageSize();
|
2017-04-05 05:07:39 +00:00
|
|
|
if (s == "MAXPAGESIZE")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [&ctx = this->ctx] { return ctx.arg.maxPageSize; };
|
2017-08-03 16:05:08 +00:00
|
|
|
setError("unknown constant: " + s);
|
2018-03-01 12:36:01 +00:00
|
|
|
return [] { return 0; };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 23:22:11 +00:00
|
|
|
// Parses Tok as an integer. It recognizes hexadecimal (prefixed with
|
|
|
|
// "0x" or suffixed with "H") and decimal numbers. Decimal numbers may
|
|
|
|
// have "K" (Ki) or "M" (Mi) suffixes.
|
2022-11-26 19:19:15 -08:00
|
|
|
static std::optional<uint64_t> parseInt(StringRef tok) {
|
2017-04-05 05:07:39 +00:00
|
|
|
// Hexadecimal
|
2017-04-05 23:22:11 +00:00
|
|
|
uint64_t val;
|
2023-05-16 10:12:42 -07:00
|
|
|
if (tok.starts_with_insensitive("0x")) {
|
2017-10-11 19:30:39 +00:00
|
|
|
if (!to_integer(tok.substr(2), val, 16))
|
2022-11-26 19:19:15 -08:00
|
|
|
return std::nullopt;
|
2017-04-05 23:22:11 +00:00
|
|
|
return val;
|
2017-10-11 19:30:39 +00:00
|
|
|
}
|
2023-05-16 10:12:42 -07:00
|
|
|
if (tok.ends_with_insensitive("H")) {
|
2017-10-11 19:30:39 +00:00
|
|
|
if (!to_integer(tok.drop_back(), val, 16))
|
2022-11-26 19:19:15 -08:00
|
|
|
return std::nullopt;
|
2017-04-05 23:22:11 +00:00
|
|
|
return val;
|
2017-10-11 19:30:39 +00:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
// Decimal
|
2023-05-16 10:12:42 -07:00
|
|
|
if (tok.ends_with_insensitive("K")) {
|
2017-05-16 08:19:25 +00:00
|
|
|
if (!to_integer(tok.drop_back(), val, 10))
|
2022-11-26 19:19:15 -08:00
|
|
|
return std::nullopt;
|
2017-04-05 23:22:11 +00:00
|
|
|
return val * 1024;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2023-05-16 10:12:42 -07:00
|
|
|
if (tok.ends_with_insensitive("M")) {
|
2017-05-16 08:19:25 +00:00
|
|
|
if (!to_integer(tok.drop_back(), val, 10))
|
2022-11-26 19:19:15 -08:00
|
|
|
return std::nullopt;
|
2017-04-05 23:22:11 +00:00
|
|
|
return val * 1024 * 1024;
|
|
|
|
}
|
2017-05-16 08:19:25 +00:00
|
|
|
if (!to_integer(tok, val, 10))
|
2022-11-26 19:19:15 -08:00
|
|
|
return std::nullopt;
|
2017-04-05 23:22:11 +00:00
|
|
|
return val;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2017-10-11 04:22:09 +00:00
|
|
|
ByteCommand *ScriptParser::readByteCommand(StringRef tok) {
|
2017-04-05 05:40:21 +00:00
|
|
|
int size = StringSwitch<int>(tok)
|
2017-04-05 05:07:39 +00:00
|
|
|
.Case("BYTE", 1)
|
|
|
|
.Case("SHORT", 2)
|
|
|
|
.Case("LONG", 4)
|
|
|
|
.Case("QUAD", 8)
|
|
|
|
.Default(-1);
|
|
|
|
if (size == -1)
|
|
|
|
return nullptr;
|
2018-03-15 09:16:40 +00:00
|
|
|
|
2024-07-26 14:26:38 -07:00
|
|
|
const char *oldS = prevTok.data();
|
2018-03-15 09:16:40 +00:00
|
|
|
Expr e = readParenExpr();
|
2024-07-26 14:26:38 -07:00
|
|
|
std::string commandString = StringRef(oldS, curBuf.s.data() - oldS).str();
|
|
|
|
squeezeSpaces(commandString);
|
|
|
|
return make<ByteCommand>(e, size, std::move(commandString));
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2022-11-26 19:19:15 -08:00
|
|
|
static std::optional<uint64_t> parseFlag(StringRef tok) {
|
|
|
|
if (std::optional<uint64_t> asInt = parseInt(tok))
|
2020-01-15 09:38:00 +00:00
|
|
|
return asInt;
|
|
|
|
#define CASE_ENT(enum) #enum, ELF::enum
|
2022-11-26 19:19:15 -08:00
|
|
|
return StringSwitch<std::optional<uint64_t>>(tok)
|
2020-01-15 09:38:00 +00:00
|
|
|
.Case(CASE_ENT(SHF_WRITE))
|
|
|
|
.Case(CASE_ENT(SHF_ALLOC))
|
|
|
|
.Case(CASE_ENT(SHF_EXECINSTR))
|
|
|
|
.Case(CASE_ENT(SHF_MERGE))
|
|
|
|
.Case(CASE_ENT(SHF_STRINGS))
|
|
|
|
.Case(CASE_ENT(SHF_INFO_LINK))
|
|
|
|
.Case(CASE_ENT(SHF_LINK_ORDER))
|
|
|
|
.Case(CASE_ENT(SHF_OS_NONCONFORMING))
|
|
|
|
.Case(CASE_ENT(SHF_GROUP))
|
|
|
|
.Case(CASE_ENT(SHF_TLS))
|
|
|
|
.Case(CASE_ENT(SHF_COMPRESSED))
|
|
|
|
.Case(CASE_ENT(SHF_EXCLUDE))
|
|
|
|
.Case(CASE_ENT(SHF_ARM_PURECODE))
|
2025-02-21 18:01:38 +01:00
|
|
|
.Case(CASE_ENT(SHF_AARCH64_PURECODE))
|
2022-12-02 23:12:36 -08:00
|
|
|
.Default(std::nullopt);
|
2020-01-15 09:38:00 +00:00
|
|
|
#undef CASE_ENT
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads the '(' <flags> ')' list of section flags in
|
|
|
|
// INPUT_SECTION_FLAGS '(' <flags> ')' in the
|
|
|
|
// following form:
|
|
|
|
// <flags> ::= <flag>
|
|
|
|
// | <flags> & flag
|
|
|
|
// <flag> ::= Recognized Flag Name, or Integer value of flag.
|
|
|
|
// If the first character of <flag> is a ! then this means without flag,
|
|
|
|
// otherwise with flag.
|
|
|
|
// Example: SHF_EXECINSTR & !SHF_WRITE means with flag SHF_EXECINSTR and
|
|
|
|
// without flag SHF_WRITE.
|
|
|
|
std::pair<uint64_t, uint64_t> ScriptParser::readInputSectionFlags() {
|
2024-07-27 16:27:05 -07:00
|
|
|
uint64_t withFlags = 0;
|
|
|
|
uint64_t withoutFlags = 0;
|
|
|
|
expect("(");
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx)) {
|
2024-07-27 16:27:05 -07:00
|
|
|
StringRef tok = readName();
|
2020-01-15 09:38:00 +00:00
|
|
|
bool without = tok.consume_front("!");
|
2022-11-26 19:19:15 -08:00
|
|
|
if (std::optional<uint64_t> flag = parseFlag(tok)) {
|
2020-01-15 09:38:00 +00:00
|
|
|
if (without)
|
|
|
|
withoutFlags |= *flag;
|
|
|
|
else
|
|
|
|
withFlags |= *flag;
|
|
|
|
} else {
|
|
|
|
setError("unrecognised flag: " + tok);
|
|
|
|
}
|
|
|
|
if (consume(")"))
|
|
|
|
break;
|
|
|
|
if (!consume("&")) {
|
|
|
|
next();
|
|
|
|
setError("expected & or )");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return std::make_pair(withFlags, withoutFlags);
|
|
|
|
}
|
|
|
|
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef ScriptParser::readParenName() {
|
2017-04-05 05:07:39 +00:00
|
|
|
expect("(");
|
2025-02-01 15:49:08 -08:00
|
|
|
auto saved = std::exchange(lexState, State::Script);
|
|
|
|
StringRef name = readName();
|
|
|
|
lexState = saved;
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
2025-02-01 15:49:08 -08:00
|
|
|
return name;
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:51:02 -07:00
|
|
|
static void checkIfExists(LinkerScript &script, const OutputSection &osec,
|
|
|
|
StringRef location) {
|
|
|
|
if (osec.location.empty() && script.errorOnMissingSection)
|
|
|
|
script.recordError(location + ": undefined section " + osec.name);
|
2017-06-01 01:16:50 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 09:34:36 -08:00
|
|
|
static bool isValidSymbolName(StringRef s) {
|
|
|
|
auto valid = [](char c) {
|
|
|
|
return isAlnum(c) || c == '$' || c == '.' || c == '_';
|
|
|
|
};
|
|
|
|
return !s.empty() && !isDigit(s[0]) && llvm::all_of(s, valid);
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr ScriptParser::readPrimary() {
|
|
|
|
if (peek() == "(")
|
|
|
|
return readParenExpr();
|
|
|
|
|
2017-04-05 23:22:11 +00:00
|
|
|
if (consume("~")) {
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr e = readPrimary();
|
2017-04-05 19:21:15 +00:00
|
|
|
return [=] { return ~e().getValue(); };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2017-08-10 15:25:47 +00:00
|
|
|
if (consume("!")) {
|
|
|
|
Expr e = readPrimary();
|
|
|
|
return [=] { return !e().getValue(); };
|
|
|
|
}
|
2017-04-05 23:22:11 +00:00
|
|
|
if (consume("-")) {
|
2017-04-05 05:07:39 +00:00
|
|
|
Expr e = readPrimary();
|
2017-04-05 19:21:15 +00:00
|
|
|
return [=] { return -e().getValue(); };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2025-01-22 09:35:07 +05:30
|
|
|
if (consume("+"))
|
|
|
|
return readPrimary();
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2017-04-05 23:22:11 +00:00
|
|
|
StringRef tok = next();
|
|
|
|
std::string location = getCurrentLocation();
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
// Built-in functions are parsed here.
|
|
|
|
// https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
|
|
|
|
if (tok == "ABSOLUTE") {
|
|
|
|
Expr inner = readParenExpr();
|
|
|
|
return [=] {
|
|
|
|
ExprValue i = inner();
|
|
|
|
i.forceAbsolute = true;
|
|
|
|
return i;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (tok == "ADDR") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
OutputSection *osec = &ctx.script->getOrCreateOutputSection(name)->osec;
|
2022-02-28 11:19:00 -08:00
|
|
|
osec->usedInExpression = true;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script]() -> ExprValue {
|
|
|
|
checkIfExists(*s, *osec, location);
|
2022-02-28 11:19:00 -08:00
|
|
|
return {osec, false, 0, location};
|
2017-06-07 08:54:43 +00:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "ALIGN") {
|
|
|
|
expect("(");
|
|
|
|
Expr e = readExpr();
|
2017-10-25 14:50:51 +00:00
|
|
|
if (consume(")")) {
|
2024-11-14 22:17:10 -08:00
|
|
|
e = checkAlignment(ctx, e, location);
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] {
|
|
|
|
return alignToPowerOf2(s->getDot(), e().getValue());
|
|
|
|
};
|
2017-10-25 14:50:51 +00:00
|
|
|
}
|
2017-04-05 05:40:21 +00:00
|
|
|
expect(",");
|
2024-11-14 22:17:10 -08:00
|
|
|
Expr e2 = checkAlignment(ctx, readExpr(), location);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
2017-05-30 03:18:28 +00:00
|
|
|
return [=] {
|
|
|
|
ExprValue v = e();
|
2017-10-25 14:50:51 +00:00
|
|
|
v.alignment = e2().getValue();
|
2017-05-30 03:18:28 +00:00
|
|
|
return v;
|
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "ALIGNOF") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
OutputSection *osec = &ctx.script->getOrCreateOutputSection(name)->osec;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] {
|
|
|
|
checkIfExists(*s, *osec, location);
|
2022-12-01 16:19:56 +00:00
|
|
|
return osec->addralign;
|
2017-10-08 02:27:02 +00:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "ASSERT")
|
2018-04-25 11:16:31 +00:00
|
|
|
return readAssert();
|
2017-08-03 16:05:08 +00:00
|
|
|
if (tok == "CONSTANT")
|
|
|
|
return readConstant();
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == "DATA_SEGMENT_ALIGN") {
|
|
|
|
expect("(");
|
|
|
|
Expr e = readExpr();
|
|
|
|
expect(",");
|
|
|
|
readExpr();
|
|
|
|
expect(")");
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->seenDataAlign = true;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] {
|
2022-07-24 11:20:49 -07:00
|
|
|
uint64_t align = std::max(uint64_t(1), e().getValue());
|
2024-09-21 11:51:02 -07:00
|
|
|
return (s->getDot() + align - 1) & -align;
|
2017-07-28 09:27:49 +00:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "DATA_SEGMENT_END") {
|
|
|
|
expect("(");
|
|
|
|
expect(".");
|
|
|
|
expect(")");
|
2024-09-21 11:51:02 -07:00
|
|
|
return [s = ctx.script] { return s->getDot(); };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "DATA_SEGMENT_RELRO_END") {
|
|
|
|
// GNU linkers implements more complicated logic to handle
|
|
|
|
// DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
|
|
|
|
// just align to the next page boundary for simplicity.
|
|
|
|
expect("(");
|
|
|
|
readExpr();
|
|
|
|
expect(",");
|
|
|
|
readExpr();
|
|
|
|
expect(")");
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->seenRelroEnd = true;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [&ctx = this->ctx] {
|
2024-09-21 11:06:06 -07:00
|
|
|
return alignToPowerOf2(ctx.script->getDot(), ctx.arg.maxPageSize);
|
2024-08-21 21:23:28 -07:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "DEFINED") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2023-09-09 14:46:51 -07:00
|
|
|
// Return 1 if s is defined. If the definition is only found in a linker
|
|
|
|
// script, it must happen before this DEFINED.
|
|
|
|
auto order = ctx.scriptSymOrderCounter++;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, &ctx = this->ctx] {
|
2024-09-23 10:33:43 -07:00
|
|
|
Symbol *s = ctx.symtab->find(name);
|
2023-09-09 14:46:51 -07:00
|
|
|
return s && s->isDefined() && ctx.scriptSymOrder.lookup(s) < order ? 1
|
|
|
|
: 0;
|
2020-07-16 21:40:31 +01:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2017-05-09 18:24:38 +00:00
|
|
|
if (tok == "LENGTH") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
if (ctx.script->memoryRegions.count(name) == 0) {
|
2017-05-09 18:24:38 +00:00
|
|
|
setError("memory region not defined: " + name);
|
2018-03-01 12:36:01 +00:00
|
|
|
return [] { return 0; };
|
|
|
|
}
|
2024-08-21 21:23:28 -07:00
|
|
|
return ctx.script->memoryRegions[name]->length;
|
2017-05-09 18:24:38 +00:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == "LOADADDR") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
OutputSection *osec = &ctx.script->getOrCreateOutputSection(name)->osec;
|
2022-02-28 11:19:00 -08:00
|
|
|
osec->usedInExpression = true;
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] {
|
|
|
|
checkIfExists(*s, *osec, location);
|
2022-02-28 11:19:00 -08:00
|
|
|
return osec->getLMA();
|
2017-10-08 02:27:02 +00:00
|
|
|
};
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
2020-07-27 11:49:24 +03:00
|
|
|
if (tok == "LOG2CEIL") {
|
|
|
|
expect("(");
|
|
|
|
Expr a = readExpr();
|
|
|
|
expect(")");
|
|
|
|
return [=] {
|
|
|
|
// LOG2CEIL(0) is defined to be 0.
|
|
|
|
return llvm::Log2_64_Ceil(std::max(a().getValue(), UINT64_C(1)));
|
|
|
|
};
|
|
|
|
}
|
2018-03-28 11:33:00 +00:00
|
|
|
if (tok == "MAX" || tok == "MIN") {
|
|
|
|
expect("(");
|
|
|
|
Expr a = readExpr();
|
|
|
|
expect(",");
|
|
|
|
Expr b = readExpr();
|
|
|
|
expect(")");
|
|
|
|
if (tok == "MIN")
|
|
|
|
return [=] { return std::min(a().getValue(), b().getValue()); };
|
|
|
|
return [=] { return std::max(a().getValue(), b().getValue()); };
|
|
|
|
}
|
2017-05-09 18:24:38 +00:00
|
|
|
if (tok == "ORIGIN") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
if (ctx.script->memoryRegions.count(name) == 0) {
|
2017-05-09 18:24:38 +00:00
|
|
|
setError("memory region not defined: " + name);
|
2018-03-01 12:36:01 +00:00
|
|
|
return [] { return 0; };
|
|
|
|
}
|
2024-08-21 21:23:28 -07:00
|
|
|
return ctx.script->memoryRegions[name]->origin;
|
2017-05-09 18:24:38 +00:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
if (tok == "SEGMENT_START") {
|
|
|
|
expect("(");
|
|
|
|
skip();
|
|
|
|
expect(",");
|
|
|
|
Expr e = readExpr();
|
|
|
|
expect(")");
|
|
|
|
return [=] { return e(); };
|
|
|
|
}
|
|
|
|
if (tok == "SIZEOF") {
|
2024-07-27 16:47:17 -07:00
|
|
|
StringRef name = readParenName();
|
2024-08-21 21:23:28 -07:00
|
|
|
OutputSection *cmd = &ctx.script->getOrCreateOutputSection(name)->osec;
|
2017-06-01 01:16:50 +00:00
|
|
|
// Linker script does not create an output section if its content is empty.
|
|
|
|
// We want to allow SIZEOF(.foo) where .foo is a section which happened to
|
|
|
|
// be empty.
|
2017-07-27 19:22:43 +00:00
|
|
|
return [=] { return cmd->size; };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
if (tok == "SIZEOF_HEADERS")
|
2024-10-03 20:06:58 -07:00
|
|
|
return [=, &ctx = ctx] { return elf::getHeaderSize(ctx); };
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2017-04-05 18:02:30 +00:00
|
|
|
// Tok is the dot.
|
|
|
|
if (tok == ".")
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return s->getSymbolValue(tok, location); };
|
2017-04-05 18:02:30 +00:00
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
// Tok is a literal number.
|
2022-11-26 19:19:15 -08:00
|
|
|
if (std::optional<uint64_t> val = parseInt(tok))
|
2017-04-05 23:22:11 +00:00
|
|
|
return [=] { return *val; };
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
// Tok is a symbol name.
|
2023-06-05 14:36:19 -07:00
|
|
|
if (tok.starts_with("\""))
|
2021-09-27 09:50:41 -07:00
|
|
|
tok = unquote(tok);
|
|
|
|
else if (!isValidSymbolName(tok))
|
2017-04-05 18:02:30 +00:00
|
|
|
setError("malformed number: " + tok);
|
2024-03-25 16:11:21 -07:00
|
|
|
if (activeProvideSym)
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->provideMap[*activeProvideSym].push_back(tok);
|
2024-03-25 16:11:21 -07:00
|
|
|
else
|
2024-08-21 21:23:28 -07:00
|
|
|
ctx.script->referencedSymbols.push_back(tok);
|
2024-09-21 11:51:02 -07:00
|
|
|
return [=, s = ctx.script] { return s->getSymbolValue(tok, location); };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expr ScriptParser::readTernary(Expr cond) {
|
|
|
|
Expr l = readExpr();
|
|
|
|
expect(":");
|
|
|
|
Expr r = readExpr();
|
|
|
|
return [=] { return cond().getValue() ? l() : r(); };
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr ScriptParser::readParenExpr() {
|
|
|
|
expect("(");
|
|
|
|
Expr e = readExpr();
|
|
|
|
expect(")");
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2021-12-26 13:53:47 -08:00
|
|
|
SmallVector<StringRef, 0> ScriptParser::readOutputSectionPhdrs() {
|
|
|
|
SmallVector<StringRef, 0> phdrs;
|
2024-11-07 09:06:01 -08:00
|
|
|
while (!errCount(ctx) && peek().starts_with(":")) {
|
2017-04-05 05:07:39 +00:00
|
|
|
StringRef tok = next();
|
2024-07-27 17:40:51 -07:00
|
|
|
phdrs.push_back((tok.size() == 1) ? readName() : tok.substr(1));
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
return phdrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read a program header type name. The next token must be a
|
|
|
|
// name of a program header type or a constant (e.g. "0x3").
|
|
|
|
unsigned ScriptParser::readPhdrType() {
|
|
|
|
StringRef tok = next();
|
2022-11-26 19:19:15 -08:00
|
|
|
if (std::optional<uint64_t> val = parseInt(tok))
|
2017-04-05 23:22:11 +00:00
|
|
|
return *val;
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
unsigned ret = StringSwitch<unsigned>(tok)
|
|
|
|
.Case("PT_NULL", PT_NULL)
|
|
|
|
.Case("PT_LOAD", PT_LOAD)
|
|
|
|
.Case("PT_DYNAMIC", PT_DYNAMIC)
|
|
|
|
.Case("PT_INTERP", PT_INTERP)
|
|
|
|
.Case("PT_NOTE", PT_NOTE)
|
|
|
|
.Case("PT_SHLIB", PT_SHLIB)
|
|
|
|
.Case("PT_PHDR", PT_PHDR)
|
|
|
|
.Case("PT_TLS", PT_TLS)
|
|
|
|
.Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
|
|
|
|
.Case("PT_GNU_STACK", PT_GNU_STACK)
|
|
|
|
.Case("PT_GNU_RELRO", PT_GNU_RELRO)
|
2024-07-12 14:34:17 -04:00
|
|
|
.Case("PT_OPENBSD_MUTABLE", PT_OPENBSD_MUTABLE)
|
2017-04-05 05:07:39 +00:00
|
|
|
.Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
|
2024-07-12 14:34:17 -04:00
|
|
|
.Case("PT_OPENBSD_SYSCALLS", PT_OPENBSD_SYSCALLS)
|
2017-04-05 05:07:39 +00:00
|
|
|
.Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
|
|
|
|
.Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
|
|
|
|
.Default(-1);
|
|
|
|
|
|
|
|
if (ret == (unsigned)-1) {
|
|
|
|
setError("invalid program header type: " + tok);
|
|
|
|
return PT_NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads an anonymous version declaration.
|
|
|
|
void ScriptParser::readAnonymousDeclaration() {
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> locals;
|
|
|
|
SmallVector<SymbolVersion, 0> globals;
|
2017-04-05 05:07:39 +00:00
|
|
|
std::tie(locals, globals) = readSymbols();
|
2019-08-05 14:31:39 +00:00
|
|
|
for (const SymbolVersion &pat : locals)
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.versionDefinitions[VER_NDX_LOCAL].localPatterns.push_back(pat);
|
2019-08-05 14:31:39 +00:00
|
|
|
for (const SymbolVersion &pat : globals)
|
2024-09-21 11:06:06 -07:00
|
|
|
ctx.arg.versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back(pat);
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
expect(";");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads a non-anonymous version definition,
|
|
|
|
// e.g. "VerStr { global: foo; bar; local: *; };".
|
|
|
|
void ScriptParser::readVersionDeclaration(StringRef verStr) {
|
|
|
|
// Read a symbol list.
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> locals;
|
|
|
|
SmallVector<SymbolVersion, 0> globals;
|
2017-04-05 05:07:39 +00:00
|
|
|
std::tie(locals, globals) = readSymbols();
|
|
|
|
|
|
|
|
// Create a new version definition and add that to the global symbols.
|
|
|
|
VersionDefinition ver;
|
|
|
|
ver.name = verStr;
|
2021-08-04 23:52:55 -07:00
|
|
|
ver.nonLocalPatterns = std::move(globals);
|
|
|
|
ver.localPatterns = std::move(locals);
|
2024-09-21 11:06:06 -07:00
|
|
|
ver.id = ctx.arg.versionDefinitions.size();
|
|
|
|
ctx.arg.versionDefinitions.push_back(ver);
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
// Each version may have a parent version. For example, "Ver2"
|
|
|
|
// defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
|
|
|
|
// as a parent. This version hierarchy is, probably against your
|
|
|
|
// instinct, purely for hint; the runtime doesn't care about it
|
|
|
|
// at all. In LLD, we simply ignore it.
|
2020-02-08 14:10:29 -08:00
|
|
|
if (next() != ";")
|
|
|
|
expect(";");
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 17:11:38 -07:00
|
|
|
bool elf::hasWildcard(StringRef s) {
|
2017-07-13 20:30:35 +00:00
|
|
|
return s.find_first_of("?*[") != StringRef::npos;
|
|
|
|
}
|
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
|
2021-12-26 20:12:55 -08:00
|
|
|
std::pair<SmallVector<SymbolVersion, 0>, SmallVector<SymbolVersion, 0>>
|
2017-04-05 05:07:39 +00:00
|
|
|
ScriptParser::readSymbols() {
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> locals;
|
|
|
|
SmallVector<SymbolVersion, 0> globals;
|
|
|
|
SmallVector<SymbolVersion, 0> *v = &globals;
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2024-07-27 14:16:12 -07:00
|
|
|
while (auto tok = till("}")) {
|
|
|
|
if (tok == "extern") {
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> ext = readVersionExtern();
|
2017-04-05 05:07:39 +00:00
|
|
|
v->insert(v->end(), ext.begin(), ext.end());
|
|
|
|
} else {
|
2024-07-23 22:03:46 -07:00
|
|
|
if (tok == "local:" || (tok == "local" && consume(":"))) {
|
|
|
|
v = &locals;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (tok == "global:" || (tok == "global" && consume(":"))) {
|
|
|
|
v = &globals;
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
v->push_back({unquote(tok), false, hasWildcard(tok)});
|
|
|
|
}
|
|
|
|
expect(";");
|
|
|
|
}
|
|
|
|
return {locals, globals};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reads an "extern C++" directive, e.g.,
|
|
|
|
// "extern "C++" { ns::*; "f(int, double)"; };"
|
2018-02-01 23:46:17 +00:00
|
|
|
//
|
|
|
|
// The last semicolon is optional. E.g. this is OK:
|
|
|
|
// "extern "C++" { ns::*; "f(int, double)" };"
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> ScriptParser::readVersionExtern() {
|
2017-04-05 05:07:39 +00:00
|
|
|
StringRef tok = next();
|
|
|
|
bool isCXX = tok == "\"C++\"";
|
|
|
|
if (!isCXX && tok != "\"C\"")
|
|
|
|
setError("Unknown language");
|
|
|
|
expect("{");
|
|
|
|
|
2021-12-26 20:12:55 -08:00
|
|
|
SmallVector<SymbolVersion, 0> ret;
|
2024-07-26 17:25:23 -07:00
|
|
|
while (auto tok = till("}")) {
|
2019-07-03 06:11:50 +00:00
|
|
|
ret.push_back(
|
2024-07-26 17:25:23 -07:00
|
|
|
{unquote(tok), isCXX, !tok.str.starts_with("\"") && hasWildcard(tok)});
|
2018-02-01 23:46:17 +00:00
|
|
|
if (consume("}"))
|
|
|
|
return ret;
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(";");
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-06 11:49:58 -08:00
|
|
|
Expr ScriptParser::readMemoryAssignment(StringRef s1, StringRef s2,
|
|
|
|
StringRef s3) {
|
2017-04-05 05:40:21 +00:00
|
|
|
if (!consume(s1) && !consume(s2) && !consume(s3)) {
|
2017-04-05 05:07:39 +00:00
|
|
|
setError("expected one of: " + s1 + ", " + s2 + ", or " + s3);
|
2020-03-06 11:49:58 -08:00
|
|
|
return [] { return 0; };
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
expect("=");
|
2020-03-06 11:49:58 -08:00
|
|
|
return readExpr();
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the MEMORY command as specified in:
|
|
|
|
// https://sourceware.org/binutils/docs/ld/MEMORY.html
|
|
|
|
//
|
|
|
|
// MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... }
|
|
|
|
void ScriptParser::readMemory() {
|
|
|
|
expect("{");
|
2024-07-26 17:13:37 -07:00
|
|
|
while (auto tok = till("}")) {
|
2018-10-12 17:07:32 +00:00
|
|
|
if (tok == "INCLUDE") {
|
|
|
|
readInclude();
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
|
|
|
uint32_t flags = 0;
|
2021-11-24 12:17:03 +07:00
|
|
|
uint32_t invFlags = 0;
|
2017-04-05 05:07:39 +00:00
|
|
|
uint32_t negFlags = 0;
|
2021-11-24 12:17:03 +07:00
|
|
|
uint32_t negInvFlags = 0;
|
2017-04-05 05:07:39 +00:00
|
|
|
if (consume("(")) {
|
2021-11-24 12:17:03 +07:00
|
|
|
readMemoryAttributes(flags, invFlags, negFlags, negInvFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(")");
|
|
|
|
}
|
|
|
|
expect(":");
|
|
|
|
|
2020-03-06 11:49:58 -08:00
|
|
|
Expr origin = readMemoryAssignment("ORIGIN", "org", "o");
|
2017-04-05 05:07:39 +00:00
|
|
|
expect(",");
|
2020-03-06 11:49:58 -08:00
|
|
|
Expr length = readMemoryAssignment("LENGTH", "len", "l");
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2017-09-08 08:23:15 +00:00
|
|
|
// Add the memory region to the region map.
|
2021-11-24 12:17:03 +07:00
|
|
|
MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, invFlags,
|
|
|
|
negFlags, negInvFlags);
|
2024-08-21 21:23:28 -07:00
|
|
|
if (!ctx.script->memoryRegions.insert({tok, mr}).second)
|
2018-10-12 17:07:32 +00:00
|
|
|
setError("region '" + tok + "' already defined");
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function parses the attributes used to match against section
|
|
|
|
// flags when placing output sections in a memory region. These flags
|
|
|
|
// are only used when an explicit memory region name is not used.
|
2021-11-24 12:17:03 +07:00
|
|
|
void ScriptParser::readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
|
|
|
|
uint32_t &negFlags,
|
|
|
|
uint32_t &negInvFlags) {
|
2017-04-05 05:07:39 +00:00
|
|
|
bool invert = false;
|
[Coding style change] Rename variables so that they start with a lowercase letter
This patch is mechanically generated by clang-llvm-rename tool that I wrote
using Clang Refactoring Engine just for creating this patch. You can see the
source code of the tool at https://reviews.llvm.org/D64123. There's no manual
post-processing; you can generate the same patch by re-running the tool against
lld's code base.
Here is the main discussion thread to change the LLVM coding style:
https://lists.llvm.org/pipermail/llvm-dev/2019-February/130083.html
In the discussion thread, I proposed we use lld as a testbed for variable
naming scheme change, and this patch does that.
I chose to rename variables so that they are in camelCase, just because that
is a minimal change to make variables to start with a lowercase letter.
Note to downstream patch maintainers: if you are maintaining a downstream lld
repo, just rebasing ahead of this commit would cause massive merge conflicts
because this patch essentially changes every line in the lld subdirectory. But
there's a remedy.
clang-llvm-rename tool is a batch tool, so you can rename variables in your
downstream repo with the tool. Given that, here is how to rebase your repo to
a commit after the mass renaming:
1. rebase to the commit just before the mass variable renaming,
2. apply the tool to your downstream repo to mass-rename variables locally, and
3. rebase again to the head.
Most changes made by the tool should be identical for a downstream repo and
for the head, so at the step 3, almost all changes should be merged and
disappear. I'd expect that there would be some lines that you need to merge by
hand, but that shouldn't be too many.
Differential Revision: https://reviews.llvm.org/D64121
llvm-svn: 365595
2019-07-10 05:00:37 +00:00
|
|
|
|
2017-04-05 05:07:39 +00:00
|
|
|
for (char c : next().lower()) {
|
2021-11-24 12:17:03 +07:00
|
|
|
if (c == '!') {
|
2017-04-05 05:07:39 +00:00
|
|
|
invert = !invert;
|
2021-11-24 12:17:03 +07:00
|
|
|
std::swap(flags, negFlags);
|
|
|
|
std::swap(invFlags, negInvFlags);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == 'w')
|
|
|
|
flags |= SHF_WRITE;
|
2017-04-05 05:07:39 +00:00
|
|
|
else if (c == 'x')
|
2021-11-24 12:17:03 +07:00
|
|
|
flags |= SHF_EXECINSTR;
|
2017-04-05 05:07:39 +00:00
|
|
|
else if (c == 'a')
|
2021-11-24 12:17:03 +07:00
|
|
|
flags |= SHF_ALLOC;
|
|
|
|
else if (c == 'r')
|
|
|
|
invFlags |= SHF_WRITE;
|
|
|
|
else
|
2017-04-05 05:07:39 +00:00
|
|
|
setError("invalid memory region attribute");
|
2021-11-24 12:17:03 +07:00
|
|
|
}
|
2017-04-05 05:07:39 +00:00
|
|
|
|
2021-11-24 12:17:03 +07:00
|
|
|
if (invert) {
|
|
|
|
std::swap(flags, negFlags);
|
|
|
|
std::swap(invFlags, negInvFlags);
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-21 11:06:06 -07:00
|
|
|
void elf::readLinkerScript(Ctx &ctx, MemoryBufferRef mb) {
|
2020-11-03 14:41:09 +00:00
|
|
|
llvm::TimeTraceScope timeScope("Read linker script",
|
|
|
|
mb.getBufferIdentifier());
|
2024-09-21 11:06:06 -07:00
|
|
|
ScriptParser(ctx, mb).readLinkerScript();
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:06:06 -07:00
|
|
|
void elf::readVersionScript(Ctx &ctx, MemoryBufferRef mb) {
|
2020-11-03 14:41:09 +00:00
|
|
|
llvm::TimeTraceScope timeScope("Read version script",
|
|
|
|
mb.getBufferIdentifier());
|
2024-09-21 11:06:06 -07:00
|
|
|
ScriptParser(ctx, mb).readVersionScript();
|
2017-04-05 05:07:39 +00:00
|
|
|
}
|
|
|
|
|
2024-09-21 11:06:06 -07:00
|
|
|
void elf::readDynamicList(Ctx &ctx, MemoryBufferRef mb) {
|
2020-11-03 14:41:09 +00:00
|
|
|
llvm::TimeTraceScope timeScope("Read dynamic list", mb.getBufferIdentifier());
|
2024-09-21 11:06:06 -07:00
|
|
|
ScriptParser(ctx, mb).readDynamicList();
|
2020-05-14 22:18:58 -07:00
|
|
|
}
|
2017-11-04 02:03:58 +00:00
|
|
|
|
2024-09-21 11:06:06 -07:00
|
|
|
void elf::readDefsym(Ctx &ctx, MemoryBufferRef mb) {
|
|
|
|
ScriptParser(ctx, mb).readDefsym();
|
|
|
|
}
|