[lld] r266798 - ELF: Add +, -, *, / and & to SECTIONS linker script command.
Rui Ueyama via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 19 11:58:12 PDT 2016
Author: ruiu
Date: Tue Apr 19 13:58:11 2016
New Revision: 266798
URL: http://llvm.org/viewvc/llvm-project?rev=266798&view=rev
Log:
ELF: Add +, -, *, / and & to SECTIONS linker script command.
This patch is based heavily on George Rimor's patch
http://reviews.llvm.org/D19221.
In the linker script, you can write expressions to compute addresses.
Currently we only support "+" operator. This adds a few more operators.
Since this patch adds * and /, we need to handle operator precedences
properly. I implemented that using the operator-precedence grammar.
Differential Revision: http://reviews.llvm.org/D19237
Modified:
lld/trunk/ELF/LinkerScript.cpp
lld/trunk/ELF/LinkerScript.h
lld/trunk/test/ELF/linkerscript-locationcounter.s
Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=266798&r1=266797&r2=266798&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Tue Apr 19 13:58:11 2016
@@ -20,6 +20,7 @@
#include "OutputSections.h"
#include "ScriptParser.h"
#include "SymbolTable.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -43,27 +44,106 @@ static uint64_t getInteger(StringRef S)
return V;
}
-// Evaluates the expression given by list of tokens.
-uint64_t LinkerScript::evaluate(std::vector<StringRef> &Tokens,
- uint64_t LocCounter) {
- uint64_t Result = 0;
- for (size_t I = 0, E = Tokens.size(); I < E; ++I) {
- // Each second token should be '+' as this is the
- // only operator we support now.
- if (I % 2 == 1) {
- if (Tokens[I] == "+")
- continue;
- error("error in location counter expression");
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Case("*", 4)
+ .Case("/", 3)
+ .Case("+", 2)
+ .Case("-", 2)
+ .Case("&", 1)
+ .Default(-1);
+}
+
+static StringRef next(ArrayRef<StringRef> &Tokens) {
+ if (Tokens.empty()) {
+ error("no next token");
+ return "";
+ }
+ StringRef Tok = Tokens.front();
+ Tokens = Tokens.slice(1);
+ return Tok;
+}
+
+static uint64_t parseExpr(uint64_t Lhs, int MinPrec,
+ ArrayRef<StringRef> &Tokens, uint64_t Dot);
+
+// This is a part of the operator-precedence parser to evaluate
+// arithmetic expressions in SECTIONS command. This function evaluates an
+// integer literal, a parenthesized expression or the special variable ".".
+static uint64_t parsePrimary(ArrayRef<StringRef> &Tokens, uint64_t Dot) {
+ StringRef Tok = next(Tokens);
+ if (Tok == ".")
+ return Dot;
+ if (Tok == "(") {
+ uint64_t V = parsePrimary(Tokens, Dot);
+ V = parseExpr(V, 0, Tokens, Dot);
+ if (Tokens.empty()) {
+ error(") expected");
+ } else {
+ Tok = next(Tokens);
+ if (Tok != ")")
+ error(") expected, but got " + Tok);
+ }
+ return V;
+ }
+ return getInteger(Tok);
+}
+
+static uint64_t apply(StringRef Op, uint64_t L, uint64_t R) {
+ if (Op == "+")
+ return L + R;
+ if (Op == "-")
+ return L - R;
+ if (Op == "*")
+ return L * R;
+ if (Op == "/") {
+ if (R == 0) {
+ error("division by zero");
return 0;
}
+ return L / R;
+ }
+ if (Op == "&")
+ return L & R;
+ llvm_unreachable("unknown operator " + Op);
+ return 0;
+}
+
+// This is an operator-precedence parser to evaluate
+// arithmetic expressions in SECTIONS command.
+static uint64_t parseExpr(uint64_t Lhs, int MinPrec,
+ ArrayRef<StringRef> &Tokens, uint64_t Dot) {
+ while (!Tokens.empty()) {
+ // Read an operator and an expression.
+ StringRef Op1 = Tokens.front();
+ if (precedence(Op1) < MinPrec)
+ return Lhs;
+ next(Tokens);
+ uint64_t Rhs = parsePrimary(Tokens, Dot);
+
+ // Evaluate the remaining part of the expression first if the
+ // next operator has greater precedence than the previous one.
+ // For example, if we have read "+" and "3", and if the next
+ // operator is "*", then we'll evaluate 3 * ... part first.
+ while (!Tokens.empty()) {
+ StringRef Op2 = Tokens.front();
+ if (precedence(Op2) <= precedence(Op1))
+ break;
+ Rhs = parseExpr(Rhs, precedence(Op2), Tokens, Dot);
+ }
- StringRef Tok = Tokens[I];
- if (Tok == ".")
- Result += LocCounter;
- else
- Result += getInteger(Tok);
+ Lhs = apply(Op1, Lhs, Rhs);
}
- return Result;
+ return Lhs;
+}
+
+// Evaluates the expression given by list of tokens.
+uint64_t evaluate(ArrayRef<StringRef> Tokens, uint64_t Dot) {
+ uint64_t V = parsePrimary(Tokens, Dot);
+ V = parseExpr(V, 0, Tokens, Dot);
+ if (!Tokens.empty())
+ error("stray token: " + Tokens[0]);
+ return V;
}
template <class ELFT>
Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=266798&r1=266797&r2=266798&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Tue Apr 19 13:58:11 2016
@@ -72,7 +72,6 @@ public:
bool DoLayout = false;
private:
- uint64_t evaluate(std::vector<StringRef> &Tokens, uint64_t LocCounter);
template <class ELFT> SectionRule *find(InputSectionBase<ELFT> *S);
// SECTIONS commands.
Modified: lld/trunk/test/ELF/linkerscript-locationcounter.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript-locationcounter.s?rev=266798&r1=266797&r2=266798&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript-locationcounter.s (original)
+++ lld/trunk/test/ELF/linkerscript-locationcounter.s Tue Apr 19 13:58:11 2016
@@ -1,63 +1,115 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: echo "SECTIONS { \
-# RUN: . = 0x12341; \
-# RUN: .data : { *(.data) } \
-# RUN: . = . + 0x10000; \
-# RUN: .text : { *(.text) } \
+# RUN: . = 0xFFF0; \
+# RUN: . = . + 0x10; \
+# RUN: .plus : { *(.plus) } \
+# RUN: . = 0x11010 - 0x10; \
+# RUN: .minus : { *(.minus) } \
+# RUN: . = 0x24000 / 0x2; \
+# RUN: .div : { *(.div) } \
+# RUN: . = 0x11000 + 0x1000 * 0x2; \
+# RUN: .mul : { *(.mul) } \
+# RUN: . = 0x10000 + (0x1000 + 0x1000) * 0x2; \
+# RUN: .bracket : { *(.bracket) } \
+# RUN: . = 0x17000 & 0x15000; \
+# RUN: .and : { *(.and) } \
# RUN: }" > %t.script
-
# RUN: ld.lld %t --script %t.script -o %t2
# RUN: llvm-readobj -s %t2 | FileCheck %s
-# CHECK: Sections [
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 0
-# CHECK-NEXT: Name: (0)
-# CHECK-NEXT: Type: SHT_NULL
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x0
-# CHECK-NEXT: Size: 0
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 0
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 1
-# CHECK-NEXT: Name: .data
-# CHECK-NEXT: Type: SHT_PROGBITS
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: SHF_ALLOC
-# CHECK-NEXT: SHF_WRITE
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x12341
-# CHECK-NEXT: Offset: 0x158
-# CHECK-NEXT: Size: 8
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 1
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: }
-# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Name: .text
-# CHECK-NEXT: Type: SHT_PROGBITS
-# CHECK-NEXT: Flags [
-# CHECK-NEXT: SHF_ALLOC
-# CHECK-NEXT: SHF_EXECINSTR
-# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x2234C
-# CHECK-NEXT: Offset: 0x160
-# CHECK-NEXT: Size: 1
-# CHECK-NEXT: Link: 0
-# CHECK-NEXT: Info: 0
-# CHECK-NEXT: AddressAlignment: 4
-# CHECK-NEXT: EntrySize: 0
-# CHECK-NEXT: }
+# CHECK: Section {
+# CHECK: Index: 1
+# CHECK: Name: .plus
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x10000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Name: .minus
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x11000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .div
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x12000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Name: .mul
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x13000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Name: .bracket
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x14000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index:
+# CHECK-NEXT: Name: .and
+# CHECK-NEXT: Type: SHT_PROGBITS
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address: 0x15000
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size:
+# CHECK-NEXT: Link:
+# CHECK-NEXT: Info:
+# CHECK-NEXT: AddressAlignment:
+# CHECK-NEXT: EntrySize:
+# CHECK-NEXT: }
+## Mailformed number error.
# RUN: echo "SECTIONS { \
# RUN: . = 0x12Q41; \
# RUN: }" > %t.script
@@ -65,10 +117,56 @@
# RUN: FileCheck --check-prefix=NUMERR %s
# NUMERR: malformed number: 0x12Q41
+## Missing closing bracket.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 + (0x1000 + 0x1000 * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=BRACKETERR %s
+# BRACKETERR: ) expected
+
+## Missing opening bracket.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 + 0x1000 + 0x1000) * 0x2; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=BRACKETERR2 %s
+# BRACKETERR2: stray token: )
+
+## Empty expression.
+# RUN: echo "SECTIONS { \
+# RUN: . = ; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=ERREXPR %s
+# ERREXPR: error in location counter expression
+
+## Div by zero error.
+# RUN: echo "SECTIONS { \
+# RUN: . = 0x10000 / 0x0; \
+# RUN: }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=DIVZERO %s
+# DIVZERO: division by zero
+
.globl _start;
_start:
nop
-.section .data
+.section .plus, "a"
.quad 0
+.section .minus, "a"
+.quad 0
+
+.section .div, "a"
+.quad 0
+
+.section .mul, "a"
+.quad 0
+
+.section .bracket, "a"
+.quad 0
+
+.section .and, "a"
+.quad 0
More information about the llvm-commits
mailing list