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);
// 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("\""))
(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,
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)
// 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") {
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 != "=") {
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:
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");
boom ^temp : { *(.temp) }
}
-# CHECK: 8: malformed number: ^temp
+# CHECK: 8: malformed number: ^
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
boom ^temp : { *(.temp) }
}
-# CHECK: 9: malformed number: ^temp
+# CHECK: 9: malformed number: ^{{$}}
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
boom ^temp : { *(.temp) }
}
-# CHECK: 9: malformed number: ^temp
+# CHECK: 9: malformed number: ^
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
# CHECK-NEXT: >>> ^
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;
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)))));
# 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
# 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
# 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{{$}}