Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -946,21 +946,6 @@ return V; } -// Parses --defsym=alias option. -static std::vector> -getDefsym(opt::InputArgList &Args) { - std::vector> Ret; - for (auto *Arg : Args.filtered(OPT_defsym)) { - StringRef From; - StringRef To; - std::tie(From, To) = StringRef(Arg->getValue()).split('='); - if (!isValidCIdentifier(To)) - error("--defsym: symbol name expected, but got " + To); - Ret.push_back({From, To}); - } - return Ret; -} - // Parses `--exclude-libs=lib,lib,...`. // The library names may be delimited by commas or colons. static DenseSet getExcludeLibs(opt::InputArgList &Args) { @@ -1054,6 +1039,12 @@ for (InputFile *F : Files) Symtab->addFile(F); + // Process -defsym option. + for (auto *Arg : Args.filtered(OPT_defsym)) { + MemoryBufferRef MB(Arg->getValue(), "-defsym"); + readDefsym(MB); + } + // Now that we have every file, we can decide if we will need a // dynamic symbol table. // We need one if we were asked to export dynamic symbols or if we are @@ -1095,15 +1086,11 @@ for (auto *Arg : Args.filtered(OPT_wrap)) Symtab->addSymbolWrap(Arg->getValue()); - // Create alias symbols for -defsym option. - for (std::pair &Def : getDefsym(Args)) - Symtab->addSymbolAlias(Def.first, Def.second); - Symtab->addCombinedLTOObject(); if (errorCount()) return; - // Apply symbol renames for -wrap and -defsym + // Apply symbol renames for -wrap. Symtab->applySymbolRenames(); // Now that we have a complete list of input files. Index: ELF/ScriptLexer.h =================================================================== --- ELF/ScriptLexer.h +++ ELF/ScriptLexer.h @@ -37,11 +37,12 @@ std::vector MBs; std::vector Tokens; - bool InExpr = false; + enum class LexerContext { Default, Defsym, Expr }; + LexerContext Context = LexerContext::Default; size_t Pos = 0; private: - void maybeSplitExpr(); + void maybeSplit(); StringRef getLine(); size_t getLineNumber(); size_t getColumnNumber(); Index: ELF/ScriptLexer.cpp =================================================================== --- ELF/ScriptLexer.cpp +++ ELF/ScriptLexer.cpp @@ -197,6 +197,28 @@ return Ret; } +// Split a given string as a defsym. +// The expected format is = which will get tokenized +// as "", "=", "". +static std::vector tokenizeDefsym(StringRef S) { + std::vector Ret; + + size_t E = S.find("="); + if (E == StringRef::npos) { + Ret.push_back(S); + return Ret; + } + + if (E != 0) + Ret.push_back(S.substr(0, E)); + + Ret.push_back(S.substr(E, 1)); + S = S.substr(E + 1); + Ret.push_back(S); + + return Ret; +} + // In contexts where expressions are expected, the lexer should apply // different tokenization rules than the default one. By default, // arithmetic operator characters are regular characters, but in the @@ -206,11 +228,21 @@ // in the expression context. // // This function may split the current token into multiple tokens. -void ScriptLexer::maybeSplitExpr() { - if (!InExpr || errorCount() || atEOF()) +void ScriptLexer::maybeSplit() { + if (errorCount() || atEOF()) return; - std::vector V = tokenizeExpr(Tokens[Pos]); + std::vector V; + switch (Context) { + case LexerContext::Defsym: + V = tokenizeDefsym(Tokens[Pos]); + break; + case LexerContext::Expr: + V = tokenizeExpr(Tokens[Pos]); + break; + default: + return; + } if (V.size() == 1) return; Tokens.erase(Tokens.begin() + Pos); @@ -218,7 +250,7 @@ } StringRef ScriptLexer::next() { - maybeSplitExpr(); + maybeSplit(); if (errorCount()) return ""; Index: ELF/ScriptParser.h =================================================================== --- ELF/ScriptParser.h +++ ELF/ScriptParser.h @@ -25,6 +25,9 @@ void readDynamicList(MemoryBufferRef MB); +// Parses the defsym expression. +void readDefsym(MemoryBufferRef MB); + } // namespace elf } // namespace lld Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -53,6 +53,7 @@ void readLinkerScript(); void readVersionScript(); void readDynamicList(); + void readDefsym(); private: void addFile(StringRef Path); @@ -269,6 +270,17 @@ } } +void ScriptParser::readDefsym() { + auto Orig = Context; + Context = LexerContext::Defsym; + StringRef Tok = next(); + Context = Orig; + expect("="); + Expr E = readExpr(); + SymbolAssignment *Cmd = make(Tok, E, getCurrentLocation()); + Script->SectionCommands.push_back(Cmd); +} + void ScriptParser::addFile(StringRef S) { if (IsUnderSysroot && S.startswith("/")) { SmallString<128> PathData; @@ -778,10 +790,10 @@ Expr ScriptParser::readExpr() { // Our lexer is context-aware. Set the in-expression bit so that // they apply different tokenization rules. - bool Orig = InExpr; - InExpr = true; + auto Orig = Context; + Context = LexerContext::Expr; Expr E = readExpr1(readPrimary(), 0); - InExpr = Orig; + Context = Orig; return E; } @@ -1326,3 +1338,7 @@ void elf::readDynamicList(MemoryBufferRef MB) { ScriptParser(MB).readDynamicList(); } + +void elf::readDefsym(MemoryBufferRef MB) { + ScriptParser(MB).readDefsym(); +} Index: test/ELF/defsym.s =================================================================== --- test/ELF/defsym.s +++ test/ELF/defsym.s @@ -19,7 +19,7 @@ # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: foo1 +# CHECK-NEXT: Name: foo2 # CHECK-NEXT: Value: 0x123 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global @@ -33,11 +33,46 @@ # USE-NEXT: _start: # USE-NEXT: movl $0x123, %edx -# RUN: not ld.lld -o %t %t.o --defsym=foo2=1 2>&1 | FileCheck %s -check-prefix=ERR1 -# ERR1: error: --defsym: symbol name expected, but got 1 +# RUN: ld.lld -o %t %t.o --defsym=foo2=1 +# RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=ABS -# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR2 -# ERR2: error: -defsym: undefined symbol: und +# ABS: Symbol { +# ABS: Name: foo2 +# ABS-NEXT: Value: 0x1 +# ABS-NEXT: Size: +# ABS-NEXT: Binding: Global +# ABS-NEXT: Type: +# ABS-NEXT: Other: +# ABS-NEXT: Section: Absolute +# ABS-NEXT: } + +# RUN: ld.lld -o %t %t.o --defsym=foo2=foo1+5 +# RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=EXPR + +# EXPR: Symbol { +# EXPR: Name: foo1 +# EXPR-NEXT: Value: 0x123 +# EXPR-NEXT: Size: +# EXPR-NEXT: Binding: Global +# EXPR-NEXT: Type: +# EXPR-NEXT: Other: +# EXPR-NEXT: Section: Absolute +# EXPR-NEXT: } +# EXPR-NEXT: Symbol { +# EXPR-NEXT: Name: foo2 +# EXPR-NEXT: Value: 0x128 +# EXPR-NEXT: Size: +# EXPR-NEXT: Binding: Global +# EXPR-NEXT: Type: +# EXPR-NEXT: Other: +# EXPR-NEXT: Section: Absolute +# EXPR-NEXT: } + +# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR1 +# ERR1: error: -defsym:1: symbol not found: und + +# RUN: not ld.lld -o %t %t.o --defsym=foo2 2>&1 | FileCheck %s -check-prefix=ERR2 +# ERR2: error: -defsym:1: unexpected EOF .globl foo1 foo1 = 0x123