Index: ELF/LinkerScript.h
===================================================================
--- ELF/LinkerScript.h
+++ ELF/LinkerScript.h
@@ -138,14 +138,11 @@
   bool shouldKeep(InputSectionBase<ELFT> *S);
   void assignAddresses(ArrayRef<OutputSectionBase<ELFT> *> S);
   int compareSections(StringRef A, StringRef B);
-  void addScriptedSymbols();
   bool hasPhdrsCommands();
   uintX_t getOutputSectionSize(StringRef Name);
+  void assignSectionSymbols();
 
 private:
-  std::vector<std::pair<StringRef, const InputSectionDescription *>>
-  getSectionMap();
-
   std::vector<InputSectionBase<ELFT> *>
   getInputSections(const InputSectionDescription *);
 
@@ -159,6 +156,7 @@
   size_t getPhdrIndex(StringRef PhdrName);
 
   std::vector<OutputSectionBase<ELFT> *> *OutputSections;
+  std::vector<std::unique_ptr<InputSectionBase<ELFT>>> SymbolSections;
   uintX_t Dot;
 };
 
Index: ELF/LinkerScript.cpp
===================================================================
--- ELF/LinkerScript.cpp
+++ ELF/LinkerScript.cpp
@@ -43,6 +43,68 @@
 
 ScriptConfiguration *elf::ScriptConfig;
 
+// Helper function to zero object memory
+template <class T> static inline T *zero(T *Val) {
+  memset(Val, 0, sizeof(*Val));
+  return Val;
+}
+
+template <class ELFT, class... ArgsT>
+static void addSymbolToSymtab(SymbolAssignment *Cmd, ArgsT... Args) {
+  if (!Cmd || Cmd->Name == ".")
+    return;
+
+  // If a symbol was in PROVIDE(), define it only when it is an
+  // undefined symbol.
+  SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
+  if (Cmd->Provide && !(B && B->isUndefined()))
+    return;
+
+  // Define an absolute symbol. The symbol value will be assigned later.
+  // (At this point, we don't know the final address yet.)
+  Symbol *Sym = Symtab<ELFT>::X->addUndefined(Cmd->Name);
+  replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, Args...);
+  Sym->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
+  Cmd->Sym = Sym->body();
+}
+
+namespace {
+// Virtual input section which represents symbol defined within
+// some output section
+template <class ELFT> class SymbolInputSection : public InputSection<ELFT> {
+public:
+  SymbolInputSection(SymbolAssignment *A);
+  void createSymbol();
+  void assignSymbolValue();
+
+private:
+  SymbolAssignment *Cmd;
+  typename ELFT::Shdr Hdr;
+};
+}
+
+template <class ELFT>
+SymbolInputSection<ELFT>::SymbolInputSection(SymbolAssignment *A)
+    : InputSection<ELFT>(nullptr, zero(&Hdr)), Cmd(A) {
+  // This is a virtual input section, which represents a symbol which belongs
+  // to some output section. We don't want even an attempt to write it to file.
+  Hdr.sh_type = SHT_NOBITS;
+}
+
+template <class ELFT> void SymbolInputSection<ELFT>::createSymbol() {
+  typename ELFT::Sym Sym = {};
+  Sym.setBindingAndType(STB_GLOBAL, STT_NOTYPE);
+  Sym.setVisibility(Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT);
+
+  addSymbolToSymtab<ELFT>(Cmd, Sym, this);
+}
+
+template <class ELFT> void SymbolInputSection<ELFT>::assignSymbolValue() {
+  if (Cmd->Sym)
+    cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value =
+        Cmd->Expression(this->OutSecOff) - this->OutSecOff;
+}
+
 bool SymbolAssignment::classof(const BaseCommand *C) {
   return C->Kind == AssignmentKind;
 }
@@ -74,21 +136,6 @@
   return false;
 }
 
-// Create a vector of (<output section name>, <input section description>).
-template <class ELFT>
-std::vector<std::pair<StringRef, const InputSectionDescription *>>
-LinkerScript<ELFT>::getSectionMap() {
-  std::vector<std::pair<StringRef, const InputSectionDescription *>> Ret;
-
-  for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
-    if (auto *Cmd1 = dyn_cast<OutputSectionCommand>(Base1.get()))
-      for (const std::unique_ptr<BaseCommand> &Base2 : Cmd1->Commands)
-        if (auto *Cmd2 = dyn_cast<InputSectionDescription>(Base2.get()))
-          Ret.emplace_back(Cmd1->Name, Cmd2);
-
-  return Ret;
-}
-
 static bool fileMatches(const InputSectionDescription *Desc,
                         StringRef Filename) {
   if (!globMatch(Desc->FilePattern, Filename))
@@ -117,36 +164,66 @@
   return Ret;
 }
 
-// Add input section to output section. If there is no output section yet,
-// then create it and add to output section list.
 template <class ELFT>
-static void addSection(OutputSectionFactory<ELFT> &Factory,
-                       std::vector<OutputSectionBase<ELFT> *> &Out,
-                       InputSectionBase<ELFT> *C, StringRef Name) {
-  OutputSectionBase<ELFT> *Sec;
+static bool compareByName(InputSectionBase<ELFT> *A,
+                          InputSectionBase<ELFT> *B) {
+  return A->getSectionName() < B->getSectionName();
+}
+
+namespace {
+// Helper class, which builds output section list, also
+// creating symbol sections, when needed
+template <class ELFT> class OutputSectionBuilder {
+public:
+  OutputSectionBuilder(OutputSectionFactory<ELFT> &F,
+                       std::vector<OutputSectionBase<ELFT> *> *Out)
+      : Factory(F), OutputSections(Out) {}
+
+  void addSection(StringRef OutputName, InputSectionBase<ELFT> *I);
+  void addSymbol(SymbolAssignment *Cmd) { PendingSymbols.push_back(Cmd); }
+  void flushSymbols();
+
+  std::vector<std::unique_ptr<InputSectionBase<ELFT>>> SymbolSections;
+
+private:
+  OutputSectionFactory<ELFT> &Factory;
+  std::vector<OutputSectionBase<ELFT> *> *OutputSections;
+  OutputSectionBase<ELFT> *Current = nullptr;
+  std::vector<SymbolAssignment *> PendingSymbols;
+};
+}
+
+template <class ELFT>
+void OutputSectionBuilder<ELFT>::addSection(StringRef OutputName,
+                                            InputSectionBase<ELFT> *C) {
   bool IsNew;
-  std::tie(Sec, IsNew) = Factory.create(C, Name);
+  std::tie(Current, IsNew) = Factory.create(C, OutputName);
   if (IsNew)
-    Out.push_back(Sec);
-  Sec->addSection(C);
+    OutputSections->push_back(Current);
+  flushSymbols();
+  Current->addSection(C);
 }
 
-template <class ELFT>
-static bool compareByName(InputSectionBase<ELFT> *A,
-                          InputSectionBase<ELFT> *B) {
-  return A->getSectionName() < B->getSectionName();
+template <class ELFT> void OutputSectionBuilder<ELFT>::flushSymbols() {
+  for (SymbolAssignment *Assignment : PendingSymbols) {
+    std::unique_ptr<SymbolInputSection<ELFT>> SymSec(
+        new SymbolInputSection<ELFT>(Assignment));
+    Current->addSection(SymSec.get());
+    SymbolSections.push_back(std::move(SymSec));
+  }
+  PendingSymbols.clear();
 }
 
+// Create output sections and symbols as listed in linker script.
 template <class ELFT>
 void LinkerScript<ELFT>::createSections(
     std::vector<OutputSectionBase<ELFT> *> *Out,
     OutputSectionFactory<ELFT> &Factory) {
   OutputSections = Out;
+  OutputSectionBuilder<ELFT> Builder(Factory, Out);
 
-  for (auto &P : getSectionMap()) {
+  auto Add = [&](StringRef OutputName, const InputSectionDescription *I) {
     std::vector<InputSectionBase<ELFT> *> Sections;
-    StringRef OutputName = P.first;
-    const InputSectionDescription *I = P.second;
     for (InputSectionBase<ELFT> *S : getInputSections(I)) {
       if (OutputName == "/DISCARD/") {
         S->Live = false;
@@ -158,25 +235,51 @@
     if (I->Sort)
       std::stable_sort(Sections.begin(), Sections.end(), compareByName<ELFT>);
     for (InputSectionBase<ELFT> *S : Sections)
-      addSection(Factory, *Out, S, OutputName);
-  }
+      Builder.addSection(OutputName, S);
+  };
+
+  for (const std::unique_ptr<BaseCommand> &Base1 : Opt.Commands)
+    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base1.get())) {
+      for (const std::unique_ptr<BaseCommand> &Base2 : Cmd->Commands)
+        if (auto *Assignment = dyn_cast<SymbolAssignment>(Base2.get()))
+          Builder.addSymbol(Assignment);
+        else
+          Add(Cmd->Name, cast<InputSectionDescription>(Base2.get()));
+
+      Builder.flushSymbols();
+    } else if (auto *Cmd2 = dyn_cast<SymbolAssignment>(Base1.get())) {
+      addSymbolToSymtab<ELFT>(Cmd2, STV_DEFAULT);
+    }
 
   // Add all other input sections, which are not listed in script.
   for (const std::unique_ptr<ObjectFile<ELFT>> &F :
        Symtab<ELFT>::X->getObjectFiles())
     for (InputSectionBase<ELFT> *S : F->getSections())
       if (!isDiscarded(S) && !S->OutSec)
-        addSection(Factory, *Out, S, getOutputSectionName(S));
+        Builder.addSection(getOutputSectionName(S), S);
 
   // Remove from the output all the sections which did not meet
   // the optional constraints.
+  SymbolSections = std::move(Builder.SymbolSections);
   filter();
+
+  // After we've filtered ouput sections and corresponding symbol
+  // sections, we can start adding symbols to symbol table.
+  for (std::unique_ptr<InputSectionBase<ELFT>> &I : SymbolSections)
+    cast<SymbolInputSection<ELFT>>(I.get())->createSymbol();
+}
+
+template <class R, class T>
+static inline void removeElements(R &Range, const T &Pred) {
+  Range.erase(std::remove_if(Range.begin(), Range.end(), Pred), Range.end());
 }
 
 // Process ONLY_IF_RO and ONLY_IF_RW.
 template <class ELFT> void LinkerScript<ELFT>::filter() {
   // In this loop, we remove output sections if they don't satisfy
   // requested properties.
+  llvm::DenseSet<OutputSectionBase<ELFT> *> Removed;
+
   for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
     auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
     if (!Cmd || Cmd->Name == "/DISCARD/")
@@ -185,20 +288,23 @@
     if (Cmd->Constraint == ConstraintKind::NoConstraint)
       continue;
 
-    auto It = llvm::find_if(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
-      return S->getName() == Cmd->Name;
-    });
-    if (It == OutputSections->end())
-      continue;
-
-    OutputSectionBase<ELFT> *Sec = *It;
-    bool Writable = (Sec->getFlags() & SHF_WRITE);
-    bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly);
-    bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
+    removeElements(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
+      bool Writable = (S->getFlags() & SHF_WRITE);
+      bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly);
+      bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
+
+      bool Filter =
+          S->getName() == Cmd->Name && ((RO && Writable) || (RW && !Writable));
+      if (Filter)
+        Removed.insert(S);
 
-    if ((RO && Writable) || (RW && !Writable))
-      OutputSections->erase(It);
+      return Filter;
+    });
   }
+  removeElements(SymbolSections,
+                 [&](std::unique_ptr<InputSectionBase<ELFT>> &I) {
+                   return Removed.find(I->OutSec) != Removed.end();
+                 });
 }
 
 template <class ELFT>
@@ -368,28 +474,6 @@
   return I < J ? -1 : 1;
 }
 
-// Add symbols defined by linker scripts.
-template <class ELFT> void LinkerScript<ELFT>::addScriptedSymbols() {
-  for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
-    auto *Cmd = dyn_cast<SymbolAssignment>(Base.get());
-    if (!Cmd || Cmd->Name == ".")
-      continue;
-
-    // If a symbol was in PROVIDE(), define it only when it is an
-    // undefined symbol.
-    SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
-    if (Cmd->Provide && !(B && B->isUndefined()))
-      continue;
-
-    // Define an absolute symbol. The symbol value will be assigned later.
-    // (At this point, we don't know the final address yet.)
-    Symbol *Sym = Symtab<ELFT>::X->addUndefined(Cmd->Name);
-    replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, STV_DEFAULT);
-    Sym->Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
-    Cmd->Sym = Sym->body();
-  }
-}
-
 template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
   return !Opt.PhdrsCommands.empty();
 }
@@ -403,6 +487,11 @@
   return 0;
 }
 
+template <class ELFT> void LinkerScript<ELFT>::assignSectionSymbols() {
+  for (std::unique_ptr<InputSectionBase<ELFT>> &I : SymbolSections)
+    cast<SymbolInputSection<ELFT>>(I.get())->assignSymbolValue();
+}
+
 // Returns indices of ELF headers containing specific section, identified
 // by Name. Each index is a zero based number of ELF header listed within
 // PHDRS {} script block.
@@ -465,7 +554,8 @@
   void readInputFilePattern(InputSectionDescription *InCmd, bool Keep);
   void readInputSectionRules(InputSectionDescription *InCmd, bool Keep);
   unsigned readPhdrType();
-  void readProvide(bool Hidden);
+  SymbolAssignment *readProvide(bool Hidden);
+  SymbolAssignment *readProvideOrAssignment(StringRef Tok);
   void readAlign(OutputSectionCommand *Cmd);
   void readSort();
 
@@ -664,16 +754,10 @@
   expect("{");
   while (!Error && !skip("}")) {
     StringRef Tok = next();
-    if (peek() == "=" || peek() == "+=") {
-      readAssignment(Tok);
-      expect(";");
-    } else if (Tok == "PROVIDE") {
-      readProvide(false);
-    } else if (Tok == "PROVIDE_HIDDEN") {
-      readProvide(true);
-    } else {
+    if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok))
+      Opt.Commands.emplace_back(Assignment);
+    else
       readOutputSectionDescription(Tok);
-    }
   }
 }
 
@@ -781,15 +865,12 @@
     }
 
     StringRef Tok = next();
-    if (Tok == "PROVIDE") {
-      readProvide(false);
-    } else if (Tok == "PROVIDE_HIDDEN") {
-      readProvide(true);
-    } else if (Tok == "SORT") {
+    if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok))
+      Cmd->Commands.emplace_back(Assignment);
+    else if (Tok == "SORT")
       readSort();
-    } else {
+    else
       setError("unknown command " + Tok);
-    }
   }
   Cmd->Phdrs = readOutputSectionPhdrs();
   Cmd->Filler = readOutputSectionFiller();
@@ -814,13 +895,27 @@
   return {static_cast<unsigned char>(Value)};
 }
 
-void ScriptParser::readProvide(bool Hidden) {
+SymbolAssignment *ScriptParser::readProvide(bool Hidden) {
   expect("(");
   SymbolAssignment *Cmd = readAssignment(next());
   Cmd->Provide = true;
   Cmd->Hidden = Hidden;
   expect(")");
   expect(";");
+  return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+  SymbolAssignment *Cmd = nullptr;
+  if (peek() == "=" || peek() == "+=") {
+    Cmd = readAssignment(Tok);
+    expect(";");
+  } else if (Tok == "PROVIDE") {
+    Cmd = readProvide(false);
+  } else if (Tok == "PROVIDE_HIDDEN") {
+    Cmd = readProvide(true);
+  }
+  return Cmd;
 }
 
 static uint64_t getSymbolValue(StringRef S, uint64_t Dot) {
@@ -873,9 +968,7 @@
   Expr E = readExpr();
   if (Op == "+=")
     E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); };
-  auto *Cmd = new SymbolAssignment(Name, E);
-  Opt.Commands.emplace_back(Cmd);
-  return Cmd;
+  return new SymbolAssignment(Name, E);
 }
 
 // This is an operator-precedence parser to parse a linker
Index: ELF/Writer.cpp
===================================================================
--- ELF/Writer.cpp
+++ ELF/Writer.cpp
@@ -697,10 +697,6 @@
   // Define __rel[a]_iplt_{start,end} symbols if needed.
   addRelIpltSymbols();
 
-  // Add scripted symbols with zero values now.
-  // Real values will be assigned later
-  Script<ELFT>::X->addScriptedSymbols();
-
   if (!Out<ELFT>::EhFrame->empty()) {
     OutputSections.push_back(Out<ELFT>::EhFrame);
     Out<ELFT>::EhFrame->finalize();
@@ -712,6 +708,11 @@
   for (OutputSectionBase<ELFT> *Sec : OutputSections)
     Sec->assignOffsets();
 
+  // Assign values to symbols defined inside output section description
+  // in linker script. This requires knowledge of exact size and offset
+  // of each input section, so must be called after we assign section offsets
+  Script<ELFT>::X->assignSectionSymbols();
+
   // Scan relocations. This must be done after every symbol is declared so that
   // we can correctly decide if a dynamic relocation is needed.
   forEachRelSec(scanRelocations<ELFT>);
Index: test/ELF/linkerscript/linkerscript-provide-in-section.s
===================================================================
--- test/ELF/linkerscript/linkerscript-provide-in-section.s
+++ test/ELF/linkerscript/linkerscript-provide-in-section.s
@@ -1,20 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: echo \
-# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE(foo = .); } }" \
-# RUN:   > %t.script
-# RUN: ld.lld -o %t1 --script %t.script %t -shared
-# RUN: llvm-objdump -t %t1 | FileCheck %s
-# CHECK: 00000000000003e8         *ABS*           00000000 foo
-
-# RUN: echo \
-# RUN: "SECTIONS { . = 1000; .blah : { PROVIDE_HIDDEN(foo = .); } }" \
-# RUN:   > %t2.script
-# RUN: ld.lld -o %t2 --script %t2.script %t -shared
-# RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=HIDDEN
-# HIDDEN: 00000000000003e8         *ABS*           00000000 .hidden foo
-
-.section .blah
-.globl patatino
-patatino:
-  movl $foo, %edx
Index: test/ELF/linkerscript/linkerscript-symbols-synthetic.s
===================================================================
--- test/ELF/linkerscript/linkerscript-symbols-synthetic.s
+++ test/ELF/linkerscript/linkerscript-symbols-synthetic.s
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+# Simple symbol assignment within input section list. The '.' symbol
+# is not location counter but offset from the beginning of output
+# section .foo
+# RUN: echo "SECTIONS { .foo : { \
+# RUN:              begin_foo = .; \
+# RUN:              *(.foo) \
+# RUN:              end_foo = .; \
+# RUN:              begin_bar = .; \
+# RUN:              *(.bar) \
+# RUN:              end_bar = .; } }" > %t.script
+# RUN: ld.lld -o %t1 --script %t.script %t
+# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s
+# SIMPLE:      0000000000000120         .foo    00000000 begin_foo
+# SIMPLE-NEXT: 0000000000000128         .foo    00000000 end_foo
+# SIMPLE-NEXT: 0000000000000128         .foo    00000000 begin_bar
+# SIMPLE-NEXT: 000000000000012c         .foo    00000000 end_bar
+
+.global _start
+_start:
+ nop
+
+.section .foo,"a"
+ .quad 0
+
+.section .bar,"a"
+ .long 0