[ELF] - Linkerscript: implemented SIZEOF(section)

SIZEOF(section)
Return the size in bytes of the named section, if that section has been allocated.

SIZEOF(section) often used in scripts. Few examples from the wild:
https://github.com/chipKIT32/pic32-Arduino-USB-Bootloader-original/blob/master/boot-linkerscript.ld
https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/gba_cart.ld

Patch implements it.

Differential revision: https://reviews.llvm.org/D22915

llvm-svn: 277165
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index ed47c74..17a5ede 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -138,9 +138,10 @@
 }
 
 template <class ELFT>
-std::vector<OutputSectionBase<ELFT> *>
-LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) {
-  std::vector<OutputSectionBase<ELFT> *> Ret;
+void LinkerScript<ELFT>::createSections(
+    std::vector<OutputSectionBase<ELFT> *> *Out,
+    OutputSectionFactory<ELFT> &Factory) {
+  OutputSections = Out;
 
   for (auto &P : getSectionMap()) {
     std::vector<InputSectionBase<ELFT> *> Sections;
@@ -157,7 +158,7 @@
     if (I->Sort)
       std::stable_sort(Sections.begin(), Sections.end(), compareByName<ELFT>);
     for (InputSectionBase<ELFT> *S : Sections)
-      addSection(Factory, Ret, S, OutputName);
+      addSection(Factory, *Out, S, OutputName);
   }
 
   // Add all other input sections, which are not listed in script.
@@ -165,17 +166,15 @@
        Symtab<ELFT>::X->getObjectFiles())
     for (InputSectionBase<ELFT> *S : F->getSections())
       if (!isDiscarded(S) && !S->OutSec)
-        addSection(Factory, Ret, S, getOutputSectionName(S));
+        addSection(Factory, *Out, S, getOutputSectionName(S));
 
   // Remove from the output all the sections which did not meet
   // the optional constraints.
-  return filter(Ret);
+  filter();
 }
 
 // Process ONLY_IF_RO and ONLY_IF_RW.
-template <class ELFT>
-std::vector<OutputSectionBase<ELFT> *>
-LinkerScript<ELFT>::filter(std::vector<OutputSectionBase<ELFT> *> &Sections) {
+template <class ELFT> void LinkerScript<ELFT>::filter() {
   // In this loop, we remove output sections if they don't satisfy
   // requested properties.
   for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
@@ -186,10 +185,10 @@
     if (Cmd->Constraint == ConstraintKind::NoConstraint)
       continue;
 
-    auto It = llvm::find_if(Sections, [&](OutputSectionBase<ELFT> *S) {
+    auto It = llvm::find_if(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
       return S->getName() == Cmd->Name;
     });
-    if (It == Sections.end())
+    if (It == OutputSections->end())
       continue;
 
     OutputSectionBase<ELFT> *Sec = *It;
@@ -198,9 +197,8 @@
     bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
 
     if ((RO && Writable) || (RW && !Writable))
-      Sections.erase(It);
+      OutputSections->erase(It);
   }
-  return Sections;
 }
 
 template <class ELFT>
@@ -396,6 +394,15 @@
   return !Opt.PhdrsCommands.empty();
 }
 
+template <class ELFT>
+typename ELFT::uint LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
+  for (OutputSectionBase<ELFT> *Sec : *OutputSections)
+    if (Sec->getName() == Name)
+      return Sec->getSize();
+  error("undefined section " + Name);
+  return 0;
+}
+
 // 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.
@@ -838,6 +845,22 @@
   return 0;
 }
 
+static uint64_t getSectionSize(StringRef Name) {
+  switch (Config->EKind) {
+  case ELF32LEKind:
+    return Script<ELF32LE>::X->getOutputSectionSize(Name);
+  case ELF32BEKind:
+    return Script<ELF32BE>::X->getOutputSectionSize(Name);
+  case ELF64LEKind:
+    return Script<ELF64LE>::X->getOutputSectionSize(Name);
+  case ELF64BEKind:
+    return Script<ELF64BE>::X->getOutputSectionSize(Name);
+  default:
+    llvm_unreachable("unsupported target");
+  }
+  return 0;
+}
+
 SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
   StringRef Op = next();
   assert(Op == "=" || Op == "+=");
@@ -946,6 +969,12 @@
     expect(")");
     return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
   }
+  if (Tok == "SIZEOF") {
+    expect("(");
+    StringRef Name = next();
+    expect(")");
+    return [=](uint64_t Dot) { return getSectionSize(Name); };
+  }
 
   // Parse a symbol name or a number literal.
   uint64_t V = 0;