[ELF] - Implemented linkerscript sections padding.
authorGeorge Rimar <grimar@accesssoftek.com>
Fri, 26 Feb 2016 14:48:31 +0000 (14:48 +0000)
committerGeorge Rimar <grimar@accesssoftek.com>
Fri, 26 Feb 2016 14:48:31 +0000 (14:48 +0000)
BSD linker scripts contain special cases to add NOP
padding to code sections. Syntax is next:

.init:
 {
   KEEP (*(.init))
 } =0x90909090
(0x90 is NOP)

This patch implements that functionality.

llvm-svn: 262020

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/OutputSections.cpp
lld/test/ELF/linkerscript-sections-padding.s [new file with mode: 0644]

index a8e7119..a146be0 100644 (file)
@@ -54,13 +54,22 @@ template <class ELFT> bool LinkerScript::shouldKeep(InputSectionBase<ELFT> *S) {
   return R && R->Keep;
 }
 
+ArrayRef<uint8_t> LinkerScript::getFiller(StringRef Name) {
+  for (OutSection &C : OutSections)
+    if (C.Name == Name)
+      return C.Filler;
+  return {};
+}
+
 // A compartor to sort output sections. Returns -1 or 1 if both
 // A and B are mentioned in linker scripts. Otherwise, returns 0
 // to use the default rule which is implemented in Writer.cpp.
 int LinkerScript::compareSections(StringRef A, StringRef B) {
-  auto E = SectionOrder.end();
-  auto I = std::find(SectionOrder.begin(), E, A);
-  auto J = std::find(SectionOrder.begin(), E, B);
+  auto E = OutSections.end();
+  auto I = std::find_if(OutSections.begin(), E,
+                        [&](OutSection &C) { return C.Name == A; });
+  auto J = std::find_if(OutSections.begin(), E,
+                        [&](OutSection &C) { return C.Name == B; });
   if (I == E || J == E)
     return 0;
   return I < J ? -1 : 1;
@@ -109,6 +118,7 @@ private:
   static StringRef skipSpace(StringRef S);
   bool atEOF();
   StringRef next();
+  StringRef peek();
   bool skip(StringRef Tok);
   void expect(StringRef Expect);
 
@@ -129,6 +139,8 @@ private:
   void readOutputSectionDescription();
   void readSectionPatterns(StringRef OutSec, bool Keep);
 
+  std::vector<uint8_t> parseHex(StringRef S);
+
   StringSaver Saver;
   std::vector<StringRef> Tokens;
   const static StringMap<Handler> Cmd;
@@ -233,6 +245,14 @@ StringRef ScriptParser::next() {
   return Tokens[Pos++];
 }
 
+StringRef ScriptParser::peek() {
+  StringRef Tok = next();
+  if (Error)
+    return "";
+  --Pos;
+  return Tok;
+}
+
 bool ScriptParser::skip(StringRef Tok) {
   if (Error)
     return false;
@@ -394,24 +414,50 @@ void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) {
     Script->Sections.emplace_back(OutSec, next(), Keep);
 }
 
+std::vector<uint8_t> ScriptParser::parseHex(StringRef S) {
+  std::vector<uint8_t> Hex;
+  while (!S.empty()) {
+    StringRef B = S.substr(0, 2);
+    S = S.substr(2);
+    uint8_t H;
+    if (B.getAsInteger(16, H)) {
+      setError("Not a HEX value: " + B);
+      return {};
+    }
+    Hex.push_back(H);
+  }
+  return Hex;
+}
+
 void ScriptParser::readOutputSectionDescription() {
-  StringRef OutSec = next();
-  Script->SectionOrder.push_back(OutSec);
+  OutSection OutSec;
+  OutSec.Name = next();
   expect(":");
   expect("{");
   while (!Error && !skip("}")) {
     StringRef Tok = next();
     if (Tok == "*") {
-      readSectionPatterns(OutSec, false);
+      readSectionPatterns(OutSec.Name, false);
     } else if (Tok == "KEEP") {
       expect("(");
       next(); // Skip *
-      readSectionPatterns(OutSec, true);
+      readSectionPatterns(OutSec.Name, true);
       expect(")");
     } else {
       setError("Unknown command " + Tok);
     }
   }
+  StringRef Tok = peek();
+  if (Tok.startswith("=")) {
+    if (!Tok.startswith("=0x")) {
+      setError("Filler should be a HEX value");
+      return;
+    }
+    Tok = Tok.substr(3); // Skip '=0x'
+    OutSec.Filler = parseHex(Tok);
+    next();
+  }
+  Script->OutSections.push_back(OutSec);
 }
 
 static bool isUnderSysroot(StringRef Path) {
index 563e513..c534478 100644 (file)
@@ -40,6 +40,11 @@ private:
   StringRef SectionPattern;
 };
 
+struct OutSection {
+  StringRef Name;
+  std::vector<uint8_t> Filler;
+};
+
 // This is a runner of the linker script.
 class LinkerScript {
   friend class ScriptParser;
@@ -50,6 +55,7 @@ public:
   void read(MemoryBufferRef MB);
 
   template <class ELFT> StringRef getOutputSection(InputSectionBase<ELFT> *S);
+  ArrayRef<uint8_t> getFiller(StringRef Name);
   template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S);
   template <class ELFT> bool shouldKeep(InputSectionBase<ELFT> *S);
   int compareSections(StringRef A, StringRef B);
@@ -60,8 +66,9 @@ private:
   // SECTIONS commands.
   std::vector<SectionRule> Sections;
 
-  // Output sections are sorted by this order.
-  std::vector<StringRef> SectionOrder;
+  // Output sections information.
+  // They are sorted by the order of the container.
+  std::vector<OutSection> OutSections;
 
   llvm::BumpPtrAllocator Alloc;
 };
index 5ed7cc0..472eda9 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "OutputSections.h"
 #include "Config.h"
+#include "LinkerScript.h"
 #include "SymbolTable.h"
 #include "Target.h"
 #include "llvm/Support/Dwarf.h"
@@ -954,7 +955,17 @@ bool elf2::canBePreempted(const SymbolBody *Body) {
   return true;
 }
 
+static void fill(uint8_t *Buf, size_t Size, ArrayRef<uint8_t> A) {
+  size_t I = 0;
+  for (; I + A.size() < Size; I += A.size())
+    memcpy(Buf + I, A.data(), A.size());
+  memcpy(Buf + I, A.data(), Size - I);
+}
+
 template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  ArrayRef<uint8_t> Filler = Script->getFiller(this->Name);
+  if (!Filler.empty())
+    fill(Buf, this->getSize(), Filler);
   for (InputSection<ELFT> *C : Sections)
     C->writeTo(Buf);
 }
diff --git a/lld/test/ELF/linkerscript-sections-padding.s b/lld/test/ELF/linkerscript-sections-padding.s
new file mode 100644 (file)
index 0000000..eb2c919
--- /dev/null
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+
+## Check that padding value works:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x112233445566778899 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES %s
+# YES: 00000120  66 22 33 44 55 66 77 88 99 11 22 33 44 55 66 77
+
+## Confirming that address was correct:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x998877665544332211 }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES2 %s
+# YES2: 00000120  66 88 77 66 55 44 33 22 11 99 88 77 66 55 44
+
+## Default padding value is 0x00:
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script
+# RUN: ld.lld -o %t.out --script %t.script %t
+# RUN: hexdump -C %t.out | FileCheck -check-prefix=NO %s
+# NO: 00000120  66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+## Filler should be a hex value (1):
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =99 }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR %s
+# ERR: Filler should be a HEX value
+
+## Filler should be a hex value (2):
+# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script
+# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \
+# RUN:   | FileCheck --check-prefix=ERR2 %s
+# ERR2: Not a HEX value: XX
+
+.section        .mysec.1,"a"
+.align  16
+.byte   0x66
+
+.section        .mysec.2,"a"
+.align  16
+.byte   0x66
+
+.globl _start
+_start:
+ nop