[lld] 1978c21 - [ELF] ScriptLexer: generate tokens lazily
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 26 14:26:42 PDT 2024
Author: Fangrui Song
Date: 2024-07-26T14:26:38-07:00
New Revision: 1978c21d967a2cd2e11cd3b2147d135f4d9e680b
URL: https://github.com/llvm/llvm-project/commit/1978c21d967a2cd2e11cd3b2147d135f4d9e680b
DIFF: https://github.com/llvm/llvm-project/commit/1978c21d967a2cd2e11cd3b2147d135f4d9e680b.diff
LOG: [ELF] ScriptLexer: generate tokens lazily
The current tokenize-whole-file approach has a few limitations.
* Lack of state information: `maybeSplitExpr` is needed to parse
expressions. It's infeasible to add new states to behave more like GNU
ld.
* `readInclude` may insert tokens in the middle, leading to a time
complexity issue with N-nested `INCLUDE`.
* line/column information for diagnostics are inaccurate, especially
after an `INCLUDE`.
* `getLineNumber` cannot be made more efficient without significant code
complexity and memory consumption. https://reviews.llvm.org/D104137
The patch switches to a traditional lexer that generates tokens lazily.
* `atEOF` behavior is modified: we need to call `peek` to determine EOF.
* `peek` and `next` cannot call `setError` upon `atEOF`.
* Since `consume` no longer reports an error upon `atEOF`, the idiom `while (!errorCount() && !consume(")"))`
would cause a dead loop. Use `while (peek() != ")" && !atEOF()) { ... } expect(")")` instead.
* An include stack is introduced to handle `readInclude`. This can be
utilized to address #93947 properly.
* `tokens` and `pos` are removed.
* `commandString` is reimplemented. Since it is used in -Map output,
`\n` needs to be replaced with space.
Pull Request: https://github.com/llvm/llvm-project/pull/100493
Added:
Modified:
lld/ELF/ScriptLexer.cpp
lld/ELF/ScriptLexer.h
lld/ELF/ScriptParser.cpp
lld/test/ELF/linkerscript/invalid.test
lld/test/ELF/linkerscript/map-file.test
lld/test/ELF/linkerscript/map-file2.test
lld/test/ELF/linkerscript/unquoted.test
Removed:
################################################################################
diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index 40c4637004352..d3a1586332f99 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -36,12 +36,13 @@ using namespace llvm;
using namespace lld;
using namespace lld::elf;
+ScriptLexer::ScriptLexer(MemoryBufferRef mb) : curBuf(mb), mbs(1, mb) {}
+
// Returns a whole line containing the current token.
StringRef ScriptLexer::getLine() {
StringRef s = getCurrentMB().getBuffer();
- StringRef tok = tokens[pos - 1];
- size_t pos = s.rfind('\n', tok.data() - s.data());
+ size_t pos = s.rfind('\n', prevTok.data() - s.data());
if (pos != StringRef::npos)
s = s.substr(pos + 1);
return s.substr(0, s.find_first_of("\r\n"));
@@ -49,11 +50,10 @@ StringRef ScriptLexer::getLine() {
// Returns 1-based line number of the current token.
size_t ScriptLexer::getLineNumber() {
- if (pos == 0)
+ if (prevTok.empty())
return 1;
StringRef s = getCurrentMB().getBuffer();
- StringRef tok = tokens[pos - 1];
- const size_t tokOffset = tok.data() - s.data();
+ const size_t tokOffset = prevTok.data() - s.data();
// For the first token, or when going backwards, start from the beginning of
// the buffer. If this token is after the previous token, start from the
@@ -76,8 +76,7 @@ size_t ScriptLexer::getLineNumber() {
// Returns 0-based column number of the current token.
size_t ScriptLexer::getColumnNumber() {
- StringRef tok = tokens[pos - 1];
- return tok.data() - getLine().data();
+ return prevTok.data() - getLine().data();
}
std::string ScriptLexer::getCurrentLocation() {
@@ -85,31 +84,33 @@ std::string ScriptLexer::getCurrentLocation() {
return (filename + ":" + Twine(getLineNumber())).str();
}
-ScriptLexer::ScriptLexer(MemoryBufferRef mb) { tokenize(mb); }
-
// We don't want to record cascading errors. Keep only the first one.
void ScriptLexer::setError(const Twine &msg) {
if (errorCount())
return;
std::string s = (getCurrentLocation() + ": " + msg).str();
- if (pos)
+ if (prevTok.size())
s += "\n>>> " + getLine().str() + "\n>>> " +
std::string(getColumnNumber(), ' ') + "^";
error(s);
}
-// Split S into linker script tokens.
-void ScriptLexer::tokenize(MemoryBufferRef mb) {
- std::vector<StringRef> vec;
- mbs.push_back(mb);
- StringRef s = mb.getBuffer();
- StringRef begin = s;
-
+void ScriptLexer::lex() {
for (;;) {
+ StringRef &s = curBuf.s;
s = skipSpace(s);
- if (s.empty())
- break;
+ if (s.empty()) {
+ // If this buffer is from an INCLUDE command, switch to the "return
+ // value"; otherwise, mark EOF.
+ if (buffers.empty()) {
+ eof = true;
+ return;
+ }
+ curBuf = buffers.pop_back_val();
+ continue;
+ }
+ curTokState = inExpr;
// Quoted token. Note that double-quote characters are parts of a token
// because, in a glob match context, only unquoted tokens are interpreted
@@ -118,45 +119,53 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
if (s.starts_with("\"")) {
size_t e = s.find("\"", 1);
if (e == StringRef::npos) {
- StringRef filename = mb.getBufferIdentifier();
- size_t lineno = begin.substr(0, s.data() - begin.data()).count('\n');
- error(filename + ":" + Twine(lineno + 1) + ": unclosed quote");
+ size_t lineno =
+ StringRef(curBuf.begin, s.data() - curBuf.begin).count('\n');
+ error(curBuf.filename + ":" + Twine(lineno + 1) + ": unclosed quote");
return;
}
- vec.push_back(s.take_front(e + 1));
+ curTok = s.take_front(e + 1);
s = s.substr(e + 1);
- continue;
+ return;
}
// Some operators form separate tokens.
if (s.starts_with("<<=") || s.starts_with(">>=")) {
- vec.push_back(s.substr(0, 3));
+ curTok = s.substr(0, 3);
s = s.substr(3);
- continue;
+ return;
}
- if (s.size() > 1 && ((s[1] == '=' && strchr("*/+-<>&^|", s[0])) ||
- (s[0] == s[1] && strchr("<>&|", s[0])))) {
- vec.push_back(s.substr(0, 2));
+ if (s.size() > 1 && (s[1] == '=' && strchr("+-*/!&^|", s[0]))) {
+ curTok = s.substr(0, 2);
s = s.substr(2);
- continue;
+ return;
}
- // Unquoted token. This is more relaxed than tokens in C-like language,
- // so that you can write "file-name.cpp" as one bare token, for example.
- size_t pos = s.find_first_not_of(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-!^:");
+ // Unquoted token. The non-expression token is more relaxed than tokens in
+ // C-like languages, so that you can write "file-name.cpp" as one bare
+ // token.
+ size_t pos;
+ if (inExpr) {
+ pos = s.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$");
+ if (pos == 0 && s.size() >= 2 &&
+ ((s[0] == s[1] && strchr("<>&|", s[0])) ||
+ is_contained({"==", "!=", "<=", ">=", "<<", ">>"}, s.substr(0, 2))))
+ pos = 2;
+ } else {
+ pos = s.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$/\\~=+[]*?-!^:");
+ }
- // A character that cannot start a word (which is usually a
- // punctuation) forms a single character token.
if (pos == 0)
pos = 1;
- vec.push_back(s.substr(0, pos));
+ curTok = s.substr(0, pos);
s = s.substr(pos);
+ break;
}
-
- tokens.insert(tokens.begin() + pos, vec.begin(), vec.end());
}
// Skip leading whitespace characters or comments.
@@ -185,93 +194,30 @@ StringRef ScriptLexer::skipSpace(StringRef s) {
}
}
-// An erroneous token is handled as if it were the last token before EOF.
-bool ScriptLexer::atEOF() { return errorCount() || tokens.size() == pos; }
-
-// Split a given string as an expression.
-// This function returns "3", "*" and "5" for "3*5" for example.
-static std::vector<StringRef> tokenizeExpr(StringRef s) {
- StringRef ops = "!~*/+-<>?^:="; // List of operators
-
- // Quoted strings are literal strings, so we don't want to split it.
- if (s.starts_with("\""))
- return {s};
-
- // Split S with operators as separators.
- std::vector<StringRef> ret;
- while (!s.empty()) {
- size_t e = s.find_first_of(ops);
-
- // No need to split if there is no operator.
- if (e == StringRef::npos) {
- ret.push_back(s);
- break;
- }
-
- // Get a token before the operator.
- if (e != 0)
- ret.push_back(s.substr(0, e));
-
- // Get the operator as a token.
- // Keep !=, ==, >=, <=, << and >> operators as a single tokens.
- if (s.substr(e).starts_with("!=") || s.substr(e).starts_with("==") ||
- s.substr(e).starts_with(">=") || s.substr(e).starts_with("<=") ||
- s.substr(e).starts_with("<<") || s.substr(e).starts_with(">>")) {
- ret.push_back(s.substr(e, 2));
- s = s.substr(e + 2);
- } else {
- ret.push_back(s.substr(e, 1));
- s = s.substr(e + 1);
- }
- }
- return ret;
-}
-
-// In contexts where expressions are expected, the lexer should apply
-//
diff erent tokenization rules than the default one. By default,
-// arithmetic operator characters are regular characters, but in the
-// expression context, they should be independent tokens.
-//
-// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
-// in the expression context.
-//
-// This function may split the current token into multiple tokens.
-void ScriptLexer::maybeSplitExpr() {
- if (!inExpr || errorCount() || atEOF())
- return;
-
- std::vector<StringRef> v = tokenizeExpr(tokens[pos]);
- if (v.size() == 1)
- return;
- tokens.erase(tokens.begin() + pos);
- tokens.insert(tokens.begin() + pos, v.begin(), v.end());
-}
+// Used to determine whether to stop parsing. Treat errors like EOF.
+bool ScriptLexer::atEOF() { return eof || errorCount(); }
StringRef ScriptLexer::next() {
- maybeSplitExpr();
-
- if (errorCount())
- return "";
- if (atEOF()) {
- setError("unexpected EOF");
- return "";
- }
- return tokens[pos++];
+ prevTok = peek();
+ return std::exchange(curTok, StringRef(curBuf.s.data(), 0));
}
StringRef ScriptLexer::peek() {
- StringRef tok = next();
- if (errorCount())
- return "";
- pos = pos - 1;
- return tok;
+ // curTok is invalid if curTokState and inExpr mismatch.
+ if (curTok.size() && curTokState != inExpr) {
+ curBuf.s = StringRef(curTok.data(), curBuf.s.end() - curTok.data());
+ curTok = {};
+ }
+ if (curTok.empty())
+ lex();
+ return curTok;
}
bool ScriptLexer::consume(StringRef tok) {
- if (next() == tok)
- return true;
- --pos;
- return false;
+ if (peek() != tok)
+ return false;
+ next();
+ return true;
}
void ScriptLexer::skip() { (void)next(); }
@@ -280,8 +226,12 @@ void ScriptLexer::expect(StringRef expect) {
if (errorCount())
return;
StringRef tok = next();
- if (tok != expect)
- setError(expect + " expected, but got " + tok);
+ if (tok != expect) {
+ if (atEOF())
+ setError("unexpected EOF");
+ else
+ setError(expect + " expected, but got " + tok);
+ }
}
// Returns true if S encloses T.
@@ -292,10 +242,8 @@ static bool encloses(StringRef s, StringRef t) {
MemoryBufferRef ScriptLexer::getCurrentMB() {
// Find input buffer containing the current token.
assert(!mbs.empty());
- if (pos == 0)
- return mbs.back();
for (MemoryBufferRef mb : mbs)
- if (encloses(mb.getBuffer(), tokens[pos - 1]))
+ if (encloses(mb.getBuffer(), curBuf.s))
return mb;
llvm_unreachable("getCurrentMB: failed to find a token");
}
diff --git a/lld/ELF/ScriptLexer.h b/lld/ELF/ScriptLexer.h
index 7d945d8f570c3..7651908d60200 100644
--- a/lld/ELF/ScriptLexer.h
+++ b/lld/ELF/ScriptLexer.h
@@ -10,6 +10,7 @@
#define LLD_ELF_SCRIPT_LEXER_H
#include "lld/Common/LLVM.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBufferRef.h"
#include <vector>
@@ -17,11 +18,35 @@
namespace lld::elf {
class ScriptLexer {
+protected:
+ struct Buffer {
+ // The remaining content to parse and the filename.
+ StringRef s, filename;
+ const char *begin = nullptr;
+ Buffer() = default;
+ Buffer(MemoryBufferRef mb)
+ : s(mb.getBuffer()), filename(mb.getBufferIdentifier()),
+ begin(mb.getBufferStart()) {}
+ };
+ // The current buffer and parent buffers due to INCLUDE.
+ Buffer curBuf;
+ SmallVector<Buffer, 0> buffers;
+
+ // The token before the last next().
+ StringRef prevTok;
+ // Rules for what is a token are
diff erent when we are in an expression.
+ // curTok holds the cached return value of peek() and is invalid when the
+ // expression state changes.
+ StringRef curTok;
+ // The inExpr state when curTok is cached.
+ bool curTokState = false;
+ bool eof = false;
+
public:
explicit ScriptLexer(MemoryBufferRef mb);
void setError(const Twine &msg);
- void tokenize(MemoryBufferRef mb);
+ void lex();
StringRef skipSpace(StringRef s);
bool atEOF();
StringRef next();
@@ -33,15 +58,12 @@ class ScriptLexer {
MemoryBufferRef getCurrentMB();
std::vector<MemoryBufferRef> mbs;
- std::vector<StringRef> tokens;
bool inExpr = false;
- size_t pos = 0;
size_t lastLineNumber = 0;
size_t lastLineNumberOffset = 0;
private:
- void maybeSplitExpr();
StringRef getLine();
size_t getLineNumber();
size_t getColumnNumber();
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 8637a8b0b2167..7303bb564afad 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -200,8 +200,9 @@ void ScriptParser::readDynamicList() {
std::tie(locals, globals) = readSymbols();
expect(";");
- if (!atEOF()) {
- setError("EOF expected, but got " + next());
+ StringRef tok = peek();
+ if (tok.size()) {
+ setError("EOF expected, but got " + tok);
return;
}
if (!locals.empty()) {
@@ -215,8 +216,9 @@ void ScriptParser::readDynamicList() {
void ScriptParser::readVersionScript() {
readVersionScriptCommand();
- if (!atEOF())
- setError("EOF expected, but got " + next());
+ StringRef tok = peek();
+ if (tok.size())
+ setError("EOF expected, but got " + tok);
}
void ScriptParser::readVersionScriptCommand() {
@@ -225,7 +227,9 @@ void ScriptParser::readVersionScriptCommand() {
return;
}
- while (!atEOF() && !errorCount() && peek() != "}") {
+ if (atEOF())
+ setError("unexpected EOF");
+ while (peek() != "}" && !atEOF()) {
StringRef verStr = next();
if (verStr == "{") {
setError("anonymous version definition is used in "
@@ -246,6 +250,8 @@ void ScriptParser::readVersion() {
void ScriptParser::readLinkerScript() {
while (!atEOF()) {
StringRef tok = next();
+ if (atEOF())
+ break;
if (tok == ";")
continue;
@@ -307,8 +313,9 @@ void ScriptParser::readDefsym(StringRef name) {
void ScriptParser::readNoCrossRefs(bool to) {
expect("(");
NoCrossRefCommand cmd{{}, to};
- while (!errorCount() && !consume(")"))
+ while (peek() != ")" && !atEOF())
cmd.outputSections.push_back(unquote(next()));
+ expect(")");
if (cmd.outputSections.size() < 2)
warn(getCurrentLocation() + ": ignored with fewer than 2 output sections");
else
@@ -368,9 +375,10 @@ void ScriptParser::readAsNeeded() {
expect("(");
bool orig = config->asNeeded;
config->asNeeded = true;
- while (!errorCount() && !consume(")"))
+ while (peek() != ")" && !atEOF())
addFile(unquote(next()));
config->asNeeded = orig;
+ expect(")");
}
void ScriptParser::readEntry() {
@@ -384,8 +392,9 @@ void ScriptParser::readEntry() {
void ScriptParser::readExtern() {
expect("(");
- while (!errorCount() && !consume(")"))
+ while (peek() != ")" && !atEOF())
config->undefined.push_back(unquote(next()));
+ expect(")");
}
void ScriptParser::readGroup() {
@@ -406,8 +415,11 @@ void ScriptParser::readInclude() {
}
if (std::optional<std::string> path = searchScript(tok)) {
- if (std::optional<MemoryBufferRef> mb = readFile(*path))
- tokenize(*mb);
+ if (std::optional<MemoryBufferRef> mb = readFile(*path)) {
+ buffers.push_back(curBuf);
+ curBuf = Buffer(*mb);
+ mbs.push_back(*mb);
+ }
return;
}
setError("cannot find linker script " + tok);
@@ -415,12 +427,13 @@ void ScriptParser::readInclude() {
void ScriptParser::readInput() {
expect("(");
- while (!errorCount() && !consume(")")) {
+ while (peek() != ")" && !atEOF()) {
if (consume("AS_NEEDED"))
readAsNeeded();
else
addFile(unquote(next()));
}
+ expect(")");
}
void ScriptParser::readOutput() {
@@ -435,8 +448,8 @@ void ScriptParser::readOutput() {
void ScriptParser::readOutputArch() {
// OUTPUT_ARCH is ignored for now.
expect("(");
- while (!errorCount() && !consume(")"))
- skip();
+ while (next() != ")" && !atEOF())
+ ;
}
static std::pair<ELFKind, uint16_t> parseBfdName(StringRef s) {
@@ -702,8 +715,9 @@ static int precedence(StringRef op) {
StringMatcher ScriptParser::readFilePatterns() {
StringMatcher Matcher;
- while (!errorCount() && !consume(")"))
+ while (peek() != ")" && !atEOF())
Matcher.addPattern(SingleStringMatcher(next()));
+ expect(")");
return Matcher;
}
@@ -790,7 +804,7 @@ ScriptParser::readInputSectionRules(StringRef filePattern, uint64_t withFlags,
make<InputSectionDescription>(filePattern, withFlags, withoutFlags);
expect("(");
- while (!errorCount() && !consume(")")) {
+ while (peek() != ")" && !atEOF()) {
SortSectionPolicy outer = readSortKind();
SortSectionPolicy inner = SortSectionPolicy::Default;
SmallVector<SectionPattern, 0> v;
@@ -816,6 +830,7 @@ ScriptParser::readInputSectionRules(StringRef filePattern, uint64_t withFlags,
std::move(v.begin(), v.end(), std::back_inserter(cmd->sectionPatterns));
}
+ expect(")");
return cmd;
}
@@ -1098,12 +1113,23 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
return cmd;
}
+// 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());
+}
+
SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
// Assert expression returns Dot, so this is equal to ".=."
if (tok == "ASSERT")
return make<SymbolAssignment>(".", readAssert(), 0, getCurrentLocation());
- size_t oldPos = pos;
+ const char *oldS = prevTok.data();
SymbolAssignment *cmd = nullptr;
bool savedSeenRelroEnd = script->seenRelroEnd;
const StringRef op = peek();
@@ -1127,9 +1153,8 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
if (cmd) {
cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && script->seenRelroEnd;
- cmd->commandString =
- tok.str() + " " +
- llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " ");
+ cmd->commandString = StringRef(oldS, curTok.data() - oldS).str();
+ squeezeSpaces(cmd->commandString);
expect(";");
}
return cmd;
@@ -1333,12 +1358,11 @@ ByteCommand *ScriptParser::readByteCommand(StringRef tok) {
if (size == -1)
return nullptr;
- size_t oldPos = pos;
+ const char *oldS = prevTok.data();
Expr e = readParenExpr();
- std::string commandString =
- tok.str() + " " +
- llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " ");
- return make<ByteCommand>(e, size, commandString);
+ std::string commandString = StringRef(oldS, curBuf.s.data() - oldS).str();
+ squeezeSpaces(commandString);
+ return make<ByteCommand>(e, size, std::move(commandString));
}
static std::optional<uint64_t> parseFlag(StringRef tok) {
diff --git a/lld/test/ELF/linkerscript/invalid.test b/lld/test/ELF/linkerscript/invalid.test
index 4cbedf639cb1a..73b761ce4d571 100644
--- a/lld/test/ELF/linkerscript/invalid.test
+++ b/lld/test/ELF/linkerscript/invalid.test
@@ -15,7 +15,7 @@
# RUN: echo foobar > %t1
# RUN: not ld.lld %t1 no-such-file 2>&1 | FileCheck -check-prefix=ERR1 %s
-# ERR1: unexpected EOF
+# ERR1: error: {{.*}}1:1: unknown directive: foobar
# ERR1: cannot open no-such-file:
# RUN: echo "foo \"bar" > %t2
diff --git a/lld/test/ELF/linkerscript/map-file.test b/lld/test/ELF/linkerscript/map-file.test
index 6ec8bafc42b16..6347c3a5d900a 100644
--- a/lld/test/ELF/linkerscript/map-file.test
+++ b/lld/test/ELF/linkerscript/map-file.test
@@ -7,17 +7,17 @@
# RUN: FileCheck -strict-whitespace %s < %t.map
SECTIONS {
- . = 0x1000;
+ . = 0x1000; # tabs
.foo : {
- BYTE(0x11)
- SHORT(0x1122)
+ BYTE ( 0x11 )
+ SHORT (0x1122)
LONG(0x11223344)
QUAD(0x1122334455667788)
PROVIDE_HIDDEN(sym4 = .);
. += 0x1000;
*(.foo.1)
PROVIDE(unused1 = 0xff);
- HIDDEN(sym6 = .);
+ HIDDEN( sym6 = . );
. += 0x123 *
(1 + 1);
foo = .;
@@ -34,20 +34,20 @@ SECTIONS {
# CHECK-NEXT: 0 0 1000 1 . = 0x1000
# CHECK-NEXT: 1000 1000 125d 1 .foo
# CHECK-NEXT: 1000 1000 1 1 BYTE ( 0x11 )
-# CHECK-NEXT: 1001 1001 2 1 SHORT ( 0x1122 )
-# CHECK-NEXT: 1003 1003 4 1 LONG ( 0x11223344 )
-# CHECK-NEXT: 1007 1007 8 1 QUAD ( 0x1122334455667788 )
-# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN ( sym4 = . )
+# CHECK-NEXT: 1001 1001 2 1 SHORT (0x1122)
+# CHECK-NEXT: 1003 1003 4 1 LONG(0x11223344)
+# CHECK-NEXT: 1007 1007 8 1 QUAD(0x1122334455667788)
+# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN(sym4 = .)
# CHECK-NEXT: 100f 100f 1000 1 . += 0x1000
# CHECK-NEXT: 200f 200f 8 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1)
-# CHECK-NEXT: 2017 2017 0 1 HIDDEN ( sym6 = . )
-# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * ( 1 + 1 )
+# CHECK-NEXT: 2017 2017 0 1 HIDDEN( sym6 = . )
+# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * (1 + 1)
# CHECK-NEXT: 225d 225d 0 1 foo = .
# CHECK-NEXT: 225d 225d 0 1 bar = 0x42 - 0x26
# CHECK-NEXT: 225d 225d 0 1 sym1 = .
# CHECK-NEXT: 225d 225d 500 1 . += 0x500
# CHECK-NEXT: 275d 275d 0 1 sym2 = .
-# CHECK-NEXT: 275d 275d 0 1 PROVIDE ( sym3 = 42 )
+# CHECK-NEXT: 275d 275d 0 1 PROVIDE(sym3 = 42)
# CHECK-NEXT: 2760 2760 10 4 .text
# CHECK-NEXT: 2760 2760 10 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text)
# CHECK-NEXT: 0 0 8 1 .comment
diff --git a/lld/test/ELF/linkerscript/map-file2.test b/lld/test/ELF/linkerscript/map-file2.test
index 8efb5d6cd3d34..a34595f14856e 100644
--- a/lld/test/ELF/linkerscript/map-file2.test
+++ b/lld/test/ELF/linkerscript/map-file2.test
@@ -27,7 +27,7 @@ SECTIONS {
# CHECK-NEXT: 1010 3000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ccc)
# CHECK-NEXT: 1018 3008 100 1 . += 0x100
# CHECK-NEXT: 1118 3108 109 1 .ddd
-# CHECK-NEXT: 1118 3108 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1118 3108 1 1 BYTE(0x11)
# CHECK-NEXT: 1119 3109 100 1 . += 0x100
# CHECK-NEXT: 1219 3209 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd)
# CHECK-NEXT: 1228 3218 34 8 .eh_frame
diff --git a/lld/test/ELF/linkerscript/unquoted.test b/lld/test/ELF/linkerscript/unquoted.test
index 7dca75fe09ab1..9a30ae8a37ff7 100644
--- a/lld/test/ELF/linkerscript/unquoted.test
+++ b/lld/test/ELF/linkerscript/unquoted.test
@@ -12,11 +12,10 @@ INCLUDE "empty.lds"
INCLUDE "1.lds"
# RUN: not ld.lld -shared 0.o -T 1.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
-# RUN: not ld.lld -shared 0.o -T 1a.lds 2>&1 | FileCheck %s --check-prefix=CHECK1A --match-full-lines --strict-whitespace
-# CHECK1:{{.*}}error: 1.lds:1: unclosed comment in a linker script
-# CHECK1A:{{.*}}error: 1a.lds:3: unclosed comment in a linker script
-#CHECK1A-NEXT:>>> INCLUDE "1.lds"
-#CHECK1A-NEXT:>>> ^
+# RUN: not ld.lld -shared 0.o -T 1a.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
+# CHECK1:{{.*}}error: 1.lds:2: unclosed comment in a linker script
+# CHECK1-NEXT:>>> SECTIONS /*
+# CHECK1-NEXT:>>> ^
#--- 2.lds
INCLUDE "empty.lds"
More information about the llvm-commits
mailing list