$OpenBSD: patch-lib_Target_Mips_MipsAsmPrinter_cpp,v 1.2 2020/01/07 22:59:43 jca Exp $

- Add retguard for octeon/mips64.
- Restore previous section after setting the MIPS ABI marker. This keeps
  the .text section in use after the file header, improving compatibility
  with gcc. Without this change, module-level inline assembly blocks could
  end up into wrong section.

Index: lib/Target/Mips/MipsAsmPrinter.cpp
--- lib/Target/Mips/MipsAsmPrinter.cpp.orig
+++ lib/Target/Mips/MipsAsmPrinter.cpp
@@ -241,6 +241,83 @@ void MipsAsmPrinter::EmitInstruction(const MachineInst
   case Mips::PATCHABLE_TAIL_CALL:
     LowerPATCHABLE_TAIL_CALL(*MI);
     return;
+  case Mips::RETGUARD_GET_FUNCTION_ADDR:
+    {
+      MCSymbol *PCSym = OutContext.createTempSymbol();
+      MCSymbol *FuncSym = OutContext.lookupSymbol(MI->getMF()->getName());
+      if (FuncSym == nullptr)
+        llvm_unreachable("Function name has no symbol");
+
+      // Branch and link forward, calculate the distance
+      // from here to the start of the function, and fill the
+      // address in the given dest register
+      unsigned OUT = MI->getOperand(0).getReg();
+      unsigned IN1 = MI->getOperand(1).getReg();
+      unsigned IN2 = MI->getOperand(2).getReg();
+      MCSymbol *ReturnSym = MI->getOperand(3).getMCSymbol();
+
+      // Save the value of RA in IN1
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64)
+          .addReg(IN1)
+          .addReg(Mips::RA_64)
+          .addReg(Mips::ZERO_64));
+      // BAL to get the PC into RA
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BAL)
+          .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)));
+      // NOP
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
+          .addReg(Mips::ZERO_64)
+          .addReg(Mips::ZERO_64)
+          .addImm(0));
+
+      // Emit a symbol for "here/PC" because BAL will put
+      // the address of the instruction following the NOP into RA
+      // and we need this symbol to do the math
+      OutStreamer->EmitLabel(PCSym);
+
+      // Store PC in IN2
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64)
+          .addReg(IN2)
+          .addReg(Mips::RA_64)
+          .addReg(Mips::ZERO_64));
+      // Restore original RA
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::OR64)
+          .addReg(Mips::RA_64)
+          .addReg(IN1)
+          .addReg(Mips::ZERO_64));
+      // Load the offset from PCSym to the start of the function
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::LUi64)
+          .addReg(IN1)
+          .addExpr(MipsMCExpr::create(MipsMCExpr::MipsExprKind::MEK_HI,
+              MCBinaryExpr::createSub(
+                MCSymbolRefExpr::create(PCSym, OutContext),
+                MCSymbolRefExpr::create(FuncSym, OutContext),
+                OutContext),
+              OutContext)));
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::DADDiu)
+          .addReg(IN1)
+          .addReg(IN1)
+          .addExpr(MipsMCExpr::create(MipsMCExpr::MipsExprKind::MEK_LO,
+              MCBinaryExpr::createSub(
+                MCSymbolRefExpr::create(PCSym, OutContext),
+                MCSymbolRefExpr::create(FuncSym, OutContext),
+                OutContext),
+              OutContext)));
+
+      // Sub distance from here to start of function
+      // to get address of the start of function
+      EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::DSUBu)
+          .addReg(OUT)
+          .addReg(IN2)
+          .addReg(IN1));
+      return;
+    }
+  case Mips::RETGUARD_EMIT_SYMBOL:
+    {
+      MCSymbol *ReturnSym = MI->getOperand(0).getMCSymbol();
+      OutStreamer->EmitLabel(ReturnSym);
+      return;
+    }
   }
 
   if (EmitJalrReloc &&
@@ -795,10 +872,12 @@ void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {
       TS.emitDirectiveOptionPic0();
   }
 
+  MCSection *CS = OutStreamer->getCurrentSectionOnly();
   // Tell the assembler which ABI we are using
   std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
   OutStreamer->SwitchSection(
       OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));
+  OutStreamer->SwitchSection(CS);
 
   // NaN: At the moment we only support:
   // 1. .nan legacy (default)
