[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).
This commit is contained in:
parent
6043d4dfec
commit
fae96104d4
@ -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("\""))
|
||||
|
@ -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");
|
||||
|
@ -8,6 +8,6 @@ SECTIONS {
|
||||
boom ^temp : { *(.temp) }
|
||||
}
|
||||
|
||||
# CHECK: 8: malformed number: ^temp
|
||||
# CHECK: 8: malformed number: ^
|
||||
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
|
||||
# CHECK-NEXT: >>> ^
|
||||
|
@ -9,6 +9,6 @@ SECTIONS {
|
||||
boom ^temp : { *(.temp) }
|
||||
}
|
||||
|
||||
# CHECK: 9: malformed number: ^temp
|
||||
# CHECK: 9: malformed number: ^{{$}}
|
||||
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
|
||||
# CHECK-NEXT: >>> ^
|
||||
|
@ -9,6 +9,6 @@ SECTIONS {
|
||||
boom ^temp : { *(.temp) }
|
||||
}
|
||||
|
||||
# CHECK: 9: malformed number: ^temp
|
||||
# CHECK: 9: malformed number: ^
|
||||
# CHECK-NEXT: >>> boom ^temp : { *(.temp) }
|
||||
# CHECK-NEXT: >>> ^
|
||||
|
@ -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{{$}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user