[lld] r337332 - Implement framework for linking split-stack object files, and x86_64 support.

Sterling Augustine via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 17 16:16:02 PDT 2018


Author: saugustine
Date: Tue Jul 17 16:16:02 2018
New Revision: 337332

URL: http://llvm.org/viewvc/llvm-project?rev=337332&view=rev
Log:
Implement framework for linking split-stack object files, and x86_64 support.


Added:
    lld/trunk/test/ELF/Inputs/x86-64-split-stack-main.s
    lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
    lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
    lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-success.s
Removed:
    lld/trunk/test/ELF/splitstacks.s
Modified:
    lld/trunk/ELF/Arch/X86_64.cpp
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/Arch/X86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/X86_64.cpp?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/X86_64.cpp (original)
+++ lld/trunk/ELF/Arch/X86_64.cpp Tue Jul 17 16:16:02 2018
@@ -43,6 +43,8 @@ public:
   void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+  bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+                                        uint8_t *End) const override;
 
 private:
   void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
@@ -469,6 +471,40 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc
   write32le(Loc - 1, Val + 1);
 }
 
+// A split-stack prologue starts by checking the amount of stack remaining
+// in one of two ways:
+// A) Comparing of the stack pointer to a field in the tcb.
+// B) Or a load of a stack pointer offset with an lea to r10 or r11.
+template <>
+bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+                                                       uint8_t *End) const {
+  // Replace "cmp %fs:0x70,%rsp" and subsequent branch
+  // with "stc, nopl 0x0(%rax,%rax,1)"
+  if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) {
+    memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8);
+    return true;
+  }
+
+  // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10"
+  if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) {
+    memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7);
+    return true;
+  }
+
+  // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11"
+  if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) {
+    memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7);
+    return true;
+  }
+  return false;
+}
+
+template <>
+bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+                                                       uint8_t *End) const {
+  llvm_unreachable("Target doesn't support split stacks.");
+}
+
 // These nonstandard PLT entries are to migtigate Spectre v2 security
 // vulnerability. In order to mitigate Spectre v2, we want to avoid indirect
 // branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Tue Jul 17 16:16:02 2018
@@ -645,13 +645,24 @@ InputSectionBase *ObjFile<ELFT>::createI
   if (Name == ".note.GNU-stack")
     return &InputSection::Discarded;
 
-  // Split stacks is a feature to support a discontiguous stack. At least
-  // as of 2017, it seems that the feature is not being used widely.
-  // Only GNU gold supports that. We don't. For the details about that,
-  // see https://gcc.gnu.org/wiki/SplitStacks
+  // Split stacks is a feature to support a discontiguous stack,
+  // commonly used in the programming language Go. For the details,
+  // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled
+  // for split stack will include a .note.GNU-split-stack section.
   if (Name == ".note.GNU-split-stack") {
-    error(toString(this) +
-          ": object file compiled with -fsplit-stack is not supported");
+    if (Config->Relocatable) {
+      error("Cannot mix split-stack and non-split-stack in a relocatable link");
+      return &InputSection::Discarded;
+    }
+    this->SplitStack = true;
+    return &InputSection::Discarded;
+  }
+
+  // An object file cmpiled for split stack, but where some of the
+  // functions were compiled with the no_split_stack_attribute will
+  // include a .note.GNU-no-split-stack section.
+  if (Name == ".note.GNU-no-split-stack") {
+    this->SomeNoSplitStack = true;
     return &InputSection::Discarded;
   }
 

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Tue Jul 17 16:16:02 2018
@@ -207,6 +207,14 @@ public:
   // symbol table.
   StringRef SourceFile;
 
+  // True if the file defines functions compiled with
+  // -fsplit-stack. Usually false.
+  bool SplitStack = false;
+
+  // True if the file defines functions compiled with -fsplit-stack,
+  // but had one or more functions with the no_split_stack attribute.
+  bool SomeNoSplitStack = false;
+
 private:
   void
   initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Tue Jul 17 16:16:02 2018
@@ -14,6 +14,7 @@
 #include "LinkerScript.h"
 #include "OutputSections.h"
 #include "Relocations.h"
+#include "SymbolTable.h"
 #include "Symbols.h"
 #include "SyntheticSections.h"
 #include "Target.h"
@@ -26,7 +27,10 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/xxhash.h"
+#include <algorithm>
 #include <mutex>
+#include <set>
+#include <vector>
 
 using namespace llvm;
 using namespace llvm::ELF;
@@ -212,6 +216,17 @@ InputSection *InputSectionBase::getLinkO
   return cast<InputSection>(File->getSections()[Link]);
 }
 
+// Find a function symbol that encloses a given location.
+template <class ELFT>
+Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
+  for (Symbol *B : File->getSymbols())
+    if (Defined *D = dyn_cast<Defined>(B))
+      if (D->Section == this && D->Type == STT_FUNC &&
+          D->Value <= Offset && Offset < D->Value + D->Size)
+        return D;
+  return nullptr;
+}
+
 // Returns a source location string. Used to construct an error message.
 template <class ELFT>
 std::string InputSectionBase::getLocation(uint64_t Offset) {
@@ -230,12 +245,8 @@ std::string InputSectionBase::getLocatio
   if (SrcFile.empty())
     SrcFile = toString(File);
 
-  // Find a function symbol that encloses a given location.
-  for (Symbol *B : File->getSymbols())
-    if (auto *D = dyn_cast<Defined>(B))
-      if (D->Section == this && D->Type == STT_FUNC)
-        if (D->Value <= Offset && Offset < D->Value + D->Size)
-          return SrcFile + ":(function " + toString(*D) + ")";
+  if (Defined *D = getEnclosingFunction<ELFT>(Offset))
+    return SrcFile + ":(function " + toString(*D) + ")";
 
   // If there's no symbol, print out the offset in the section.
   return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
@@ -747,6 +758,9 @@ static void relocateNonAllocForRelocatab
 
 template <class ELFT>
 void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+  if (Flags & SHF_EXECINSTR)
+    adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd);
+
   if (Flags & SHF_ALLOC) {
     relocateAlloc(Buf, BufEnd);
     return;
@@ -825,6 +839,103 @@ void InputSectionBase::relocateAlloc(uin
   }
 }
 
+// For each function-defining prologue, find any calls to __morestack,
+// and replace them with calls to __morestack_non_split.
+static void switchMorestackCallsToMorestackNonSplit(
+    llvm::DenseSet<Defined *>& Prologues,
+    std::vector<Relocation *>& MorestackCalls) {
+
+  // If the target adjusted a function's prologue, all calls to
+  // __morestack inside that function should be switched to
+  // __morestack_non_split.
+  Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+
+  // Sort both collections to compare addresses efficiently.
+  llvm::sort(MorestackCalls.begin(), MorestackCalls.end(),
+             [](const Relocation *L, const Relocation *R) {
+               return L->Offset < R->Offset;
+             });
+  std::vector<Defined *> Functions(Prologues.begin(), Prologues.end());
+  llvm::sort(
+      Functions.begin(), Functions.end(),
+      [](const Defined *L, const Defined *R) { return L->Value < R->Value; });
+
+  auto It = MorestackCalls.begin();
+  for (Defined *F : Functions) {
+    // Find the first call to __morestack within the function.
+    while (It != MorestackCalls.end() && (*It)->Offset < F->Value)
+      ++It;
+    // Adjust all calls inside the function.
+    while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) {
+      (*It)->Sym = MoreStackNonSplit;
+      ++It;
+    }
+  }
+}
+
+static bool
+enclosingPrologueAdjusted(uint64_t Offset,
+                          const llvm::DenseSet<Defined *> &Prologues) {
+  for (Defined *F : Prologues)
+    if (F->Value <= Offset && Offset < F->Value + F->Size)
+      return true;
+  return false;
+}
+
+// If a function compiled for split stack calls a function not
+// compiled for split stack, then the caller needs its prologue
+// adjusted to ensure that the called function will have enough stack
+// available. Find those functions, and adjust their prologues.
+template <class ELFT>
+void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
+                                                         uint8_t *End) {
+  if (!getFile<ELFT>()->SplitStack)
+    return;
+  llvm::DenseSet<Defined *> AdjustedPrologues;
+  std::vector<Relocation *> MorestackCalls;
+
+  for (Relocation &Rel : Relocations) {
+    // Local symbols can't possibly be cross-calls, and should have been
+    // resolved long before this line.
+    if (Rel.Sym->isLocal())
+      continue;
+
+    Defined *D = dyn_cast<Defined>(Rel.Sym);
+    // A reference to an undefined symbol was an error, and should not
+    // have gotten to this point.
+    if (!D)
+      continue;
+
+    // Ignore calls into the split-stack api.
+    if (D->getName().startswith("__morestack")) {
+      if (D->getName().equals("__morestack"))
+        MorestackCalls.push_back(&Rel);
+      continue;
+    }
+
+    // A relocation to non-function isn't relevant. Sometimes
+    // __morestack is not marked as a function, so this check comes
+    // after the name check.
+    if (D->Type != STT_FUNC)
+      continue;
+
+    if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues))
+      continue;
+
+    if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
+      if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) {
+        AdjustedPrologues.insert(F);
+        continue;
+      }
+    }
+    if (!getFile<ELFT>()->SomeNoSplitStack)
+      error("function call at " + getErrorLocation(Buf + Rel.Offset) +
+            "crosses a split-stack boundary, but unable " +
+            "to adjust the enclosing function's prologue");
+  }
+  switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls);
+}
+
 template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
   if (Type == SHT_NOBITS)
     return;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Tue Jul 17 16:16:02 2018
@@ -106,7 +106,7 @@ public:
 
   static bool classof(const SectionBase *S) { return S->kind() != Output; }
 
-  // The file which contains this section. It's dynamic type is always
+  // The file which contains this section. Its dynamic type is always
   // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as
   // its static type.
   InputFile *File;
@@ -164,6 +164,11 @@ public:
 
   InputSection *getLinkOrderDep() const;
 
+  // Get the function symbol that encloses this offset from within the
+  // section.
+  template <class ELFT>
+  Defined *getEnclosingFunction(uint64_t Offset);
+
   // Compilers emit zlib-compressed debug sections if the -gz option
   // is given. This function checks if this section is compressed, and
   // if so, decompress in memory.
@@ -185,6 +190,15 @@ public:
   // This vector contains such "cooked" relocations.
   std::vector<Relocation> Relocations;
 
+  // A function compiled with -fsplit-stack calling a function
+  // compiled without -fsplit-stack needs its prologue adjusted. Find
+  // such functions and adjust their prologues.  This is very similar
+  // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more
+  // information.
+  template <typename ELFT>
+  void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End);
+
+
   template <typename T> llvm::ArrayRef<T> getDataAs() const {
     size_t S = Data.size();
     assert(S % sizeof(T) == 0);

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Tue Jul 17 16:16:02 2018
@@ -130,6 +130,12 @@ bool TargetInfo::needsThunk(RelExpr Expr
   return false;
 }
 
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc,
+                                                  uint8_t *End) const {
+  llvm_unreachable("Target doesn't support split stacks.");
+}
+
+
 bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
   return true;
 }

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=337332&r1=337331&r2=337332&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Tue Jul 17 16:16:02 2018
@@ -59,6 +59,13 @@ public:
   virtual bool needsThunk(RelExpr Expr, RelType RelocType,
                           const InputFile *File, uint64_t BranchAddr,
                           const Symbol &S) const;
+
+  // The function with a prologue starting at Loc was compiled with
+  // -fsplit-stack and it calls a function compiled without. Adjust the prologue
+  // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks.
+  virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc,
+                                                uint8_t *End) const;
+
   // Return true if we can reach Dst from Src with Relocation RelocType
   virtual bool inBranchRange(RelType Type, uint64_t Src,
                              uint64_t Dst) const;

Added: lld/trunk/test/ELF/Inputs/x86-64-split-stack-main.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/x86-64-split-stack-main.s?rev=337332&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/x86-64-split-stack-main.s (added)
+++ lld/trunk/test/ELF/Inputs/x86-64-split-stack-main.s Tue Jul 17 16:16:02 2018
@@ -0,0 +1,16 @@
+	.text
+
+	.global	non_split
+	.type	non_split, at function
+non_split:
+	retq
+	.size	non_split,. - non_split
+
+	.global non_function_text_symbol
+non_function_text_symbol:
+	.byte 0x01
+	.type	non_function_text_symbol, at STT_OBJECT
+	.size	non_function_text_symbol, 1
+
+
+	.section	.note.GNU-stack,"", at progbits

Removed: lld/trunk/test/ELF/splitstacks.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/splitstacks.s?rev=337331&view=auto
==============================================================================
--- lld/trunk/test/ELF/splitstacks.s (original)
+++ lld/trunk/test/ELF/splitstacks.s (removed)
@@ -1,11 +0,0 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
-
-# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: .o: object file compiled with -fsplit-stack is not supported
-
-.globl _start
-_start:
- nop
-
-.section .note.GNU-split-stack,"", at progbits

Added: lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-fail.s?rev=337332&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-fail.s (added)
+++ lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-fail.s Tue Jul 17 16:16:02 2018
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: not ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+
+# An unknown prologue gives a match failure
+# CHECK: unable to adjust the enclosing function's
+
+# RUN: not ld.lld -r --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s -check-prefix=RELOCATABLE
+# RELOCATABLE: Cannot mix split-stack and non-split-stack in a relocatable link
+
+	.text
+
+	.global	unknown_prologue
+	.type	unknown_prologue, at function
+unknown_prologue:
+	push	%rbp
+	mov	%rsp,%rbp
+	cmp	%fs:0x70,%rsp
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	callq	non_split
+	leaveq
+	retq
+
+	.size	unknown_prologue,. - unknown_prologue
+
+	.section	.note.GNU-split-stack,"", at progbits

Added: lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-silent.s?rev=337332&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-silent.s (added)
+++ lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-silent.s Tue Jul 17 16:16:02 2018
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t 2>&1 | FileCheck %s
+
+# An unknown prologue ordinarily gives a match failure, except that this
+# object file includes a .note.GNU-no-split-stack section, which tells the
+# linker to expect such prologues, and therefore not error.
+
+# CHECK: __morestack
+
+	.text
+
+	.global	unknown_prologue
+	.type	unknown_prologue, at function
+unknown_prologue:
+	push %rbp
+	mov %rsp,%rbp
+	cmp %fs:0x70,%rsp
+	jae 1f
+	callq __morestack
+	retq
+1:
+	callq non_split
+	leaveq
+	retq
+
+	.size unknown_prologue,. - unknown_prologue
+	.section .note.GNU-split-stack,"", at progbits
+	.section .note.GNU-no-split-stack,"", at progbits

Added: lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-success.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-success.s?rev=337332&view=auto
==============================================================================
--- lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-success.s (added)
+++ lld/trunk/test/ELF/x86-64-split-stack-prologue-adjust-success.s Tue Jul 17 16:16:02 2018
@@ -0,0 +1,124 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o
+
+# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t -z notext
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# Avoid duplicating the prologue for every test via macros.
+
+.macro prologue1 function_to_call
+	.global	prologue1_calls_\function_to_call
+	.type	prologue1_calls_\function_to_call, at function
+prologue1_calls_\function_to_call:
+	cmp %fs:0x70,%rsp
+	jae 1f
+	callq __morestack
+	retq
+1:
+	# Various and duplicate calls to ensure every code path is taken.
+	callq \function_to_call
+	callq \function_to_call
+	callq 1b
+	callq non_function_text_symbol
+	retq
+	.size	prologue1_calls_\function_to_call,. - prologue1_calls_\function_to_call
+.endm
+
+.macro prologue2 function_to_call register
+	.global	prologue2_calls_\function_to_call\register
+	.type	prologue2_calls_\function_to_call\register, at function
+prologue2_calls_\function_to_call\register:
+	lea	-0x200(%rsp),%\register
+	cmp	%fs:0x70,%\register
+	jae	1f
+	callq	__morestack
+	retq
+1:
+	# Various and duplicate calls to ensure every code path is taken.
+	callq	\function_to_call
+	callq	\function_to_call
+	callq 1b
+	callq non_function_text_symbol
+	retq
+	.size	prologue2_calls_\function_to_call\register,. - prologue2_calls_\function_to_call\register
+.endm
+
+	.local foo
+foo:
+	.section .text,"ax", at progbits
+	.quad foo
+
+	.text
+
+# For split-stack code calling split-stack code, ensure prologue v1 still
+# calls plain __morestack, and that any raw bytes written to the prologue
+# make sense.
+# CHECK: prologue1_calls_split:
+# CHECK-NEXT: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%rsp
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue1 split
+
+# For split-stack code calling split-stack code, ensure prologue v2 still
+# calls plain __morestack, that any raw bytes written to the prologue
+# make sense, and that the register number is preserved.
+# CHECK: prologue2_calls_splitr10:
+# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r10
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
+# CHECK: jae{{.*}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue2 split r10
+
+# CHECK: prologue2_calls_splitr11:
+# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r11
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
+# CHECK: jae{{.*}}
+# CHECK-NEXT: callq{{.*}}<__morestack>
+
+prologue2 split r11
+
+# For split-stack code calling non-split-stack code, ensure prologue v1
+# calls __morestack_non_split, and that any raw bytes written to the prologue
+# make sense.
+# CHECK: prologue1_calls_non_split:
+# CHECK-NEXT: stc{{.*$}}
+# CHECK-NEXT: nopl{{.*$}}
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue1 non_split
+
+# For split-stack code calling non-split-stack code, ensure prologue v2
+# calls __morestack_non_split, that any raw bytes written to the prologue
+# make sense, and that the register number is preserved
+# CHECK: prologue2_calls_non_splitr10:
+# CHECK-NEXT: lea{{.*$}}
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r10
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue2 non_split r10
+
+# CHECK: prologue2_calls_non_splitr11:
+# CHECK-NEXT: lea{{.*$}}
+# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r11
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+prologue2 non_split r11
+#	call foo at plt  # for code-coverage.
+
+
+
+	.global	split
+	.type	split, at function
+split:
+	retq
+
+	.size	split,. - split
+
+	.section	.note.GNU-stack,"", at progbits
+	.section	.note.GNU-split-stack,"", at progbits




More information about the llvm-commits mailing list