update embedded LLD to 7.0.0rc1
This commit is contained in:
291
deps/lld/ELF/ScriptParser.cpp
vendored
291
deps/lld/ELF/ScriptParser.cpp
vendored
@@ -63,6 +63,7 @@ private:
|
||||
void readExtern();
|
||||
void readGroup();
|
||||
void readInclude();
|
||||
void readInput();
|
||||
void readMemory();
|
||||
void readOutput();
|
||||
void readOutputArch();
|
||||
@@ -74,12 +75,14 @@ private:
|
||||
void readVersion();
|
||||
void readVersionScriptCommand();
|
||||
|
||||
SymbolAssignment *readAssignment(StringRef Name);
|
||||
SymbolAssignment *readSymbolAssignment(StringRef Name);
|
||||
ByteCommand *readByteCommand(StringRef Tok);
|
||||
uint32_t readFill();
|
||||
uint32_t parseFill(StringRef Tok);
|
||||
void readSectionAddressType(OutputSection *Cmd);
|
||||
OutputSection *readOverlaySectionDescription();
|
||||
OutputSection *readOutputSectionDescription(StringRef OutSec);
|
||||
std::vector<BaseCommand *> readOverlay();
|
||||
std::vector<StringRef> readOutputSectionPhdrs();
|
||||
InputSectionDescription *readInputSectionDescription(StringRef Tok);
|
||||
StringMatcher readFilePatterns();
|
||||
@@ -88,16 +91,16 @@ private:
|
||||
unsigned readPhdrType();
|
||||
SortSectionPolicy readSortKind();
|
||||
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
|
||||
SymbolAssignment *readProvideOrAssignment(StringRef Tok);
|
||||
SymbolAssignment *readAssignment(StringRef Tok);
|
||||
void readSort();
|
||||
AssertCommand *readAssert();
|
||||
Expr readAssertExpr();
|
||||
Expr readAssert();
|
||||
Expr readConstant();
|
||||
Expr getPageSize();
|
||||
|
||||
uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
|
||||
std::pair<uint32_t, uint32_t> readMemoryAttributes();
|
||||
|
||||
Expr combine(StringRef Op, Expr L, Expr R);
|
||||
Expr readExpr();
|
||||
Expr readExpr1(Expr Lhs, int MinPrec);
|
||||
StringRef readParenLiteral();
|
||||
@@ -157,17 +160,6 @@ static ExprValue sub(ExprValue A, ExprValue B) {
|
||||
return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc};
|
||||
}
|
||||
|
||||
static ExprValue mul(ExprValue A, ExprValue B) {
|
||||
return A.getValue() * B.getValue();
|
||||
}
|
||||
|
||||
static ExprValue div(ExprValue A, ExprValue B) {
|
||||
if (uint64_t BV = B.getValue())
|
||||
return A.getValue() / BV;
|
||||
error("division by zero");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ExprValue bitAnd(ExprValue A, ExprValue B) {
|
||||
moveAbsRight(A, B);
|
||||
return {A.Sec, A.ForceAbsolute,
|
||||
@@ -237,16 +229,16 @@ void ScriptParser::readLinkerScript() {
|
||||
if (Tok == ";")
|
||||
continue;
|
||||
|
||||
if (Tok == "ASSERT") {
|
||||
Script->SectionCommands.push_back(readAssert());
|
||||
} else if (Tok == "ENTRY") {
|
||||
if (Tok == "ENTRY") {
|
||||
readEntry();
|
||||
} else if (Tok == "EXTERN") {
|
||||
readExtern();
|
||||
} else if (Tok == "GROUP" || Tok == "INPUT") {
|
||||
} else if (Tok == "GROUP") {
|
||||
readGroup();
|
||||
} else if (Tok == "INCLUDE") {
|
||||
readInclude();
|
||||
} else if (Tok == "INPUT") {
|
||||
readInput();
|
||||
} else if (Tok == "MEMORY") {
|
||||
readMemory();
|
||||
} else if (Tok == "OUTPUT") {
|
||||
@@ -265,7 +257,7 @@ void ScriptParser::readLinkerScript() {
|
||||
readSections();
|
||||
} else if (Tok == "VERSION") {
|
||||
readVersion();
|
||||
} else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
|
||||
} else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
|
||||
Script->SectionCommands.push_back(Cmd);
|
||||
} else {
|
||||
setError("unknown directive: " + Tok);
|
||||
@@ -336,13 +328,12 @@ void ScriptParser::readExtern() {
|
||||
}
|
||||
|
||||
void ScriptParser::readGroup() {
|
||||
expect("(");
|
||||
while (!errorCount() && !consume(")")) {
|
||||
if (consume("AS_NEEDED"))
|
||||
readAsNeeded();
|
||||
else
|
||||
addFile(unquote(next()));
|
||||
}
|
||||
bool Orig = InputFile::IsInGroup;
|
||||
InputFile::IsInGroup = true;
|
||||
readInput();
|
||||
InputFile::IsInGroup = Orig;
|
||||
if (!Orig)
|
||||
++InputFile::NextGroupId;
|
||||
}
|
||||
|
||||
void ScriptParser::readInclude() {
|
||||
@@ -353,7 +344,7 @@ void ScriptParser::readInclude() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Optional<std::string> Path = searchLinkerScript(Tok)) {
|
||||
if (Optional<std::string> Path = searchScript(Tok)) {
|
||||
if (Optional<MemoryBufferRef> MB = readFile(*Path))
|
||||
tokenize(*MB);
|
||||
return;
|
||||
@@ -361,6 +352,16 @@ void ScriptParser::readInclude() {
|
||||
setError("cannot find linker script " + Tok);
|
||||
}
|
||||
|
||||
void ScriptParser::readInput() {
|
||||
expect("(");
|
||||
while (!errorCount() && !consume(")")) {
|
||||
if (consume("AS_NEEDED"))
|
||||
readAsNeeded();
|
||||
else
|
||||
addFile(unquote(next()));
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptParser::readOutput() {
|
||||
// -o <file> takes predecence over OUTPUT(<file>).
|
||||
expect("(");
|
||||
@@ -437,6 +438,49 @@ void ScriptParser::readSearchDir() {
|
||||
expect(")");
|
||||
}
|
||||
|
||||
// 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
|
||||
std::vector<BaseCommand *> ScriptParser::readOverlay() {
|
||||
// VA and LMA expressions are optional, though for simplicity of
|
||||
// implementation we assume they are not. That is what OVERLAY was designed
|
||||
// for first of all: to allow sections with overlapping VAs at different LMAs.
|
||||
Expr AddrExpr = readExpr();
|
||||
expect(":");
|
||||
expect("AT");
|
||||
Expr LMAExpr = readParenExpr();
|
||||
expect("{");
|
||||
|
||||
std::vector<BaseCommand *> V;
|
||||
OutputSection *Prev = nullptr;
|
||||
while (!errorCount() && !consume("}")) {
|
||||
// VA is the same for all sections. The LMAs are consecutive in memory
|
||||
// starting from the base load address specified.
|
||||
OutputSection *OS = readOverlaySectionDescription();
|
||||
OS->AddrExpr = AddrExpr;
|
||||
if (Prev)
|
||||
OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; };
|
||||
else
|
||||
OS->LMAExpr = LMAExpr;
|
||||
V.push_back(OS);
|
||||
Prev = OS;
|
||||
}
|
||||
|
||||
// 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;
|
||||
for (BaseCommand *Cmd : V)
|
||||
Max = std::max(Max, cast<OutputSection>(Cmd)->Size);
|
||||
return AddrExpr().getValue() + Max;
|
||||
};
|
||||
V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation()));
|
||||
return V;
|
||||
}
|
||||
|
||||
void ScriptParser::readSections() {
|
||||
Script->HasSectionsCommand = true;
|
||||
|
||||
@@ -446,26 +490,48 @@ void ScriptParser::readSections() {
|
||||
Config->SingleRoRx = true;
|
||||
|
||||
expect("{");
|
||||
std::vector<BaseCommand *> V;
|
||||
while (!errorCount() && !consume("}")) {
|
||||
StringRef Tok = next();
|
||||
BaseCommand *Cmd = readProvideOrAssignment(Tok);
|
||||
if (!Cmd) {
|
||||
if (Tok == "ASSERT")
|
||||
Cmd = readAssert();
|
||||
else
|
||||
Cmd = readOutputSectionDescription(Tok);
|
||||
if (Tok == "OVERLAY") {
|
||||
for (BaseCommand *Cmd : readOverlay())
|
||||
V.push_back(Cmd);
|
||||
continue;
|
||||
}
|
||||
Script->SectionCommands.push_back(Cmd);
|
||||
|
||||
if (BaseCommand *Cmd = readAssignment(Tok))
|
||||
V.push_back(Cmd);
|
||||
else
|
||||
V.push_back(readOutputSectionDescription(Tok));
|
||||
}
|
||||
|
||||
if (!atEOF() && consume("INSERT")) {
|
||||
std::vector<BaseCommand *> *Dest = nullptr;
|
||||
if (consume("AFTER"))
|
||||
Dest = &Script->InsertAfterCommands[next()];
|
||||
else if (consume("BEFORE"))
|
||||
Dest = &Script->InsertBeforeCommands[next()];
|
||||
else
|
||||
setError("expected AFTER/BEFORE, but got '" + next() + "'");
|
||||
if (Dest)
|
||||
Dest->insert(Dest->end(), V.begin(), V.end());
|
||||
return;
|
||||
}
|
||||
|
||||
Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(),
|
||||
V.end());
|
||||
}
|
||||
|
||||
static int precedence(StringRef Op) {
|
||||
return StringSwitch<int>(Op)
|
||||
.Cases("*", "/", 5)
|
||||
.Cases("+", "-", 4)
|
||||
.Cases("<<", ">>", 3)
|
||||
.Cases("<", "<=", ">", ">=", "==", "!=", 2)
|
||||
.Cases("&", "|", 1)
|
||||
.Cases("*", "/", "%", 8)
|
||||
.Cases("+", "-", 7)
|
||||
.Cases("<<", ">>", 6)
|
||||
.Cases("<", "<=", ">", ">=", "==", "!=", 5)
|
||||
.Case("&", 4)
|
||||
.Case("|", 3)
|
||||
.Case("&&", 2)
|
||||
.Case("||", 1)
|
||||
.Default(-1);
|
||||
}
|
||||
|
||||
@@ -588,11 +654,7 @@ void ScriptParser::readSort() {
|
||||
expect(")");
|
||||
}
|
||||
|
||||
AssertCommand *ScriptParser::readAssert() {
|
||||
return make<AssertCommand>(readAssertExpr());
|
||||
}
|
||||
|
||||
Expr ScriptParser::readAssertExpr() {
|
||||
Expr ScriptParser::readAssert() {
|
||||
expect("(");
|
||||
Expr E = readExpr();
|
||||
expect(",");
|
||||
@@ -617,12 +679,14 @@ uint32_t ScriptParser::readFill() {
|
||||
return V;
|
||||
}
|
||||
|
||||
// Reads an expression and/or the special directive "(NOLOAD)" for an
|
||||
// output section definition.
|
||||
// Reads an expression and/or the special directive for an output
|
||||
// section definition. Directive is one of following: "(NOLOAD)",
|
||||
// "(COPY)", "(INFO)" or "(OVERLAY)".
|
||||
//
|
||||
// An output section name can be followed by an address expression
|
||||
// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be
|
||||
// interpreted as either the beginning of some expression or "(NOLOAD)".
|
||||
// and/or directive. This grammar is not LL(1) because "(" can be
|
||||
// interpreted as either the beginning of some expression or beginning
|
||||
// of directive.
|
||||
//
|
||||
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
|
||||
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
|
||||
@@ -633,6 +697,11 @@ void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
|
||||
Cmd->Noload = true;
|
||||
return;
|
||||
}
|
||||
if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
|
||||
expect(")");
|
||||
Cmd->NonAlloc = true;
|
||||
return;
|
||||
}
|
||||
Cmd->AddrExpr = readExpr();
|
||||
expect(")");
|
||||
} else {
|
||||
@@ -657,10 +726,23 @@ static Expr checkAlignment(Expr E, std::string &Loc) {
|
||||
};
|
||||
}
|
||||
|
||||
OutputSection *ScriptParser::readOverlaySectionDescription() {
|
||||
OutputSection *Cmd =
|
||||
Script->createOutputSection(next(), getCurrentLocation());
|
||||
Cmd->InOverlay = true;
|
||||
expect("{");
|
||||
while (!errorCount() && !consume("}"))
|
||||
Cmd->SectionCommands.push_back(readInputSectionRules(next()));
|
||||
Cmd->Phdrs = readOutputSectionPhdrs();
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||
OutputSection *Cmd =
|
||||
Script->createOutputSection(OutSec, getCurrentLocation());
|
||||
|
||||
size_t SymbolsReferenced = Script->ReferencedSymbols.size();
|
||||
|
||||
if (peek() != ":")
|
||||
readSectionAddressType(Cmd);
|
||||
expect(":");
|
||||
@@ -684,13 +766,10 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||
StringRef Tok = next();
|
||||
if (Tok == ";") {
|
||||
// Empty commands are allowed. Do nothing here.
|
||||
} else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
|
||||
} else if (SymbolAssignment *Assign = readAssignment(Tok)) {
|
||||
Cmd->SectionCommands.push_back(Assign);
|
||||
} else if (ByteCommand *Data = readByteCommand(Tok)) {
|
||||
Cmd->SectionCommands.push_back(Data);
|
||||
} else if (Tok == "ASSERT") {
|
||||
Cmd->SectionCommands.push_back(readAssert());
|
||||
expect(";");
|
||||
} 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.
|
||||
@@ -727,6 +806,8 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
|
||||
// Consume optional comma following output section command.
|
||||
consume(",");
|
||||
|
||||
if (Script->ReferencedSymbols.size() > SymbolsReferenced)
|
||||
Cmd->ExpressionsUseSymbols = true;
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
@@ -749,30 +830,39 @@ uint32_t ScriptParser::parseFill(StringRef Tok) {
|
||||
|
||||
SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
|
||||
expect("(");
|
||||
SymbolAssignment *Cmd = readAssignment(next());
|
||||
SymbolAssignment *Cmd = readSymbolAssignment(next());
|
||||
Cmd->Provide = Provide;
|
||||
Cmd->Hidden = Hidden;
|
||||
expect(")");
|
||||
expect(";");
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
|
||||
SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) {
|
||||
// Assert expression returns Dot, so this is equal to ".=."
|
||||
if (Tok == "ASSERT")
|
||||
return make<SymbolAssignment>(".", readAssert(), getCurrentLocation());
|
||||
|
||||
size_t OldPos = Pos;
|
||||
SymbolAssignment *Cmd = nullptr;
|
||||
if (peek() == "=" || peek() == "+=") {
|
||||
Cmd = readAssignment(Tok);
|
||||
expect(";");
|
||||
} else if (Tok == "PROVIDE") {
|
||||
if (peek() == "=" || peek() == "+=")
|
||||
Cmd = readSymbolAssignment(Tok);
|
||||
else if (Tok == "PROVIDE")
|
||||
Cmd = readProvideHidden(true, false);
|
||||
} else if (Tok == "HIDDEN") {
|
||||
else if (Tok == "HIDDEN")
|
||||
Cmd = readProvideHidden(false, true);
|
||||
} else if (Tok == "PROVIDE_HIDDEN") {
|
||||
else if (Tok == "PROVIDE_HIDDEN")
|
||||
Cmd = readProvideHidden(true, true);
|
||||
|
||||
if (Cmd) {
|
||||
Cmd->CommandString =
|
||||
Tok.str() + " " +
|
||||
llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
|
||||
expect(";");
|
||||
}
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
|
||||
SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) {
|
||||
StringRef Op = next();
|
||||
assert(Op == "=" || Op == "+=");
|
||||
Expr E = readExpr();
|
||||
@@ -795,15 +885,31 @@ Expr ScriptParser::readExpr() {
|
||||
return E;
|
||||
}
|
||||
|
||||
static Expr combine(StringRef Op, Expr L, Expr R) {
|
||||
Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) {
|
||||
if (Op == "+")
|
||||
return [=] { return add(L(), R()); };
|
||||
if (Op == "-")
|
||||
return [=] { return sub(L(), R()); };
|
||||
if (Op == "*")
|
||||
return [=] { return mul(L(), R()); };
|
||||
if (Op == "/")
|
||||
return [=] { return div(L(), R()); };
|
||||
return [=] { return L().getValue() * R().getValue(); };
|
||||
if (Op == "/") {
|
||||
std::string Loc = getCurrentLocation();
|
||||
return [=]() -> uint64_t {
|
||||
if (uint64_t RV = R().getValue())
|
||||
return L().getValue() / RV;
|
||||
error(Loc + ": division by zero");
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
if (Op == "%") {
|
||||
std::string Loc = getCurrentLocation();
|
||||
return [=]() -> uint64_t {
|
||||
if (uint64_t RV = R().getValue())
|
||||
return L().getValue() % RV;
|
||||
error(Loc + ": modulo by zero");
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
if (Op == "<<")
|
||||
return [=] { return L().getValue() << R().getValue(); };
|
||||
if (Op == ">>")
|
||||
@@ -820,6 +926,10 @@ static Expr combine(StringRef Op, Expr L, Expr R) {
|
||||
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 bitAnd(L(), R()); };
|
||||
if (Op == "|")
|
||||
@@ -873,20 +983,13 @@ Expr ScriptParser::readConstant() {
|
||||
if (S == "MAXPAGESIZE")
|
||||
return [] { return Config->MaxPageSize; };
|
||||
setError("unknown constant: " + S);
|
||||
return {};
|
||||
return [] { return 0; };
|
||||
}
|
||||
|
||||
// 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.
|
||||
static Optional<uint64_t> parseInt(StringRef Tok) {
|
||||
// Negative number
|
||||
if (Tok.startswith("-")) {
|
||||
if (Optional<uint64_t> Val = parseInt(Tok.substr(1)))
|
||||
return -*Val;
|
||||
return None;
|
||||
}
|
||||
|
||||
// Hexadecimal
|
||||
uint64_t Val;
|
||||
if (Tok.startswith_lower("0x")) {
|
||||
@@ -925,7 +1028,13 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) {
|
||||
.Default(-1);
|
||||
if (Size == -1)
|
||||
return nullptr;
|
||||
return make<ByteCommand>(readParenExpr(), Size);
|
||||
|
||||
size_t OldPos = Pos;
|
||||
Expr E = readParenExpr();
|
||||
std::string CommandString =
|
||||
Tok.str() + " " +
|
||||
llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " ");
|
||||
return make<ByteCommand>(E, Size, CommandString);
|
||||
}
|
||||
|
||||
StringRef ScriptParser::readParenLiteral() {
|
||||
@@ -1006,7 +1115,7 @@ Expr ScriptParser::readPrimary() {
|
||||
};
|
||||
}
|
||||
if (Tok == "ASSERT")
|
||||
return readAssertExpr();
|
||||
return readAssert();
|
||||
if (Tok == "CONSTANT")
|
||||
return readConstant();
|
||||
if (Tok == "DATA_SEGMENT_ALIGN") {
|
||||
@@ -1043,8 +1152,10 @@ Expr ScriptParser::readPrimary() {
|
||||
}
|
||||
if (Tok == "LENGTH") {
|
||||
StringRef Name = readParenLiteral();
|
||||
if (Script->MemoryRegions.count(Name) == 0)
|
||||
if (Script->MemoryRegions.count(Name) == 0) {
|
||||
setError("memory region not defined: " + Name);
|
||||
return [] { return 0; };
|
||||
}
|
||||
return [=] { return Script->MemoryRegions[Name]->Length; };
|
||||
}
|
||||
if (Tok == "LOADADDR") {
|
||||
@@ -1055,10 +1166,22 @@ Expr ScriptParser::readPrimary() {
|
||||
return Cmd->getLMA();
|
||||
};
|
||||
}
|
||||
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()); };
|
||||
}
|
||||
if (Tok == "ORIGIN") {
|
||||
StringRef Name = readParenLiteral();
|
||||
if (Script->MemoryRegions.count(Name) == 0)
|
||||
if (Script->MemoryRegions.count(Name) == 0) {
|
||||
setError("memory region not defined: " + Name);
|
||||
return [] { return 0; };
|
||||
}
|
||||
return [=] { return Script->MemoryRegions[Name]->Origin; };
|
||||
}
|
||||
if (Tok == "SEGMENT_START") {
|
||||
@@ -1240,6 +1363,9 @@ ScriptParser::readSymbols() {
|
||||
|
||||
// Reads an "extern C++" directive, e.g.,
|
||||
// "extern "C++" { ns::*; "f(int, double)"; };"
|
||||
//
|
||||
// The last semicolon is optional. E.g. this is OK:
|
||||
// "extern "C++" { ns::*; "f(int, double)" };"
|
||||
std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
|
||||
StringRef Tok = next();
|
||||
bool IsCXX = Tok == "\"C++\"";
|
||||
@@ -1252,6 +1378,8 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
|
||||
StringRef Tok = next();
|
||||
bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
|
||||
Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
|
||||
if (consume("}"))
|
||||
return Ret;
|
||||
expect(";");
|
||||
}
|
||||
|
||||
@@ -1291,11 +1419,10 @@ void ScriptParser::readMemory() {
|
||||
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
|
||||
|
||||
// Add the memory region to the region map.
|
||||
if (Script->MemoryRegions.count(Name))
|
||||
setError("region '" + Name + "' already defined");
|
||||
MemoryRegion *MR =
|
||||
make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags);
|
||||
Script->MemoryRegions[Name] = MR;
|
||||
if (!Script->MemoryRegions.insert({Name, MR}).second)
|
||||
setError("region '" + Name + "' already defined");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user