[lld] fae9610 - [ELF] Support operator ^ and ^=
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 15 14:10:44 PDT 2023
Author: Fangrui Song
Date: 2023-07-15T14:10:40-07:00
New Revision: fae96104d4378166cbe5c875ef8ed808a356f3fb
URL: https://github.com/llvm/llvm-project/commit/fae96104d4378166cbe5c875ef8ed808a356f3fb
DIFF: https://github.com/llvm/llvm-project/commit/fae96104d4378166cbe5c875ef8ed808a356f3fb.diff
LOG: [ELF] Support operator ^ and ^=
GNU ld added ^ support in July 2023 and it looks like ^= is in plan as
well.
For now, we don't support `a^=0` (^= without a preceding space).
Added:
Modified:
lld/ELF/ScriptLexer.cpp
lld/ELF/ScriptParser.cpp
lld/test/ELF/linkerscript/diag3.test
lld/test/ELF/linkerscript/diag4.test
lld/test/ELF/linkerscript/diag5.test
lld/test/ELF/linkerscript/operators.test
Removed:
################################################################################
diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index a10927666dcdb6..14f39ed10e17c2 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -140,7 +140,7 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
s = s.substr(3);
continue;
}
- if (s.size() > 1 && ((s[1] == '=' && strchr("*/+-<>&|", s[0])) ||
+ if (s.size() > 1 && ((s[1] == '=' && strchr("*/+-<>&^|", s[0])) ||
(s[0] == s[1] && strchr("<>&|", s[0])))) {
vec.push_back(s.substr(0, 2));
s = s.substr(2);
@@ -196,7 +196,7 @@ 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
+ StringRef ops = "!~*/+-<>?^:="; // List of operators
// Quoted strings are literal strings, so we don't want to split it.
if (s.starts_with("\""))
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 9f20cefe4c5f42..dbe86beae59b67 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -177,6 +177,12 @@ static ExprValue bitAnd(ExprValue a, ExprValue b) {
(a.getValue() & b.getValue()) - a.getSecAddr(), a.loc};
}
+static ExprValue bitXor(ExprValue a, ExprValue b) {
+ moveAbsRight(a, b);
+ return {a.sec, a.forceAbsolute,
+ (a.getValue() ^ b.getValue()) - a.getSecAddr(), a.loc};
+}
+
static ExprValue bitOr(ExprValue a, ExprValue b) {
moveAbsRight(a, b);
return {a.sec, a.forceAbsolute,
@@ -638,12 +644,13 @@ void ScriptParser::readTarget() {
static int precedence(StringRef op) {
return StringSwitch<int>(op)
- .Cases("*", "/", "%", 10)
- .Cases("+", "-", 9)
- .Cases("<<", ">>", 8)
- .Cases("<", "<=", ">", ">=", 7)
- .Cases("==", "!=", 6)
- .Case("&", 5)
+ .Cases("*", "/", "%", 11)
+ .Cases("+", "-", 10)
+ .Cases("<<", ">>", 9)
+ .Cases("<", "<=", ">", ">=", 8)
+ .Cases("==", "!=", 7)
+ .Case("&", 6)
+ .Case("^", 5)
.Case("|", 4)
.Case("&&", 3)
.Case("||", 2)
@@ -1047,7 +1054,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
// Support = followed by an expression without whitespace.
SaveAndRestore saved(inExpr, true);
cmd = readSymbolAssignment(tok);
- } else if ((op.size() == 2 && op[1] == '=' && strchr("*/+-&|", op[0])) ||
+ } else if ((op.size() == 2 && op[1] == '=' && strchr("*/+-&^|", op[0])) ||
op == "<<=" || op == ">>=") {
cmd = readSymbolAssignment(tok);
} else if (tok == "PROVIDE") {
@@ -1074,7 +1081,7 @@ SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) {
name = unquote(name);
StringRef op = next();
assert(op == "=" || op == "*=" || op == "/=" || op == "+=" || op == "-=" ||
- op == "&=" || op == "|=" || op == "<<=" || op == ">>=");
+ op == "&=" || op == "^=" || op == "|=" || op == "<<=" || op == ">>=");
// Note: GNU ld does not support %= or ^=.
Expr e = readExpr();
if (op != "=") {
@@ -1099,6 +1106,8 @@ SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) {
return lhs.getValue() >> e().getValue() % 64;
case '&':
return lhs.getValue() & e().getValue();
+ case '^':
+ return lhs.getValue() ^ e().getValue();
case '|':
return lhs.getValue() | e().getValue();
default:
@@ -1168,6 +1177,8 @@ Expr ScriptParser::combine(StringRef op, Expr l, Expr r) {
return [=] { return l().getValue() && r().getValue(); };
if (op == "&")
return [=] { return bitAnd(l(), r()); };
+ if (op == "^")
+ return [=] { return bitXor(l(), r()); };
if (op == "|")
return [=] { return bitOr(l(), r()); };
llvm_unreachable("invalid operator");
diff --git a/lld/test/ELF/linkerscript/diag3.test b/lld/test/ELF/linkerscript/diag3.test
index 1e4371241f304a..1df8d601db0164 100644
--- a/lld/test/ELF/linkerscript/diag3.test
+++ b/lld/test/ELF/linkerscript/diag3.test
@@ -8,6 +8,6 @@ SECTIONS {
boom ^temp : { *(.temp) }
}
-# CHECK: 8: malformed number: ^temp
+# CHECK: 8: malformed number: ^
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
diff --git a/lld/test/ELF/linkerscript/diag4.test b/lld/test/ELF/linkerscript/diag4.test
index 15d81fdc2be4ad..d93a69a95c61dd 100644
--- a/lld/test/ELF/linkerscript/diag4.test
+++ b/lld/test/ELF/linkerscript/diag4.test
@@ -9,6 +9,6 @@ SECTIONS {
boom ^temp : { *(.temp) }
}
-# CHECK: 9: malformed number: ^temp
+# CHECK: 9: malformed number: ^{{$}}
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
diff --git a/lld/test/ELF/linkerscript/diag5.test b/lld/test/ELF/linkerscript/diag5.test
index 15d81fdc2be4ad..9a2304baa44131 100644
--- a/lld/test/ELF/linkerscript/diag5.test
+++ b/lld/test/ELF/linkerscript/diag5.test
@@ -9,6 +9,6 @@ SECTIONS {
boom ^temp : { *(.temp) }
}
-# CHECK: 9: malformed number: ^temp
+# CHECK: 9: malformed number: ^
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
diff --git a/lld/test/ELF/linkerscript/operators.test b/lld/test/ELF/linkerscript/operators.test
index 0b6fdc2fe63f8e..27209a2e40f598 100644
--- a/lld/test/ELF/linkerscript/operators.test
+++ b/lld/test/ELF/linkerscript/operators.test
@@ -21,6 +21,7 @@ SECTIONS {
neq = 1 != 1 <= 1 ? 1 : 2;
and = 3 & 4 > 0;
or = 0xbb & 0xee | 1;
+ xor = 3&3^5|1;
logicaland = (0 && 0) + (0&&1)*2 + (1&& 0)*4 + (1 &&1) *8;
logicaland2 = 1 & 0 && 1 | 1;
logicalor = (0 || 0) + (0||1)*2 + (1|| 0)*4 + (1 ||1) *8;
@@ -44,8 +45,13 @@ SECTIONS {
rshiftassign >>= 130; # arbitrarily reduced to 2
andassign = 6;
andassign &= 4;
+ andassign&=4;
+ xorassign = 6;
+ xorassign ^= 3;
+ xorassign ^=0;
orassign = 4;
orassign |= 1;
+ orassign|=1;
braces = 1 + (2 + 3) * 4;
precedence1 = 1|0xff&1/1<<1+1*2;
precedence2 = (1 | (0xff & (1 << (1 + (1 * 2)))));
@@ -85,6 +91,7 @@ SECTIONS {
# CHECK-NEXT: 0000000000000002 A neq
# CHECK-NEXT: 0000000000000001 A and
# CHECK-NEXT: 00000000000000ab A or
+# CHECK-NEXT: 0000000000000007 A xor
# CHECK-NEXT: 0000000000000008 A logicaland
# CHECK-NEXT: 0000000000000000 A logicaland2
# CHECK-NEXT: 000000000000000e A logicalor
@@ -98,6 +105,7 @@ SECTIONS {
# CHECK-NEXT: 0000000000000004 A lshiftassign
# CHECK-NEXT: 0000000000000003 A rshiftassign
# CHECK-NEXT: 0000000000000004 A andassign
+# CHECK-NEXT: 0000000000000005 A xorassign
# CHECK-NEXT: 0000000000000005 A orassign
# CHECK-NEXT: 0000000000000015 A braces
# CHECK-NEXT: 0000000000000009 A precedence1
@@ -165,10 +173,12 @@ SECTIONS {
# RUN: echo 'a = 1; a /= 0;' > %t.script
# RUN: not ld.lld %t.o -T %t.script -o /dev/null 2>&1 | FileCheck --check-prefix=DIVZERO %s
-## GNU ld does not support %= or ^=.
+## GNU ld does not support %=.
# RUN: echo 'a = 1; a %= 0;' > %t.script
-# RUN: not ld.lld %t.o -T %t.script -o /dev/null 2>&1 | FileCheck --check-prefix=UNKNOWN %s
-# RUN: echo 'a = 1; a ^= 0;' > %t.script
-# RUN: not ld.lld %t.o -T %t.script -o /dev/null 2>&1 | FileCheck --check-prefix=UNKNOWN %s
+# RUN: not ld.lld %t.o -T %t.script -o /dev/null 2>&1 | FileCheck --check-prefix=UNKNOWN1 %s
+## For now, we don't support ^= without a preceding space.
+# RUN: echo 'a = 1; a^=0;' > %t.script
+# RUN: not ld.lld %t.o -T %t.script -o /dev/null 2>&1 | FileCheck --check-prefix=UNKNOWN2 %s
-# UNKNOWN: error: {{.*}}:1: unknown directive: a
+# UNKNOWN1: error: {{.*}}:1: unknown directive: a{{$}}
+# UNKNOWN2: error: {{.*}}:1: unknown directive: a^=0{{$}}
More information about the llvm-commits
mailing list