SecBSD's official ports repository

This commit is contained in:
purplerain 2023-08-16 22:26:55 +00:00
commit 2c0afcbbf3
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
64331 changed files with 5339189 additions and 0 deletions

View file

@ -0,0 +1,14 @@
Properly parse library suffixes on OpenBSD
Index: cmake/modules/GetLibraryName.cmake
--- cmake/modules/GetLibraryName.cmake.orig
+++ cmake/modules/GetLibraryName.cmake
@@ -2,7 +2,7 @@
function(get_library_name path name)
get_filename_component(path ${path} NAME)
set(prefixes ${CMAKE_FIND_LIBRARY_PREFIXES})
- set(suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ set(suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES} ".so.[0-9]+.[0-9]+")
list(FILTER prefixes EXCLUDE REGEX "^\\s*$")
list(FILTER suffixes EXCLUDE REGEX "^\\s*$")
if(prefixes)

View file

@ -0,0 +1,16 @@
Avoid adding a dep on all headers in ${LOCALBASE}/include, not
compatible with dpb(1) junking.
Index: cmake/modules/LLVMProcessSources.cmake
--- cmake/modules/LLVMProcessSources.cmake.orig
+++ cmake/modules/LLVMProcessSources.cmake
@@ -46,6 +46,9 @@ function(find_all_header_files hdrs_out additional_hea
list(APPEND all_headers ${hds})
foreach(additional_dir ${additional_headerdirs})
+ if (${additional_dir} MATCHES "^${LOCALBASE}/include")
+ message(FATAL_ERROR "ports: refusing to scan ${additional_dir}")
+ endif()
add_header_files_for_glob(hds "${additional_dir}/*.h")
list(APPEND all_headers ${hds})
add_header_files_for_glob(hds "${additional_dir}/*.inc")

View file

@ -0,0 +1,21 @@
- support more than one input file in llvm-ranlib
Index: docs/CommandGuide/llvm-ranlib.rst
--- docs/CommandGuide/llvm-ranlib.rst.orig
+++ docs/CommandGuide/llvm-ranlib.rst
@@ -6,13 +6,13 @@ llvm-ranlib - generates an archive index
SYNOPSIS
--------
-:program:`llvm-ranlib` [*options*]
+:program:`llvm-ranlib` [*options*] *archive ...*
DESCRIPTION
-----------
:program:`llvm-ranlib` is an alias for the :doc:`llvm-ar <llvm-ar>` tool that
-generates an index for an archive. It can be used as a replacement for GNU's
+generates an index for one or more archives. It can be used as a replacement for GNU's
:program:`ranlib` tool.
Running :program:`llvm-ranlib` is equivalent to running ``llvm-ar s``.

View file

@ -0,0 +1,20 @@
- In the linkers, collect objects in section "openbsd.mutable" and place
them into a page-aligned region in the bss, with the right markers for
kernel/ld.so to identify the region and skip making it immutable.
- Implement support for PT_OPENBSD_NOBTCFI in lld(1). This can be set using
the -z nobtcfi option.
Index: include/llvm/BinaryFormat/ELF.h
--- include/llvm/BinaryFormat/ELF.h.orig
+++ include/llvm/BinaryFormat/ELF.h
@@ -1303,8 +1303,10 @@ enum {
PT_GNU_RELRO = 0x6474e552, // Read-only after relocation.
PT_GNU_PROPERTY = 0x6474e553, // .note.gnu.property notes sections.
+ PT_OPENBSD_MUTABLE = 0x65a3dbe5, // Like bss, but not immutable.
PT_OPENBSD_RANDOMIZE = 0x65a3dbe6, // Fill with random data.
PT_OPENBSD_WXNEEDED = 0x65a3dbe7, // Program does W^X violations.
+ PT_OPENBSD_NOBTCFI = 0x65a3dbe8, // Do not enforce branch target CFI
PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments.
// ARM program header types.

View file

@ -0,0 +1,29 @@
Use int3 trap padding between functions instead of trapsleds with a leading jump.
Index: include/llvm/CodeGen/AsmPrinter.h
--- include/llvm/CodeGen/AsmPrinter.h.orig
+++ include/llvm/CodeGen/AsmPrinter.h
@@ -434,6 +434,11 @@ class AsmPrinter : public MachineFunctionPass { (publi
/// correctness.
void emitAlignment(Align Alignment, const GlobalObject *GV = nullptr) const;
+ /// Emit an alignment directive to the specified power of two boundary,
+ /// like emitAlignment, but call emitTrapToAlignment to fill with
+ /// trap instructions instead of NOPs.
+ void emitTrapAlignment(Align Alignment, const GlobalObject *GO = nullptr) const;
+
/// Lower the specified LLVM Constant to an MCExpr.
virtual const MCExpr *lowerConstant(const Constant *CV);
@@ -499,6 +504,11 @@ class AsmPrinter : public MachineFunctionPass { (publi
virtual void emitInstruction(const MachineInstr *) {
llvm_unreachable("EmitInstruction not implemented");
}
+
+ /// Emit an alignment directive to the specified power
+ /// of two boundary, but use Trap instructions for alignment
+ /// sections that should never be executed.
+ virtual void emitTrapToAlignment(Align Alignment) const;
/// Return the symbol for the specified constant pool entry.
virtual MCSymbol *GetCPISymbol(unsigned CPID) const;

View file

@ -0,0 +1,56 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
Index: include/llvm/CodeGen/MachineFrameInfo.h
--- include/llvm/CodeGen/MachineFrameInfo.h.orig
+++ include/llvm/CodeGen/MachineFrameInfo.h
@@ -274,6 +274,15 @@ class MachineFrameInfo { (private)
/// The frame index for the stack protector.
int StackProtectorIdx = -1;
+ struct ReturnProtector {
+ /// The register to use for return protector calculations
+ unsigned Register = 0;
+ /// Set to true if this function needs return protectors
+ bool Needed = false;
+ /// Does the return protector cookie need to be stored in frame
+ bool NeedsStore = true;
+ } RPI;
+
/// The frame index for the function context. Used for SjLj exceptions.
int FunctionContextIdx = -1;
@@ -354,6 +363,17 @@ class MachineFrameInfo { (private)
int getStackProtectorIndex() const { return StackProtectorIdx; }
void setStackProtectorIndex(int I) { StackProtectorIdx = I; }
bool hasStackProtectorIndex() const { return StackProtectorIdx != -1; }
+
+ /// Get / Set return protector calculation register
+ unsigned getReturnProtectorRegister() const { return RPI.Register; }
+ void setReturnProtectorRegister(unsigned I) { RPI.Register = I; }
+ bool hasReturnProtectorRegister() const { return RPI.Register != 0; }
+ /// Get / Set if this frame needs a return protector
+ void setReturnProtectorNeeded(bool I) { RPI.Needed = I; }
+ bool getReturnProtectorNeeded() const { return RPI.Needed; }
+ /// Get / Set if the return protector cookie needs to be stored in frame
+ void setReturnProtectorNeedsStore(bool I) { RPI.NeedsStore = I; }
+ bool getReturnProtectorNeedsStore() const { return RPI.NeedsStore; }
/// Return the index for the function context object.
/// This object is used for SjLj exceptions.

View file

@ -0,0 +1,31 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: include/llvm/CodeGen/Passes.h
--- include/llvm/CodeGen/Passes.h.orig
+++ include/llvm/CodeGen/Passes.h
@@ -353,6 +353,9 @@ namespace llvm {
///
FunctionPass *createStackProtectorPass();
+ // createReturnProtectorPass - This pass add return protectors to functions.
+ FunctionPass *createReturnProtectorPass();
+
/// createMachineVerifierPass - This pass verifies cenerated machine code
/// instructions for correctness.
///

View file

@ -0,0 +1,88 @@
- Refactor retguard to make adding additional arches easier.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: include/llvm/CodeGen/ReturnProtectorLowering.h
--- include/llvm/CodeGen/ReturnProtectorLowering.h.orig
+++ include/llvm/CodeGen/ReturnProtectorLowering.h
@@ -0,0 +1,79 @@
+//===-- llvm/CodeGen/ReturnProtectorLowering.h ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A class to insert and lower the return protector instrumentation
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_RETURNPROTECTORLOWERING_H
+#define LLVM_CODEGEN_RETURNPROTECTORLOWERING_H
+
+#include "llvm/ADT/SmallVector.h"
+
+#include <utility>
+#include <vector>
+
+namespace llvm {
+class CalleeSavedInfo;
+class GlobalVariable;
+class MachineBasicBlock;
+class MachineFunction;
+class MachineInstr;
+
+class ReturnProtectorLowering {
+public:
+ virtual ~ReturnProtectorLowering() {}
+ /// Subclass interface - subclasses need to implement these functions.
+
+ /// insertReturnProtectorPrologue/Epilogue - insert return protector
+ /// instrumentation in prologue or epilogue.
+ virtual void insertReturnProtectorPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ GlobalVariable *cookie) const {}
+ virtual void insertReturnProtectorEpilogue(MachineFunction &MF,
+ MachineInstr &MI,
+ GlobalVariable *cookie) const {}
+
+ /// opcodeIsReturn - Reuturn true is the given opcode is a return
+ /// instruction needing return protection, false otherwise.
+ virtual bool opcodeIsReturn(unsigned opcode) const { return false; }
+
+ /// fillTempRegisters - Fill the list of available temp registers we can
+ /// use as a CalculationRegister.
+ virtual void fillTempRegisters(MachineFunction &MF,
+ std::vector<unsigned> &TempRegs) const {}
+
+ /// Generic public interface used by llvm
+
+ /// setupReturnProtector - Checks the function for ROP friendly return
+ /// instructions and sets ReturnProtectorNeeded in the frame if found.
+ virtual void setupReturnProtector(MachineFunction &MF) const;
+
+ /// saveReturnProtectorRegister - Allows the target to save the
+ /// CalculationRegister in the CalleeSavedInfo vector if needed.
+ virtual void
+ saveReturnProtectorRegister(MachineFunction &MF,
+ std::vector<CalleeSavedInfo> &CSI) const;
+
+ /// determineReturnProtectorTempRegister - Find a register that can be used
+ /// during function prologue / epilogue to store the return protector cookie.
+ /// Returns false if a register is needed but could not be found,
+ /// otherwise returns true.
+ virtual bool determineReturnProtectorRegister(
+ MachineFunction &MF,
+ const SmallVector<MachineBasicBlock *, 4> &SaveBlocks,
+ const SmallVector<MachineBasicBlock *, 4> &RestoreBlocks) const;
+
+ /// insertReturnProtectors - insert return protector instrumentation.
+ virtual void insertReturnProtectors(MachineFunction &MF) const;
+};
+
+} // namespace llvm
+
+#endif

View file

@ -0,0 +1,41 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
Index: include/llvm/CodeGen/TargetFrameLowering.h
--- include/llvm/CodeGen/TargetFrameLowering.h.orig
+++ include/llvm/CodeGen/TargetFrameLowering.h
@@ -14,6 +14,7 @@
#define LLVM_CODEGEN_TARGETFRAMELOWERING_H
#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
#include "llvm/Support/TypeSize.h"
#include <vector>
@@ -209,6 +210,10 @@ class TargetFrameLowering { (public)
MachineBasicBlock &MBB) const = 0;
virtual void emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const = 0;
+
+ virtual const ReturnProtectorLowering *getReturnProtector() const {
+ return nullptr;
+ }
/// With basic block sections, emit callee saved frame moves for basic blocks
/// that are in a different section.

View file

@ -0,0 +1,29 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: include/llvm/InitializePasses.h
--- include/llvm/InitializePasses.h.orig
+++ include/llvm/InitializePasses.h
@@ -387,6 +387,7 @@ void initializeRemoveRedundantDebugValuesPass(PassRegi
void initializeRenameIndependentSubregsPass(PassRegistry&);
void initializeReplaceWithVeclibLegacyPass(PassRegistry &);
void initializeResetMachineFunctionPass(PassRegistry&);
+void initializeReturnProtectorPass(PassRegistry&);
void initializeReversePostOrderFunctionAttrsLegacyPassPass(PassRegistry&);
void initializeRewriteStatepointsForGCLegacyPassPass(PassRegistry &);
void initializeRewriteSymbolsLegacyPassPass(PassRegistry&);

View file

@ -0,0 +1,68 @@
- Use int3 trap padding between functions instead of trapsleds with a leading jump.
- Emit trap alignment between basic blocks that are unreachable via
fallthrough. Avoids unnecessary jmp instructions in the middle
of functions and makes disassembly nicer to read.
Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp
--- lib/CodeGen/AsmPrinter/AsmPrinter.cpp.orig
+++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -745,7 +745,7 @@ void AsmPrinter::emitFunctionHeader() {
emitLinkage(&F, CurrentFnSym);
if (MAI->hasFunctionAlignment())
- emitAlignment(MF->getAlignment(), &F);
+ emitTrapAlignment(MF->getAlignment(), &F);
if (MAI->hasDotTypeDotSizeDirective())
OutStreamer->emitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction);
@@ -2462,6 +2462,30 @@ void AsmPrinter::emitAlignment(Align Alignment, const
}
//===----------------------------------------------------------------------===//
+/// emitTrapAlignment - Emit an alignment directive to the specified power of
+/// two boundary, but call emitTrapToAlignment to fill with Trap instructions
+/// if the Target implements emitTrapToAlignment.
+void AsmPrinter::emitTrapAlignment(Align Alignment, const GlobalObject *GV) const {
+ if (GV)
+ Alignment = getGVAlignment(GV, GV->getParent()->getDataLayout(), Alignment);
+
+ if (Alignment == Align(1)) return; // 1-byte aligned: no need to emit alignment.
+
+ emitTrapToAlignment(Alignment);
+}
+
+//===----------------------------------------------------------------------===//
+/// emitTrapToAlignment - Emit an alignment directive to the specified power
+/// of two boundary. This default implementation calls EmitCodeAlignment on
+/// the OutStreamer, but can be overridden by Target implementations.
+void AsmPrinter::emitTrapToAlignment(Align Alignment) const {
+ if (Alignment == Align(1)) return;
+ OutStreamer->emitCodeAlignment(Alignment.value());
+}
+
+
+
+//===----------------------------------------------------------------------===//
// Constant emission.
//===----------------------------------------------------------------------===//
@@ -3246,10 +3270,17 @@ void AsmPrinter::emitBasicBlockStart(const MachineBasi
}
}
+ bool isReachableViaFallthrough =
+ std::find(MBB.pred_begin(), MBB.pred_end(), MBB.getPrevNode()) !=
+ MBB.pred_end();
// Emit an alignment directive for this block, if needed.
const Align Alignment = MBB.getAlignment();
- if (Alignment != Align(1))
- emitAlignment(Alignment);
+ if (Alignment != Align(1)) {
+ if (isReachableViaFallthrough)
+ emitAlignment(Alignment);
+ else
+ emitTrapAlignment(Alignment);
+ }
// Switch to a new section if this basic block must begin a section. The
// entry block is always placed in the function section and is handled

View file

@ -0,0 +1,31 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
Index: lib/CodeGen/CMakeLists.txt
--- lib/CodeGen/CMakeLists.txt.orig
+++ lib/CodeGen/CMakeLists.txt
@@ -153,6 +153,8 @@ add_llvm_component_library(LLVMCodeGen
RegUsageInfoPropagate.cpp
ReplaceWithVeclib.cpp
ResetMachineFunctionPass.cpp
+ ReturnProtectorLowering.cpp
+ ReturnProtectorPass.cpp
SafeStack.cpp
SafeStackLayout.cpp
ScheduleDAG.cpp

View file

@ -0,0 +1,97 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
Index: lib/CodeGen/PrologEpilogInserter.cpp
--- lib/CodeGen/PrologEpilogInserter.cpp.orig
+++ lib/CodeGen/PrologEpilogInserter.cpp
@@ -213,7 +213,11 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
const Function &F = MF.getFunction();
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+ const ReturnProtectorLowering *RPL = TFI->getReturnProtector();
+ if (RPL)
+ RPL->setupReturnProtector(MF);
+
RS = TRI->requiresRegisterScavenging(MF) ? new RegScavenger() : nullptr;
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(MF);
ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
@@ -251,6 +255,10 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
if (!F.hasFnAttribute(Attribute::Naked))
insertPrologEpilogCode(MF);
+ // Add Return Protectors if using them
+ if (RPL)
+ RPL->insertReturnProtectors(MF);
+
// Reinsert stashed debug values at the start of the entry blocks.
for (auto &I : EntryDbgValues)
I.first->insert(I.first->begin(), I.second.begin(), I.second.end());
@@ -357,7 +365,9 @@ void PEI::calculateCallFrameInfo(MachineFunction &MF)
/// Compute the sets of entry and return blocks for saving and restoring
/// callee-saved registers, and placing prolog and epilog code.
void PEI::calculateSaveRestoreBlocks(MachineFunction &MF) {
- const MachineFrameInfo &MFI = MF.getFrameInfo();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+ const ReturnProtectorLowering *RPL = TFI->getReturnProtector();
// Even when we do not change any CSR, we still want to insert the
// prologue and epilogue of the function.
@@ -373,7 +383,18 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &
// epilogue.
if (!RestoreBlock->succ_empty() || RestoreBlock->isReturnBlock())
RestoreBlocks.push_back(RestoreBlock);
- return;
+
+ // If we are adding return protectors ensure we can find a free register
+ if (RPL &&
+ !RPL->determineReturnProtectorRegister(MF, SaveBlocks, RestoreBlocks)) {
+ // Shrinkwrapping will prevent finding a free register
+ SaveBlocks.clear();
+ RestoreBlocks.clear();
+ MFI.setSavePoint(nullptr);
+ MFI.setRestorePoint(nullptr);
+ } else {
+ return;
+ }
}
// Save refs to entry and return blocks.
@@ -384,6 +405,9 @@ void PEI::calculateSaveRestoreBlocks(MachineFunction &
if (MBB.isReturnBlock())
RestoreBlocks.push_back(&MBB);
}
+
+ if (RPL)
+ RPL->determineReturnProtectorRegister(MF, SaveBlocks, RestoreBlocks);
}
static void assignCalleeSavedSpillSlots(MachineFunction &F,
@@ -405,6 +429,10 @@ static void assignCalleeSavedSpillSlots(MachineFunctio
const TargetFrameLowering *TFI = F.getSubtarget().getFrameLowering();
MachineFrameInfo &MFI = F.getFrameInfo();
+
+ if (TFI->getReturnProtector())
+ TFI->getReturnProtector()->saveReturnProtectorRegister(F, CSI);
+
if (!TFI->assignCalleeSavedSpillSlots(F, RegInfo, CSI, MinCSFrameIndex,
MaxCSFrameIndex)) {
// If target doesn't implement this, use generic code.

View file

@ -0,0 +1,348 @@
- Refactor retguard to make adding additional arches easier.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: lib/CodeGen/ReturnProtectorLowering.cpp
--- lib/CodeGen/ReturnProtectorLowering.cpp.orig
+++ lib/CodeGen/ReturnProtectorLowering.cpp
@@ -0,0 +1,339 @@
+//===- ReturnProtectorLowering.cpp - ---------------------------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements common routines for return protector support.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+
+using namespace llvm;
+
+static void markUsedRegsInSuccessors(MachineBasicBlock &MBB,
+ SmallSet<unsigned, 16> &Used,
+ SmallSet<int, 24> &Visited) {
+ int BBNum = MBB.getNumber();
+ if (Visited.count(BBNum))
+ return;
+
+ // Mark all the registers used
+ for (auto &MBBI : MBB.instrs()) {
+ for (auto &MBBIOp : MBBI.operands()) {
+ if (MBBIOp.isReg())
+ Used.insert(MBBIOp.getReg());
+ }
+ }
+
+ // Mark this MBB as visited
+ Visited.insert(BBNum);
+ // Recurse over all successors
+ for (auto &SuccMBB : MBB.successors())
+ markUsedRegsInSuccessors(*SuccMBB, Used, Visited);
+}
+
+static bool containsProtectableData(Type *Ty) {
+ if (!Ty)
+ return false;
+
+ if (ArrayType *AT = dyn_cast<ArrayType>(Ty))
+ return true;
+
+ if (StructType *ST = dyn_cast<StructType>(Ty)) {
+ for (StructType::element_iterator I = ST->element_begin(),
+ E = ST->element_end();
+ I != E; ++I) {
+ if (containsProtectableData(*I))
+ return true;
+ }
+ }
+ return false;
+}
+
+// Mostly the same as StackProtector::HasAddressTaken
+static bool hasAddressTaken(const Instruction *AI,
+ SmallPtrSet<const PHINode *, 16> &visitedPHI) {
+ for (const User *U : AI->users()) {
+ const auto *I = cast<Instruction>(U);
+ switch (I->getOpcode()) {
+ case Instruction::Store:
+ if (AI == cast<StoreInst>(I)->getValueOperand())
+ return true;
+ break;
+ case Instruction::AtomicCmpXchg:
+ if (AI == cast<AtomicCmpXchgInst>(I)->getNewValOperand())
+ return true;
+ break;
+ case Instruction::PtrToInt:
+ if (AI == cast<PtrToIntInst>(I)->getOperand(0))
+ return true;
+ break;
+ case Instruction::BitCast:
+ case Instruction::GetElementPtr:
+ case Instruction::Select:
+ case Instruction::AddrSpaceCast:
+ if (hasAddressTaken(I, visitedPHI))
+ return true;
+ break;
+ case Instruction::PHI: {
+ const auto *PN = cast<PHINode>(I);
+ if (visitedPHI.insert(PN).second)
+ if (hasAddressTaken(PN, visitedPHI))
+ return true;
+ break;
+ }
+ case Instruction::Load:
+ case Instruction::AtomicRMW:
+ case Instruction::Ret:
+ return false;
+ break;
+ default:
+ // Conservatively return true for any instruction that takes an address
+ // operand, but is not handled above.
+ return true;
+ }
+ }
+ return false;
+}
+
+/// setupReturnProtector - Checks the function for ROP friendly return
+/// instructions and sets ReturnProtectorNeeded if found.
+void ReturnProtectorLowering::setupReturnProtector(MachineFunction &MF) const {
+ if (MF.getFunction().hasFnAttribute("ret-protector")) {
+ for (auto &MBB : MF) {
+ for (auto &T : MBB.terminators()) {
+ if (opcodeIsReturn(T.getOpcode())) {
+ MF.getFrameInfo().setReturnProtectorNeeded(true);
+ return;
+ }
+ }
+ }
+ }
+}
+
+/// saveReturnProtectorRegister - Allows the target to save the
+/// ReturnProtectorRegister in the CalleeSavedInfo vector if needed.
+void ReturnProtectorLowering::saveReturnProtectorRegister(
+ MachineFunction &MF, std::vector<CalleeSavedInfo> &CSI) const {
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (!MFI.getReturnProtectorNeeded())
+ return;
+
+ if (!MFI.hasReturnProtectorRegister())
+ llvm_unreachable("Saving unset return protector register");
+
+ unsigned Reg = MFI.getReturnProtectorRegister();
+ if (MFI.getReturnProtectorNeedsStore())
+ CSI.push_back(CalleeSavedInfo(Reg));
+ else {
+ for (auto &MBB : MF) {
+ if (!MBB.isLiveIn(Reg))
+ MBB.addLiveIn(Reg);
+ }
+ }
+}
+
+/// determineReturnProtectorTempRegister - Find a register that can be used
+/// during function prologue / epilogue to store the return protector cookie.
+/// Returns false if a register is needed but could not be found,
+/// otherwise returns true.
+bool ReturnProtectorLowering::determineReturnProtectorRegister(
+ MachineFunction &MF, const SmallVector<MachineBasicBlock *, 4> &SaveBlocks,
+ const SmallVector<MachineBasicBlock *, 4> &RestoreBlocks) const {
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (!MFI.getReturnProtectorNeeded())
+ return true;
+
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+
+ std::vector<unsigned> TempRegs;
+ fillTempRegisters(MF, TempRegs);
+
+ // For leaf functions, try to find a free register that is available
+ // in every BB, so we do not need to store it in the frame at all.
+ // We walk the entire function here because MFI.hasCalls() is unreliable.
+ bool hasCalls = false;
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
+ if (MI.isCall() && !MI.isReturn()) {
+ hasCalls = true;
+ break;
+ }
+ }
+ if (hasCalls)
+ break;
+ }
+
+ // If the return address is always on the stack, then we
+ // want to try to keep the return protector cookie unspilled.
+ // This prevents a single stack smash from corrupting both the
+ // return protector cookie and the return address.
+ llvm::Triple::ArchType arch = MF.getTarget().getTargetTriple().getArch();
+ bool returnAddrOnStack = arch == llvm::Triple::ArchType::x86
+ || arch == llvm::Triple::ArchType::x86_64;
+
+ // For architectures which do not spill a return address
+ // to the stack by default, it is possible that in a leaf
+ // function that neither the return address or the retguard cookie
+ // will be spilled, and stack corruption may be missed.
+ // Here, we check leaf functions on these kinds of architectures
+ // to see if they have any variable sized local allocations,
+ // array type allocations, allocations which contain array
+ // types, or elements that have their address taken. If any of
+ // these conditions are met, then we skip leaf function
+ // optimization and spill the retguard cookie to the stack.
+ bool hasLocals = MFI.hasVarSizedObjects();
+ if (!hasCalls && !hasLocals && !returnAddrOnStack) {
+ for (const BasicBlock &BB : MF.getFunction()) {
+ for (const Instruction &I : BB) {
+ if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
+ // Check for array allocations
+ Type *Ty = AI->getAllocatedType();
+ if (AI->isArrayAllocation() || containsProtectableData(Ty)) {
+ hasLocals = true;
+ break;
+ }
+ // Check for address taken
+ SmallPtrSet<const PHINode *, 16> visitedPHIs;
+ if (hasAddressTaken(AI, visitedPHIs)) {
+ hasLocals = true;
+ break;
+ }
+ }
+ }
+ if (hasLocals)
+ break;
+ }
+ }
+
+ bool tryLeafOptimize = !hasCalls && (returnAddrOnStack || !hasLocals);
+
+ if (tryLeafOptimize) {
+ SmallSet<unsigned, 16> LeafUsed;
+ SmallSet<int, 24> LeafVisited;
+ markUsedRegsInSuccessors(MF.front(), LeafUsed, LeafVisited);
+ for (unsigned Reg : TempRegs) {
+ bool canUse = true;
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
+ if (LeafUsed.count(*AI)) {
+ canUse = false;
+ break;
+ }
+ }
+ if (canUse) {
+ MFI.setReturnProtectorRegister(Reg);
+ MFI.setReturnProtectorNeedsStore(false);
+ return true;
+ }
+ }
+ }
+
+ // For non-leaf functions, we only need to search save / restore blocks
+ SmallSet<unsigned, 16> Used;
+ SmallSet<int, 24> Visited;
+
+ // CSR spills happen at the beginning of this block
+ // so we can mark it as visited because anything past it is safe
+ for (auto &SB : SaveBlocks)
+ Visited.insert(SB->getNumber());
+
+ // CSR Restores happen at the end of restore blocks, before any terminators,
+ // so we need to search restores for MBB terminators, and any successor BBs.
+ for (auto &RB : RestoreBlocks) {
+ for (auto &RBI : RB->terminators()) {
+ for (auto &RBIOp : RBI.operands()) {
+ if (RBIOp.isReg())
+ Used.insert(RBIOp.getReg());
+ }
+ }
+ for (auto &SuccMBB : RB->successors())
+ markUsedRegsInSuccessors(*SuccMBB, Used, Visited);
+ }
+
+ // Now we iterate from the front to find code paths that
+ // bypass save blocks and land on return blocks
+ markUsedRegsInSuccessors(MF.front(), Used, Visited);
+
+ // Now we have gathered all the regs used outside the frame save / restore,
+ // so we can see if we have a free reg to use for the retguard cookie.
+ for (unsigned Reg : TempRegs) {
+ bool canUse = true;
+ for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) {
+ if (Used.count(*AI)) {
+ // Reg is used somewhere, so we cannot use it
+ canUse = false;
+ break;
+ }
+ }
+ if (canUse) {
+ MFI.setReturnProtectorRegister(Reg);
+ break;
+ }
+ }
+
+ return MFI.hasReturnProtectorRegister();
+}
+
+/// insertReturnProtectors - insert return protector instrumentation.
+void ReturnProtectorLowering::insertReturnProtectors(
+ MachineFunction &MF) const {
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+
+ if (!MFI.getReturnProtectorNeeded())
+ return;
+
+ if (!MFI.hasReturnProtectorRegister())
+ llvm_unreachable("Inconsistent return protector state.");
+
+ const Function &Fn = MF.getFunction();
+ const Module *M = Fn.getParent();
+ GlobalVariable *cookie =
+ dyn_cast_or_null<GlobalVariable>(M->getGlobalVariable(
+ Fn.getFnAttribute("ret-protector-cookie").getValueAsString(),
+ Type::getInt8PtrTy(M->getContext())));
+
+ if (!cookie)
+ llvm_unreachable("Function needs return protector but no cookie assigned");
+
+ unsigned Reg = MFI.getReturnProtectorRegister();
+
+ std::vector<MachineInstr *> returns;
+ for (auto &MBB : MF) {
+ if (MBB.isReturnBlock()) {
+ for (auto &MI : MBB.terminators()) {
+ if (opcodeIsReturn(MI.getOpcode())) {
+ returns.push_back(&MI);
+ if (!MBB.isLiveIn(Reg))
+ MBB.addLiveIn(Reg);
+ }
+ }
+ }
+ }
+
+ if (returns.empty())
+ return;
+
+ for (auto &MI : returns)
+ insertReturnProtectorEpilogue(MF, *MI, cookie);
+
+ insertReturnProtectorPrologue(MF, MF.front(), cookie);
+
+ if (!MF.front().isLiveIn(Reg))
+ MF.front().addLiveIn(Reg);
+}

View file

@ -0,0 +1,91 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Put the new retguard symbols in their own section,
'.openbsd.randomdata.retguard', to make them easier to work with in the
kernel hibernate code.
- Move the hashed __retguard_* symbols into individual sections and mark
them as COMDATs so that the linker can individually discard them, instead
of just ignoring duplicate symbols but keep the (duplicate) space.
Index: lib/CodeGen/ReturnProtectorPass.cpp
--- lib/CodeGen/ReturnProtectorPass.cpp.orig
+++ lib/CodeGen/ReturnProtectorPass.cpp
@@ -0,0 +1,63 @@
+//===- ReturnProtectorPass.cpp - Set up rteurn protectors -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass sets up functions for return protectors.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "return-protector"
+
+STATISTIC(NumSymbols, "Counts number of cookie symbols added");
+
+namespace {
+ struct ReturnProtector : public FunctionPass {
+ static char ID;
+ ReturnProtector() : FunctionPass(ID) {}
+
+ bool runOnFunction(Function &F) override {
+ if (F.hasFnAttribute("ret-protector")) {
+ // Create a symbol for the cookie
+ Module *M = F.getParent();
+ std::hash<std::string> hasher;
+ std::string hash = std::to_string(hasher((M->getName() + F.getName()).str()) % 4000);
+ std::string cookiename = "__retguard_" + hash;
+ Type *cookietype = Type::getInt8PtrTy(M->getContext());
+ GlobalVariable *cookie = dyn_cast_or_null<GlobalVariable>(
+ M->getOrInsertGlobal(cookiename, cookietype));
+ cookie->setInitializer(Constant::getNullValue(cookietype));
+ cookie->setLinkage(GlobalVariable::LinkOnceAnyLinkage);
+ cookie->setVisibility(GlobalValue::HiddenVisibility);
+ cookie->setComdat(M->getOrInsertComdat(cookiename));
+ cookie->setSection(".openbsd.randomdata.retguard." + hash);
+ cookie->setExternallyInitialized(true);
+ F.addFnAttr("ret-protector-cookie", cookiename);
+ NumSymbols++;
+ }
+ return false;
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ }
+ };
+}
+
+char ReturnProtector::ID = 0;
+INITIALIZE_PASS(ReturnProtector, "return-protector", "Return Protector Pass",
+ false, false)
+FunctionPass *llvm::createReturnProtectorPass() { return new ReturnProtector(); }

View file

@ -0,0 +1,30 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: lib/CodeGen/TargetPassConfig.cpp
--- lib/CodeGen/TargetPassConfig.cpp.orig
+++ lib/CodeGen/TargetPassConfig.cpp
@@ -950,6 +950,8 @@ void TargetPassConfig::addISelPrepare() {
if (requiresCodeGenSCCOrder())
addPass(new DummyCGSCCPass);
+ addPass(createReturnProtectorPass());
+
// Add both the safe stack and the stack protection passes: each of them will
// only protect functions that have corresponding attributes.
addPass(createSafeStackPass());

View file

@ -0,0 +1,14 @@
Do not use ident.
Index: lib/MC/MCAsmInfoELF.cpp
--- lib/MC/MCAsmInfoELF.cpp.orig
+++ lib/MC/MCAsmInfoELF.cpp
@@ -25,7 +25,7 @@ MCSection *MCAsmInfoELF::getNonexecutableStackSection(
}
MCAsmInfoELF::MCAsmInfoELF() {
- HasIdentDirective = true;
+ HasIdentDirective = false;
WeakRefDirective = "\t.weak\t";
PrivateGlobalPrefix = ".L";
PrivateLabelPrefix = ".L";

View file

@ -0,0 +1,19 @@
getNonexecutableStackSection() may return nullptr.
Index: lib/MC/MCELFStreamer.cpp
--- lib/MC/MCELFStreamer.cpp.orig
+++ lib/MC/MCELFStreamer.cpp
@@ -93,8 +93,11 @@ void MCELFStreamer::InitSections(bool NoExecStack) {
SwitchSection(Ctx.getObjectFileInfo()->getTextSection());
emitCodeAlignment(4);
- if (NoExecStack)
- SwitchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx));
+ if (NoExecStack) {
+ MCSection *s = Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx);
+ if (s)
+ SwitchSection(s);
+ }
}
void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {

View file

@ -0,0 +1,22 @@
make clang include a FILE symbol for .(s|S) files
This is mostly needed by syspatch at the moment to be
to be able to re-link in the same order as the original
libraries were linked with by relying on the readelf(1)
and without this .(s|S) assembly files were not getting
a file directive.
Index: lib/MC/MCParser/AsmParser.cpp
--- lib/MC/MCParser/AsmParser.cpp.orig
+++ lib/MC/MCParser/AsmParser.cpp
@@ -975,6 +975,10 @@ bool AsmParser::Run(bool NoInitialTextSection, bool No
(void)InsertResult;
}
+ StringRef Filename = getContext().getMainFileName();
+ if (!Filename.empty() && (Filename.compare(StringRef("-")) != 0))
+ Out.emitFileDirective(Filename);
+
getTargetParser().onBeginOfFile();
// While we have input, parse each statement.

View file

@ -0,0 +1,25 @@
Add retguard for arm64.
Index: lib/Target/AArch64/AArch64AsmPrinter.cpp
--- lib/Target/AArch64/AArch64AsmPrinter.cpp.orig
+++ lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -1488,6 +1488,19 @@ void AArch64AsmPrinter::emitInstruction(const MachineI
case AArch64::SEH_EpilogEnd:
TS->emitARM64WinCFIEpilogEnd();
return;
+
+ case AArch64::RETGUARD_JMP_TRAP:
+ {
+ MCSymbol *RGSuccSym = OutContext.createTempSymbol();
+ /* Compare and branch */
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CBZX)
+ .addReg(MI->getOperand(0).getReg())
+ .addExpr(MCSymbolRefExpr::create(RGSuccSym, OutContext)));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(1));
+ OutStreamer->emitLabel(RGSuccSym);
+ return;
+ }
+
}
// Finally, do the automated lowerings for everything else.

View file

@ -0,0 +1,35 @@
Add retguard for arm64.
Index: lib/Target/AArch64/AArch64FrameLowering.cpp
--- lib/Target/AArch64/AArch64FrameLowering.cpp.orig
+++ lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -123,6 +123,7 @@
#include "AArch64InstrInfo.h"
#include "AArch64MachineFunctionInfo.h"
#include "AArch64RegisterInfo.h"
+#include "AArch64ReturnProtectorLowering.h"
#include "AArch64Subtarget.h"
#include "AArch64TargetMachine.h"
#include "MCTargetDesc/AArch64AddressingModes.h"
@@ -2753,6 +2754,10 @@ void AArch64FrameLowering::determineCalleeSaves(Machin
? RegInfo->getBaseRegister()
: (unsigned)AArch64::NoRegister;
+ if (MFI.hasReturnProtectorRegister() && MFI.getReturnProtectorNeedsStore()) {
+ SavedRegs.set(MFI.getReturnProtectorRegister());
+ }
+
unsigned ExtraCSSpill = 0;
// Figure out which callee-saved registers to save/restore.
for (unsigned i = 0; CSRegs[i]; ++i) {
@@ -3532,6 +3537,10 @@ unsigned AArch64FrameLowering::getWinEHFuncletFrameSiz
// This is the amount of stack a funclet needs to allocate.
return alignTo(CSSize + MF.getFrameInfo().getMaxCallFrameSize(),
getStackAlign());
+}
+
+const ReturnProtectorLowering *AArch64FrameLowering::getReturnProtector() const {
+ return &RPL;
}
namespace {

View file

@ -0,0 +1,36 @@
Add retguard for arm64.
Index: lib/Target/AArch64/AArch64FrameLowering.h
--- lib/Target/AArch64/AArch64FrameLowering.h.orig
+++ lib/Target/AArch64/AArch64FrameLowering.h
@@ -13,6 +13,7 @@
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
+#include "AArch64ReturnProtectorLowering.h"
#include "llvm/Support/TypeSize.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
@@ -22,9 +23,12 @@ class MCCFIInstruction;
class AArch64FrameLowering : public TargetFrameLowering {
public:
+
+ const AArch64ReturnProtectorLowering RPL;
+
explicit AArch64FrameLowering()
: TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16),
- true /*StackRealignable*/) {}
+ true /*StackRealignable*/), RPL() {}
void
emitCalleeSavedFrameMoves(MachineBasicBlock &MBB,
@@ -38,6 +42,8 @@ class AArch64FrameLowering : public TargetFrameLowerin
/// the function.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+
+ const ReturnProtectorLowering *getReturnProtector() const override;
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;

View file

@ -0,0 +1,17 @@
Disable the Load Stack Guard for OpenBSD on AArch64. We don't use it
on any other platform and it causes a segfault in combination with our
IR Stack Guard.
Index: lib/Target/AArch64/AArch64ISelLowering.cpp
--- lib/Target/AArch64/AArch64ISelLowering.cpp.orig
+++ lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -17364,7 +17364,8 @@ void AArch64TargetLowering::ReplaceNodeResults(
}
bool AArch64TargetLowering::useLoadStackGuardNode() const {
- if (Subtarget->isTargetAndroid() || Subtarget->isTargetFuchsia())
+ if (Subtarget->isTargetAndroid() || Subtarget->isTargetFuchsia() ||
+ Subtarget->isTargetOpenBSD())
return TargetLowering::useLoadStackGuardNode();
return true;
}

View file

@ -0,0 +1,15 @@
XXX no comment
Index: lib/Target/AArch64/AArch64InstrInfo.cpp
--- lib/Target/AArch64/AArch64InstrInfo.cpp.orig
+++ lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -97,6 +97,9 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const Ma
default:
// Anything not explicitly designated otherwise is a normal 4-byte insn.
NumBytes = 4;
+
+ if (Desc.getSize() > 0)
+ NumBytes = Desc.getSize();
break;
case TargetOpcode::STACKMAP:
// The upper bound for a stackmap intrinsic is the full length of its shadow

View file

@ -0,0 +1,20 @@
Add retguard for arm64.
Index: lib/Target/AArch64/AArch64InstrInfo.td
--- lib/Target/AArch64/AArch64InstrInfo.td.orig
+++ lib/Target/AArch64/AArch64InstrInfo.td
@@ -721,6 +721,14 @@ def ADDlowTLS
} // isReMaterializable, isCodeGenOnly
+//===----------------------------------------------------------------------===//
+// Pseudo instruction used by retguard
+let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
+ let Size = 8 in {
+ def RETGUARD_JMP_TRAP: Pseudo<(outs), (ins GPR64:$reg), []>;
+ }
+}
+
def : Pat<(AArch64LOADgot tglobaltlsaddr:$addr),
(LOADgot tglobaltlsaddr:$addr)>;

View file

@ -0,0 +1,135 @@
- Add retguard for arm64.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
- Fix frame pointer slot on aarch64 for functions that do not save callee
registers with retguard enabled.
Index: lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp
--- lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp.orig
+++ lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp
@@ -0,0 +1,124 @@
+//===-- AArch64ReturnProtectorLowering.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the AArch64 implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AArch64InstrInfo.h"
+#include "AArch64MachineFunctionInfo.h"
+#include "AArch64RegisterInfo.h"
+#include "AArch64ReturnProtectorLowering.h"
+#include "AArch64Subtarget.h"
+#include "AArch64TargetMachine.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+void AArch64ReturnProtectorLowering::insertReturnProtectorPrologue(
+ MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
+
+ MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
+ DebugLoc MBBDL = MBB.findDebugLoc(MI);
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), REG)
+ .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), REG)
+ .addReg(REG)
+ .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::EORXrr), REG)
+ .addReg(REG)
+ .addReg(AArch64::LR);
+}
+
+void AArch64ReturnProtectorLowering::insertReturnProtectorEpilogue(
+ MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc MBBDL = MI.getDebugLoc();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ MBB.addLiveIn(AArch64::X9);
+ // REG holds the cookie we calculated in prologue. We use X9 as a
+ // scratch reg to pull the random data. XOR REG with LR should yield
+ // the random data again. Compare REG with X9 to check.
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::EORXrr), REG)
+ .addReg(REG)
+ .addReg(AArch64::LR);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::ADRP), AArch64::X9)
+ .addGlobalAddress(cookie, 0, AArch64II::MO_PAGE);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::LDRXui), AArch64::X9)
+ .addReg(AArch64::X9)
+ .addGlobalAddress(cookie, 0, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::SUBSXrr), REG)
+ .addReg(REG)
+ .addReg(AArch64::X9);
+ BuildMI(MBB, MI, MBBDL, TII->get(AArch64::RETGUARD_JMP_TRAP)).addReg(REG);
+}
+
+bool AArch64ReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
+ switch (opcode) {
+ case AArch64::RET:
+ case AArch64::RET_ReallyLR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void AArch64ReturnProtectorLowering::fillTempRegisters(
+ MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
+
+ TempRegs.push_back(AArch64::X15);
+ TempRegs.push_back(AArch64::X14);
+ TempRegs.push_back(AArch64::X13);
+ TempRegs.push_back(AArch64::X12);
+ TempRegs.push_back(AArch64::X11);
+ TempRegs.push_back(AArch64::X10);
+}
+
+void AArch64ReturnProtectorLowering::saveReturnProtectorRegister(
+ MachineFunction &MF, std::vector<CalleeSavedInfo> &CSI) const {
+
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ if (!MFI.getReturnProtectorNeeded())
+ return;
+
+ if (!MFI.hasReturnProtectorRegister())
+ llvm_unreachable("Saving unset return protector register");
+
+ unsigned Reg = MFI.getReturnProtectorRegister();
+ if (!MFI.getReturnProtectorNeedsStore()) {
+ for (auto &MBB : MF) {
+ if (!MBB.isLiveIn(Reg))
+ MBB.addLiveIn(Reg);
+ }
+ return;
+ }
+
+ // CSI Reg order is important for pairing registers later.
+ // The expected order of the CSI is given by getCalleeSavedRegs(),
+ // which for us returns a list of GPRs and FPRs in ascending
+ // order. Since our temp regs are all before the usual callee
+ // saved regs, we can just insert our reg first.
+ CSI.insert(CSI.begin(), CalleeSavedInfo(MFI.getReturnProtectorRegister()));
+}

View file

@ -0,0 +1,61 @@
- Add retguard for arm64.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: lib/Target/AArch64/AArch64ReturnProtectorLowering.h
--- lib/Target/AArch64/AArch64ReturnProtectorLowering.h.orig
+++ lib/Target/AArch64/AArch64ReturnProtectorLowering.h
@@ -0,0 +1,52 @@
+//===-- AArch64ReturnProtectorLowering.h - --------------------- -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the AArch64 implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64RETURNPROTECTORLOWERING_H
+#define LLVM_LIB_TARGET_AARCH64_AARCH64RETURNPROTECTORLOWERING_H
+
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
+
+namespace llvm {
+
+class AArch64ReturnProtectorLowering : public ReturnProtectorLowering {
+public:
+ /// insertReturnProtectorPrologue/Epilogue - insert return protector
+ /// instrumentation in prologue or epilogue.
+ virtual void
+ insertReturnProtectorPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
+ GlobalVariable *cookie) const override;
+ virtual void
+ insertReturnProtectorEpilogue(MachineFunction &MF, MachineInstr &MI,
+ GlobalVariable *cookie) const override;
+
+ /// opcodeIsReturn - Reuturn true is the given opcode is a return
+ /// instruction needing return protection, false otherwise.
+ virtual bool opcodeIsReturn(unsigned opcode) const override;
+
+ /// fillTempRegisters - Fill the list of available temp registers we can
+ /// use as a return protector register.
+ virtual void
+ fillTempRegisters(MachineFunction &MF,
+ std::vector<unsigned> &TempRegs) const override;
+
+ /// saveReturnProtectorRegister - Allows the target to save the
+ /// CalculationRegister in the CalleeSavedInfo vector if needed.
+ virtual void
+ saveReturnProtectorRegister(MachineFunction &MF,
+ std::vector<CalleeSavedInfo> &CSI) const override;
+};
+
+} // namespace llvm
+
+#endif

View file

@ -0,0 +1,15 @@
Disable the Load Stack Guard for OpenBSD on AArch64. We don't use it
on any other platform and it causes a segfault in combination with our
IR Stack Guard.
Index: lib/Target/AArch64/AArch64Subtarget.h
--- lib/Target/AArch64/AArch64Subtarget.h.orig
+++ lib/Target/AArch64/AArch64Subtarget.h
@@ -500,6 +500,7 @@ class AArch64Subtarget final : public AArch64GenSubtar
bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); }
bool isTargetIOS() const { return TargetTriple.isiOS(); }
bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
+ bool isTargetOpenBSD() const { return TargetTriple.isOSOpenBSD(); }
bool isTargetWindows() const { return TargetTriple.isOSWindows(); }
bool isTargetAndroid() const { return TargetTriple.isAndroid(); }
bool isTargetFuchsia() const { return TargetTriple.isOSFuchsia(); }

View file

@ -0,0 +1,15 @@
Always disable GlobalISel on aarch64, fixes a crash when building on
aarch64 without retguard, with a stack protector and without
optimizations.
Index: lib/Target/AArch64/AArch64TargetMachine.cpp
--- lib/Target/AArch64/AArch64TargetMachine.cpp.orig
+++ lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -332,6 +332,7 @@ AArch64TargetMachine::AArch64TargetMachine(const Targe
// Enable GlobalISel at or below EnableGlobalISelAt0, unless this is
// MachO/CodeModel::Large, which GlobalISel does not support.
if (getOptLevel() <= EnableGlobalISelAtO &&
+ !getTargetTriple().isOSOpenBSD() &&
TT.getArch() != Triple::aarch64_32 &&
TT.getEnvironment() != Triple::GNUILP32 &&
!(getCodeModel() == CodeModel::Large && TT.isOSBinFormatMachO())) {

View file

@ -0,0 +1,13 @@
Add retguard for arm64.
Index: lib/Target/AArch64/CMakeLists.txt
--- lib/Target/AArch64/CMakeLists.txt.orig
+++ lib/Target/AArch64/CMakeLists.txt
@@ -70,6 +70,7 @@ add_llvm_target(AArch64CodeGen
AArch64PromoteConstant.cpp
AArch64PBQPRegAlloc.cpp
AArch64RegisterInfo.cpp
+ AArch64ReturnProtectorLowering.cpp
AArch64SLSHardening.cpp
AArch64SelectionDAGInfo.cpp
AArch64SpeculationHardening.cpp

View file

@ -0,0 +1,83 @@
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp
--- lib/Target/Mips/AsmParser/MipsAsmParser.cpp.orig
+++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -68,6 +68,7 @@ class MCInstrInfo;
} // end namespace llvm
extern cl::opt<bool> EmitJalrReloc;
+extern cl::opt<bool> FixLoongson2FBTB;
namespace {
@@ -236,6 +237,9 @@ class MipsAsmParser : public MCTargetAsmParser {
bool emitPartialAddress(MipsTargetStreamer &TOut, SMLoc IDLoc, MCSymbol *Sym);
+ bool emitLoongson2FBTBFlush(MCInst &Inst, MipsTargetStreamer &TOut,
+ SMLoc IDLoc, const MCSubtargetInfo *STI);
+
bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc,
MCStreamer &Out, const MCSubtargetInfo *STI);
@@ -2104,6 +2108,19 @@ bool MipsAsmParser::processInstruction(MCInst &Inst, S
Inst = BInst;
}
+ if (FixLoongson2FBTB) {
+ switch (Inst.getOpcode()) {
+ case Mips::JALR:
+ case Mips::JR:
+ case Mips::JalOneReg:
+ case Mips::JalTwoReg:
+ if (emitLoongson2FBTBFlush(Inst, TOut, IDLoc, STI))
+ return true;
+ default:
+ break;
+ }
+ }
+
// This expansion is not in a function called by tryExpandInstruction()
// because the pseudo-instruction doesn't have a distinct opcode.
if ((Opcode == Mips::JAL || Opcode == Mips::JAL_MM) && inPicMode()) {
@@ -3334,6 +3351,39 @@ bool MipsAsmParser::emitPartialAddress(MipsTargetStrea
TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI);
}
}
+ return false;
+}
+
+bool MipsAsmParser::emitLoongson2FBTBFlush(MCInst &Inst,
+ MipsTargetStreamer &TOut,
+ SMLoc IDLoc,
+ const MCSubtargetInfo *STI) {
+ unsigned SReg = Inst.getOperand(0).getReg();
+ if (SReg == Mips::ZERO || SReg == Mips::ZERO_64 ||
+ SReg == Mips::K0 || SReg == Mips::K0_64 ||
+ SReg == Mips::K1 || SReg == Mips::K1_64)
+ return false;
+
+ unsigned ATReg = getATReg(IDLoc);
+ if (ATReg == 0)
+ return true;
+
+ // Direct comparison of SReg and ATReg is not reliable because
+ // the register classes may differ.
+ unsigned ATRegIndex = AssemblerOptions.back()->getATRegIndex();
+ if (ATRegIndex == 0)
+ return true;
+ if (SReg == getReg(Mips::GPR32RegClassID, ATRegIndex) ||
+ SReg == getReg(Mips::GPR64RegClassID, ATRegIndex))
+ return false;
+
+ warnIfNoMacro(IDLoc);
+
+ // li $at, COP_0_BTB_CLEAR | COP_0_RAS_DISABLE
+ TOut.emitRRI(Mips::ORi, ATReg, Mips::ZERO, 3, IDLoc, STI);
+ // dmtc0 $at, COP_0_DIAG
+ TOut.emitRRI(Mips::DMTC0, Mips::COP022, ATReg, 0, IDLoc, STI);
+
return false;
}

View file

@ -0,0 +1,22 @@
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
- Add retguard for octeon/mips64.
Index: lib/Target/Mips/CMakeLists.txt
--- lib/Target/Mips/CMakeLists.txt.orig
+++ lib/Target/Mips/CMakeLists.txt
@@ -41,6 +41,7 @@ add_llvm_target(MipsCodeGen
MipsISelLowering.cpp
MipsFrameLowering.cpp
MipsLegalizerInfo.cpp
+ MipsLoongson2FBTBFix.cpp
MipsBranchExpansion.cpp
MipsMCInstLower.cpp
MipsMachineFunction.cpp
@@ -50,6 +51,7 @@ add_llvm_target(MipsCodeGen
MipsPreLegalizerCombiner.cpp
MipsRegisterBankInfo.cpp
MipsRegisterInfo.cpp
+ MipsReturnProtectorLowering.cpp
MipsSEFrameLowering.cpp
MipsSEInstrInfo.cpp
MipsSEISelDAGToDAG.cpp

View file

@ -0,0 +1,17 @@
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
Index: lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
--- lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp.orig
+++ lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -21,6 +21,11 @@ EmitJalrReloc("mips-jalr-reloc", cl::Hidden,
cl::desc("MIPS: Emit R_{MICRO}MIPS_JALR relocation with jalr"),
cl::init(true));
+cl::opt<bool>
+FixLoongson2FBTB("fix-loongson2f-btb", cl::Hidden,
+ cl::desc("MIPS: Enable Loongson 2F BTB workaround"),
+ cl::init(false));
+
namespace {
static const MCPhysReg O32IntRegs[4] = {Mips::A0, Mips::A1, Mips::A2, Mips::A3};

View file

@ -0,0 +1,89 @@
- Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsAsmPrinter.cpp
--- lib/Target/Mips/MipsAsmPrinter.cpp.orig
+++ lib/Target/Mips/MipsAsmPrinter.cpp
@@ -242,6 +242,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 &&

View file

@ -0,0 +1,33 @@
Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsFrameLowering.cpp
--- lib/Target/Mips/MipsFrameLowering.cpp.orig
+++ lib/Target/Mips/MipsFrameLowering.cpp
@@ -14,6 +14,7 @@
#include "MCTargetDesc/MipsBaseInfo.h"
#include "MipsInstrInfo.h"
#include "MipsMachineFunction.h"
+#include "MipsReturnProtectorLowering.h"
#include "MipsTargetMachine.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -122,6 +123,10 @@ uint64_t MipsFrameLowering::estimateStackSize(const Ma
if (MFI.getObjectOffset(I) > 0)
Size += MFI.getObjectSize(I);
+ // Account for saving return protector register
+ if (MFI.getReturnProtectorNeeded())
+ Size += TRI.getSpillSize(*TRI.getMinimalPhysRegClass(Mips::T9_64));
+
// Conservatively assume all callee-saved registers will be saved.
for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) {
unsigned RegSize = TRI.getSpillSize(*TRI.getMinimalPhysRegClass(*R));
@@ -148,4 +153,8 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, Mac
}
return MBB.erase(I);
+}
+
+const ReturnProtectorLowering *MipsFrameLowering::getReturnProtector() const {
+ return &RPL;
}

View file

@ -0,0 +1,35 @@
Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsFrameLowering.h
--- lib/Target/Mips/MipsFrameLowering.h.orig
+++ lib/Target/Mips/MipsFrameLowering.h
@@ -14,6 +14,7 @@
#define LLVM_LIB_TARGET_MIPS_MIPSFRAMELOWERING_H
#include "Mips.h"
+#include "MipsReturnProtectorLowering.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
namespace llvm {
@@ -24,8 +25,11 @@ class MipsFrameLowering : public TargetFrameLowering {
const MipsSubtarget &STI;
public:
+
+ const MipsReturnProtectorLowering RPL;
+
explicit MipsFrameLowering(const MipsSubtarget &sti, Align Alignment)
- : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {
+ : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti), RPL() {
}
static const MipsFrameLowering *create(const MipsSubtarget &ST);
@@ -39,6 +43,8 @@ class MipsFrameLowering : public TargetFrameLowering {
bool enableShrinkWrapping(const MachineFunction &MF) const override {
return true;
}
+
+ const ReturnProtectorLowering *getReturnProtector() const override;
MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction &MF,

View file

@ -0,0 +1,48 @@
- Implement the 'h' register constraint on mips64. This lets clang build
pieces of software that use the constraint if the compiler claims
to be compatible with GCC 4.2.1.
Note that the constraint was removed in GCC 4.4. The reason was that
'h' could generate code whose result is unpredictable. The underlying
reason is that the HI and LO registers are special, and the optimizer
has to be careful when choosing the order of HI/LO accesses. It looks
that LLVM has the needed logic.
Index: lib/Target/Mips/MipsISelLowering.cpp
--- lib/Target/Mips/MipsISelLowering.cpp.orig
+++ lib/Target/Mips/MipsISelLowering.cpp
@@ -3925,6 +3925,7 @@ MipsTargetLowering::getConstraintType(StringRef Constr
// backwards compatibility.
// 'c' : A register suitable for use in an indirect
// jump. This will always be $25 for -mabicalls.
+ // 'h' : The hi register. 1 word storage.
// 'l' : The lo register. 1 word storage.
// 'x' : The hilo register pair. Double word storage.
if (Constraint.size() == 1) {
@@ -3934,6 +3935,7 @@ MipsTargetLowering::getConstraintType(StringRef Constr
case 'y':
case 'f':
case 'c':
+ case 'h':
case 'l':
case 'x':
return C_RegisterClass;
@@ -3979,6 +3981,7 @@ MipsTargetLowering::getSingleConstraintMatchWeight(
weight = CW_Register;
break;
case 'c': // $25 for indirect jumps
+ case 'h': // hi register
case 'l': // lo register
case 'x': // hilo register pair
if (type->isIntegerTy())
@@ -4153,6 +4156,11 @@ MipsTargetLowering::getRegForInlineAsmConstraint(const
return std::make_pair((unsigned)Mips::T9_64, &Mips::GPR64RegClass);
// This will generate an error message
return std::make_pair(0U, nullptr);
+ case 'h': // use the `hi` register to store values
+ // that are no bigger than a word
+ if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8)
+ return std::make_pair((unsigned)Mips::HI0, &Mips::HI32RegClass);
+ return std::make_pair((unsigned)Mips::HI0_64, &Mips::HI64RegClass);
case 'l': // use the `lo` register to store values
// that are no bigger than a word
if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8)

View file

@ -0,0 +1,37 @@
- Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsInstrInfo.td
--- lib/Target/Mips/MipsInstrInfo.td.orig
+++ lib/Target/Mips/MipsInstrInfo.td
@@ -2012,6 +2012,31 @@ def LONG_BRANCH_ADDiu2Op : PseudoSE<(outs GPR32Opnd:$d
bit hasNoSchedulingInfo = 1;
}
+// Pseudo instructions used by retguard. In order to calculste the PC
+// for PIC code, we use a pair of pseudos to get the function address
+// into T9, which is normally used to hold this value but is trashed
+// by function epilogue.
+let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
+
+ // Use BAL to get the PC into RA, then calculate the address of the
+ // current function and save this value in $rd. $rs and $rt are used
+ // as scratch registers and are trashed by this pseudo. $tgt is the
+ // symbol to branch to when calling BAL.
+ let Size = 32 in {
+ def RETGUARD_GET_FUNCTION_ADDR: PseudoSE<(outs GPR64:$rd),
+ (ins GPR64:$rs, GPR64:$rt, brtarget:$tgt), []>;
+ }
+
+ // Emit the symbol used for $tgt in RETGUARD_GET_FUNCTION_ADDR. We
+ // emit this symbol immediately before the usual function return, with
+ // the effect that the BAL branches to an immediate return and resumes
+ // execution through the rest of the RETGUARD epilogue. We pair BAL
+ // with RET to satisfy return branch predictors.
+ let Size = 0 in {
+ def RETGUARD_EMIT_SYMBOL: PseudoSE<(outs), (ins brtarget:$tgt), []>;
+ }
+}
+
//===----------------------------------------------------------------------===//
// Instruction definition
//===----------------------------------------------------------------------===//

View file

@ -0,0 +1,97 @@
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
Index: lib/Target/Mips/MipsLoongson2FBTBFix.cpp
--- lib/Target/Mips/MipsLoongson2FBTBFix.cpp.orig
+++ lib/Target/Mips/MipsLoongson2FBTBFix.cpp
@@ -0,0 +1,91 @@
+//===- MipsLoongson2FBTBFix.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mips.h"
+#include "MipsTargetMachine.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/Passes.h"
+
+using namespace llvm;
+
+namespace {
+
+class MipsLoongson2FBTBFix : public MachineFunctionPass {
+public:
+ static char ID;
+
+ MipsLoongson2FBTBFix() : MachineFunctionPass(ID) {
+ initializeMipsLoongson2FBTBFixPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ StringRef getPassName() const override {
+ return "Loongson 2F BTB erratum workaround pass";
+ }
+
+private:
+ bool runOnBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB);
+};
+
+} // end of anonymous namespace
+
+char MipsLoongson2FBTBFix::ID = 0;
+
+INITIALIZE_PASS(MipsLoongson2FBTBFix, "loongson2f-btb-fix-pass",
+ "Mips Loongson 2F BTB erratum workaround", false, false)
+
+FunctionPass *llvm::createMipsLoongson2FBTBFix() {
+ return new MipsLoongson2FBTBFix();
+}
+
+bool MipsLoongson2FBTBFix::runOnMachineFunction(MachineFunction &MF) {
+ bool Changed = false;
+
+ for (auto &MBB : MF) {
+ Changed |= runOnBasicBlock(MF, MBB);
+ }
+ return Changed;
+}
+
+bool MipsLoongson2FBTBFix::runOnBasicBlock(
+ MachineFunction &MF, MachineBasicBlock &MBB) {
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ bool Changed = false;
+
+ for (auto &MI : MBB) {
+ if (!MI.isCall() && !MI.isIndirectBranch() && !MI.isReturn())
+ continue;
+
+ // Skip calls that are not through a register.
+ if (MI.isCall()) {
+ if (MI.getNumOperands() == 0)
+ continue;
+ const MachineOperand &MO = MI.getOperand(0);
+ if (!MO.isReg())
+ continue;
+ }
+
+ Changed = true;
+
+ DebugLoc MBBDL = MI.getDebugLoc();
+ Register TempReg = MRI.createVirtualRegister(&Mips::GPR64RegClass);
+
+ // li $TempReg, COP_0_BTB_CLEAR | COP_0_RAS_DISABLE
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::ORi), TempReg)
+ .addReg(Mips::ZERO)
+ .addImm(3);
+ // dmtc0 $TempReg, COP_0_DIAG
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DMTC0))
+ .addReg(Mips::COP022)
+ .addReg(TempReg)
+ .addImm(0);
+ }
+ return Changed;
+}

View file

@ -0,0 +1,279 @@
Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsReturnProtectorLowering.cpp
--- lib/Target/Mips/MipsReturnProtectorLowering.cpp.orig
+++ lib/Target/Mips/MipsReturnProtectorLowering.cpp
@@ -0,0 +1,273 @@
+//===-- MipsReturnProtectorLowering.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Mips implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/MipsBaseInfo.h"
+#include "MipsInstrInfo.h"
+#include "MipsMachineFunction.h"
+#include "MipsReturnProtectorLowering.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+void MipsReturnProtectorLowering::insertReturnProtectorPrologue(
+ MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
+
+ MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
+ DebugLoc MBBDL = MBB.findDebugLoc(MI);
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ const TargetMachine &TM = MF.getTarget();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ const GlobalValue *FName = &MF.getFunction();
+
+ // Select some scratch registers
+ unsigned TempReg1 = Mips::AT_64;
+ unsigned TempReg2 = Mips::V0_64;
+ if (!MBB.isLiveIn(TempReg1))
+ MBB.addLiveIn(TempReg1);
+ if (!MBB.isLiveIn(TempReg2))
+ MBB.addLiveIn(TempReg2);
+
+ if (TM.isPositionIndependent()) {
+
+ if (!MBB.isLiveIn(Mips::T9_64))
+ MBB.addLiveIn(Mips::T9_64);
+
+ // TempReg1 loads the GOT pointer
+ // TempReg2 load the offset from GOT to random cookie pointer
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
+ .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(Mips::T9_64);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2)
+ .addReg(TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(TempReg2);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
+ .addReg(TempReg1)
+ .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
+ .addReg(REG)
+ .addImm(0);
+ } else {
+ // TempReg1 loads the high 32 bits
+ // TempReg2 loads the low 32 bits
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1)
+ .addReg(TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1)
+ .addReg(TempReg1)
+ .addImm(32);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(TempReg2);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), REG)
+ .addReg(TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO);
+ }
+
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG)
+ .addReg(REG)
+ .addReg(Mips::RA_64);
+}
+
+void MipsReturnProtectorLowering::insertReturnProtectorEpilogue(
+ MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
+
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc MBBDL = MI.getDebugLoc();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ const TargetMachine &TM = MF.getTarget();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ const GlobalValue *FName = &MF.getFunction();
+ const unsigned TRAPCODE = 0x52;
+
+ // Select some scratch registers
+ unsigned TempReg1 = Mips::T7_64;
+ unsigned TempReg2 = Mips::T8_64;
+ if (REG == Mips::T7_64 || REG == Mips::T8_64) {
+ TempReg1 = Mips::T5_64;
+ TempReg2 = Mips::T6_64;
+ }
+ if (!MBB.isLiveIn(TempReg1))
+ MBB.addLiveIn(TempReg1);
+ if (!MBB.isLiveIn(TempReg2))
+ MBB.addLiveIn(TempReg2);
+
+ // Undo the XOR to retrieve the random cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::XOR64), REG)
+ .addReg(REG)
+ .addReg(Mips::RA_64);
+
+ // Load the random cookie
+ if (TM.isPositionIndependent()) {
+
+ if (!MBB.isLiveIn(Mips::T9_64))
+ MBB.addLiveIn(Mips::T9_64);
+
+ // T9 is trashed by this point, and we cannot trust saving
+ // the value from function entry on the stack, so calculate
+ // the address of the function entry using a pseudo
+ MCSymbol *BALTarget = MF.getContext().createTempSymbol();
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_GET_FUNCTION_ADDR), Mips::T9_64)
+ .addReg(TempReg1)
+ .addReg(TempReg2)
+ .addSym(BALTarget);
+
+ // TempReg1 loads the GOT pointer
+ // TempReg2 load the offset from GOT to random cookie pointer
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
+ .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_GOT_HI16);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(Mips::T9_64);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg2)
+ .addReg(TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_GOT_LO16);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(TempReg2);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
+ .addReg(TempReg1)
+ .addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
+ .addReg(TempReg1)
+ .addImm(0);
+ // Verify the random cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE))
+ .addReg(TempReg1)
+ .addReg(REG)
+ .addImm(TRAPCODE);
+ // Emit the BAL target symbol from above
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::RETGUARD_EMIT_SYMBOL))
+ .addSym(BALTarget);
+ } else {
+ // TempReg1 loads the high 32 bits
+ // TempReg2 loads the low 32 bits
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_HIGHEST);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LUi64), TempReg2)
+ .addGlobalAddress(cookie, 0, MipsII::MO_ABS_HI);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDiu), TempReg1)
+ .addReg(TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_HIGHER);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DSLL), TempReg1)
+ .addReg(TempReg1)
+ .addImm(32);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::DADDu), TempReg1)
+ .addReg(TempReg1)
+ .addReg(TempReg2);
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::LD), TempReg1)
+ .addReg(TempReg1)
+ .addGlobalAddress(cookie, 0, MipsII::MO_ABS_LO);
+ // Verify the random cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(Mips::TNE))
+ .addReg(TempReg1)
+ .addReg(REG)
+ .addImm(TRAPCODE);
+ }
+}
+
+bool MipsReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
+ switch (opcode) {
+ case Mips::RetRA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void MipsReturnProtectorLowering::fillTempRegisters(
+ MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
+
+ const Function &F = MF.getFunction();
+
+ // long double arguments (f128) occupy two arg registers, so shift
+ // subsequent arguments down by one register
+ size_t shift_reg = 0;
+ for (const auto &arg : F.args()) {
+ if (arg.getType()->isFP128Ty())
+ shift_reg += 1;
+ }
+
+ if (!F.isVarArg()) {
+ // We can use any of the caller saved unused arg registers
+ switch (F.arg_size() + shift_reg) {
+ case 0:
+ // A0 is used to return f128 values in soft float
+ case 1:
+ TempRegs.push_back(Mips::A1_64);
+ LLVM_FALLTHROUGH;
+ case 2:
+ TempRegs.push_back(Mips::A2_64);
+ LLVM_FALLTHROUGH;
+ case 3:
+ TempRegs.push_back(Mips::A3_64);
+ LLVM_FALLTHROUGH;
+ case 4:
+ TempRegs.push_back(Mips::T0_64);
+ LLVM_FALLTHROUGH;
+ case 5:
+ TempRegs.push_back(Mips::T1_64);
+ LLVM_FALLTHROUGH;
+ case 6:
+ TempRegs.push_back(Mips::T2_64);
+ LLVM_FALLTHROUGH;
+ case 7:
+ TempRegs.push_back(Mips::T3_64);
+ LLVM_FALLTHROUGH;
+ case 8:
+ TempRegs.push_back(Mips::T4_64);
+ LLVM_FALLTHROUGH;
+ case 9:
+ TempRegs.push_back(Mips::T5_64);
+ LLVM_FALLTHROUGH;
+ case 10:
+ TempRegs.push_back(Mips::T6_64);
+ LLVM_FALLTHROUGH;
+ case 11:
+ TempRegs.push_back(Mips::T7_64);
+ LLVM_FALLTHROUGH;
+ case 12:
+ TempRegs.push_back(Mips::T8_64);
+ LLVM_FALLTHROUGH;
+ default:
+ break;
+ }
+ }
+ // For FastCC this is the only scratch reg that isn't V0 or T9
+ TempRegs.push_back(Mips::AT_64);
+}

View file

@ -0,0 +1,52 @@
Add retguard for octeon/mips64.
Index: lib/Target/Mips/MipsReturnProtectorLowering.h
--- lib/Target/Mips/MipsReturnProtectorLowering.h.orig
+++ lib/Target/Mips/MipsReturnProtectorLowering.h
@@ -0,0 +1,46 @@
+//===-- MipsReturnProtectorLowering.h - --------------------- -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Mips implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_MIPS_MIPSRETURNPROTECTORLOWERING_H
+#define LLVM_LIB_TARGET_MIPS_MIPSRETURNPROTECTORLOWERING_H
+
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
+
+namespace llvm {
+
+class MipsReturnProtectorLowering : public ReturnProtectorLowering {
+public:
+ /// insertReturnProtectorPrologue/Epilogue - insert return protector
+ /// instrumentation in prologue or epilogue.
+ virtual void
+ insertReturnProtectorPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
+ GlobalVariable *cookie) const override;
+ virtual void
+ insertReturnProtectorEpilogue(MachineFunction &MF, MachineInstr &MI,
+ GlobalVariable *cookie) const override;
+
+ /// opcodeIsReturn - Reuturn true is the given opcode is a return
+ /// instruction needing return protection, false otherwise.
+ virtual bool opcodeIsReturn(unsigned opcode) const override;
+
+ /// fillTempRegisters - Fill the list of available temp registers we can
+ /// use as a return protector register.
+ virtual void
+ fillTempRegisters(MachineFunction &MF,
+ std::vector<unsigned> &TempRegs) const override;
+};
+
+} // namespace llvm
+
+#endif

View file

@ -0,0 +1,24 @@
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
Index: lib/Target/Mips/MipsTargetMachine.cpp
--- lib/Target/Mips/MipsTargetMachine.cpp.orig
+++ lib/Target/Mips/MipsTargetMachine.cpp
@@ -45,6 +45,8 @@ using namespace llvm;
#define DEBUG_TYPE "mips"
+extern cl::opt<bool> FixLoongson2FBTB;
+
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTarget() {
// Register the target.
RegisterTargetMachine<MipsebTargetMachine> X(getTheMipsTarget());
@@ -268,6 +270,9 @@ bool MipsPassConfig::addInstSelector() {
void MipsPassConfig::addPreRegAlloc() {
addPass(createMipsOptimizePICCallPass());
+
+ if (FixLoongson2FBTB)
+ addPass(createMipsLoongson2FBTBFix());
}
TargetTransformInfo

View file

@ -0,0 +1,21 @@
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
Index: lib/Target/Mips/Mips.h
--- lib/Target/Mips/Mips.h.orig
+++ lib/Target/Mips/Mips.h
@@ -38,6 +38,7 @@ namespace llvm {
FunctionPass *createMicroMipsSizeReducePass();
FunctionPass *createMipsExpandPseudoPass();
FunctionPass *createMipsPreLegalizeCombiner();
+ FunctionPass *createMipsLoongson2FBTBFix();
InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &,
MipsSubtarget &,
@@ -47,6 +48,7 @@ namespace llvm {
void initializeMipsBranchExpansionPass(PassRegistry &);
void initializeMicroMipsSizeReducePass(PassRegistry &);
void initializeMipsPreLegalizerCombinerPass(PassRegistry&);
+ void initializeMipsLoongson2FBTBFixPass(PassRegistry &);
} // end namespace llvm;
#endif

View file

@ -0,0 +1,11 @@
Index: lib/Target/PowerPC/CMakeLists.txt
--- lib/Target/PowerPC/CMakeLists.txt.orig
+++ lib/Target/PowerPC/CMakeLists.txt
@@ -42,6 +42,7 @@ add_llvm_target(PowerPCCodeGen
PPCMacroFusion.cpp
PPCMIPeephole.cpp
PPCRegisterInfo.cpp
+ PPCReturnProtectorLowering.cpp
PPCSubtarget.cpp
PPCTargetMachine.cpp
PPCTargetObjectFile.cpp

View file

@ -0,0 +1,91 @@
Add RETGUARD implementation for powerpc and powerpc64.
Index: lib/Target/PowerPC/PPCAsmPrinter.cpp
--- lib/Target/PowerPC/PPCAsmPrinter.cpp.orig
+++ lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -815,6 +815,85 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr
return;
}
}
+ case PPC::RETGUARD_LOAD_PC: {
+ unsigned DEST = MI->getOperand(0).getReg();
+ unsigned LR = MI->getOperand(1).getReg();
+ MCSymbol *HereSym = MI->getOperand(2).getMCSymbol();
+
+ unsigned MTLR = PPC::MTLR;
+ unsigned MFLR = PPC::MFLR;
+ unsigned BL = PPC::BL;
+ if (Subtarget->isPPC64()) {
+ MTLR = PPC::MTLR8;
+ MFLR = PPC::MFLR8;
+ BL = PPC::BL8;
+ }
+
+ // Cache the current LR
+ EmitToStreamer(*OutStreamer, MCInstBuilder(MFLR)
+ .addReg(LR));
+
+ // Create the BL forward
+ const MCExpr *HereExpr = MCSymbolRefExpr::create(HereSym, OutContext);
+ EmitToStreamer(*OutStreamer, MCInstBuilder(BL)
+ .addExpr(HereExpr));
+ OutStreamer->emitLabel(HereSym);
+
+ // Grab the result
+ EmitToStreamer(*OutStreamer, MCInstBuilder(MFLR)
+ .addReg(DEST));
+ // Restore LR
+ EmitToStreamer(*OutStreamer, MCInstBuilder(MTLR)
+ .addReg(LR));
+ return;
+ }
+ case PPC::RETGUARD_LOAD_GOT: {
+ if (Subtarget->isSecurePlt() && isPositionIndependent() ) {
+ StringRef GOTName = (PL == PICLevel::SmallPIC ?
+ "_GLOBAL_OFFSET_TABLE_" : ".LTOC");
+ unsigned DEST = MI->getOperand(0).getReg();
+ unsigned HERE = MI->getOperand(1).getReg();
+ MCSymbol *HereSym = MI->getOperand(2).getMCSymbol();
+ MCSymbol *GOTSym = OutContext.getOrCreateSymbol(GOTName);
+ const MCExpr *HereExpr = MCSymbolRefExpr::create(HereSym, OutContext);
+ const MCExpr *GOTExpr = MCSymbolRefExpr::create(GOTSym, OutContext);
+
+ // Get offset from Here to GOT
+ const MCExpr *GOTDeltaExpr =
+ MCBinaryExpr::createSub(GOTExpr, HereExpr, OutContext);
+ const MCExpr *GOTDeltaHi =
+ PPCMCExpr::createHa(GOTDeltaExpr, OutContext);
+ const MCExpr *GOTDeltaLo =
+ PPCMCExpr::createLo(GOTDeltaExpr, OutContext);
+
+ EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS)
+ .addReg(DEST)
+ .addReg(HERE)
+ .addExpr(GOTDeltaHi));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI)
+ .addReg(DEST)
+ .addReg(DEST)
+ .addExpr(GOTDeltaLo));
+ }
+ return;
+ }
+ case PPC::RETGUARD_LOAD_COOKIE: {
+ unsigned DEST = MI->getOperand(0).getReg();
+ MCSymbol *CookieSym = getSymbol(MI->getOperand(1).getGlobal());
+ const MCExpr *CookieExprHa = MCSymbolRefExpr::create(
+ CookieSym, MCSymbolRefExpr::VK_PPC_HA, OutContext);
+ const MCExpr *CookieExprLo = MCSymbolRefExpr::create(
+ CookieSym, MCSymbolRefExpr::VK_PPC_LO, OutContext);
+
+ EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LIS)
+ .addReg(DEST)
+ .addExpr(CookieExprHa));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LWZ)
+ .addReg(DEST)
+ .addExpr(CookieExprLo)
+ .addReg(DEST));
+ return;
+ }
case PPC::LWZtoc: {
// Transform %rN = LWZtoc @op1, %r2
LowerPPCMachineInstrToMCInst(MI, TmpInst, *this);

View file

@ -0,0 +1,22 @@
Add RETGUARD implementation for powerpc and powerpc64.
Index: lib/Target/PowerPC/PPCFrameLowering.cpp
--- lib/Target/PowerPC/PPCFrameLowering.cpp.orig
+++ lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -15,6 +15,7 @@
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "PPCMachineFunctionInfo.h"
+#include "PPCReturnProtectorLowering.h"
#include "PPCSubtarget.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/Statistic.h"
@@ -2696,4 +2697,8 @@ bool PPCFrameLowering::enableShrinkWrapping(const Mach
if (MF.getInfo<PPCFunctionInfo>()->shrinkWrapDisabled())
return false;
return !MF.getSubtarget<PPCSubtarget>().is32BitELFABI();
+}
+
+const ReturnProtectorLowering *PPCFrameLowering::getReturnProtector() const {
+ return &RPL;
}

View file

@ -0,0 +1,23 @@
Add RETGUARD implementation for powerpc and powerpc64.
Index: lib/Target/PowerPC/PPCFrameLowering.h
--- lib/Target/PowerPC/PPCFrameLowering.h.orig
+++ lib/Target/PowerPC/PPCFrameLowering.h
@@ -12,6 +12,7 @@
#ifndef LLVM_LIB_TARGET_POWERPC_PPCFRAMELOWERING_H
#define LLVM_LIB_TARGET_POWERPC_PPCFRAMELOWERING_H
+#include "PPCReturnProtectorLowering.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/Target/TargetMachine.h"
@@ -173,6 +174,9 @@ class PPCFrameLowering: public TargetFrameLowering { (
/// function prologue/epilogue.
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
bool canUseAsEpilogue(const MachineBasicBlock &MBB) const override;
+
+ const PPCReturnProtectorLowering RPL;
+ const ReturnProtectorLowering *getReturnProtector() const override;
};
} // End llvm namespace

View file

@ -0,0 +1,37 @@
Add RETGUARD implementation for powerpc and powerpc64.
Index: lib/Target/PowerPC/PPCInstrInfo.td
--- lib/Target/PowerPC/PPCInstrInfo.td.orig
+++ lib/Target/PowerPC/PPCInstrInfo.td
@@ -1690,6 +1690,31 @@ let Defs = [LR] in
def MoveGOTtoLR : PPCEmitTimePseudo<(outs), (ins), "#MoveGOTtoLR", []>,
PPC970_Unit_BRU;
+// Pseudo instruction used by retguard.
+//
+// We need to get the PC into a register in order to calculate the address of
+// the retguard cookies. This pseudo will branch immediately forward to get PC
+// in LR, and then move LR into the destination register. The current value of
+// LR is saved and restored via the given temp register, which is trashed.
+let Size = 16 in {
+def RETGUARD_LOAD_PC : PPCEmitTimePseudo<(outs gprc:$dest), (ins gprc:$tmp),
+ "#RGLoadPC", []>;
+}
+
+// Once we have the PC in a register, we need to load the address of the GOT
+// into another register so we can then finally load the local offset of the
+// retguard symbol entry from the GOT and then the cookie value.
+let Size = 8 in {
+def RETGUARD_LOAD_GOT : PPCEmitTimePseudo<(outs gprc:$dest),
+ (ins gprc:$pc, calltarget:$sym), "RGLoadGOT", []>;
+}
+
+let Size = 8 in {
+// For static linkage, we can load the cookie directly
+def RETGUARD_LOAD_COOKIE : PPCEmitTimePseudo<(outs gprc:$dest),
+ (ins calltarget:$sym), "RGLoadCookie", []>;
+}
+
let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7 in {
let isBarrier = 1 in {
let isPredicable = 1 in

View file

@ -0,0 +1,285 @@
- Add RETGUARD implementation for powerpc and powerpc64.
- Use all 64 bits of the RETGUARD cookie on powerpc64.
Index: lib/Target/PowerPC/PPCReturnProtectorLowering.cpp
--- lib/Target/PowerPC/PPCReturnProtectorLowering.cpp.orig
+++ lib/Target/PowerPC/PPCReturnProtectorLowering.cpp
@@ -0,0 +1,278 @@
+//===-- PPCReturnProtectorLowering.cpp --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the PPC implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PPC.h"
+#include "PPCInstrInfo.h"
+#include "PPCMachineFunctionInfo.h"
+#include "PPCReturnProtectorLowering.h"
+#include "PPCTargetMachine.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+void PPCReturnProtectorLowering::insertReturnProtectorPrologue(
+ MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
+
+ MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
+ DebugLoc MBBDL = MBB.findDebugLoc(MI);
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ const TargetMachine &TM = MF.getTarget();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+ bool is64bit = MF.getSubtarget<PPCSubtarget>().isPPC64();
+ bool isELFv2 = MF.getSubtarget<PPCSubtarget>().isELFv2ABI();
+
+ unsigned LRReg = PPC::R0;
+ unsigned TOCReg = PPC::R2;
+ unsigned XOR = PPC::XOR;
+ unsigned LWZ = PPC::LWZ;
+ unsigned MFLR = PPC::MFLR;
+ if (is64bit) {
+ LRReg = PPC::X0;
+ TOCReg = PPC::X2;
+ XOR = PPC::XOR8;
+ LWZ = PPC::LWZ8;
+ MFLR = PPC::MFLR8;
+ }
+
+ if (!MBB.isLiveIn(LRReg))
+ MBB.addLiveIn(LRReg);
+
+ if (is64bit) {
+ // PIC and non-PIC is the same
+ if (!isELFv2)
+ llvm_unreachable("ppc64 retguard requires ELFv2");
+ // Get the return address into LRReg
+ BuildMI(MBB, MI, MBBDL, TII->get(MFLR), LRReg);
+ // Load the random cookie value into REG
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::ADDIStocHA8), REG)
+ .addReg(TOCReg)
+ .addGlobalAddress(cookie);
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LD), REG)
+ .addGlobalAddress(cookie, 0, PPCII::MO_TOC_LO)
+ .addReg(REG);
+ // XOR cookie ^ random = retguard cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ } else {
+ // 32 bit
+ if (TM.isPositionIndependent()) {
+ MCSymbol *HereSym = MF.getContext().createTempSymbol();
+ // Get LR into a register, and get PC into another register
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_PC), REG)
+ .addReg(LRReg, RegState::Define)
+ .addSym(HereSym);
+ // Get the random cookie address into REG
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_GOT), REG)
+ .addReg(REG)
+ .addSym(HereSym);
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LWZtoc), REG)
+ .addGlobalAddress(cookie, 0, 0)
+ .addReg(REG);
+ // Now load the random cookie value
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LWZ), REG)
+ .addImm(0)
+ .addReg(REG);
+ // XOR cookie ^ random = retguard cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ } else {
+ // Non-PIC prologue
+ // Load LR into a register
+ BuildMI(MBB, MI, MBBDL, TII->get(MFLR), LRReg);
+ // Load random cookie into another register
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_COOKIE), REG)
+ .addGlobalAddress(cookie);
+ // XOR cookie ^ random = retguard cookie
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ }
+ }
+}
+
+void PPCReturnProtectorLowering::insertReturnProtectorEpilogue(
+ MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc MBBDL = MI.getDebugLoc();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ const TargetMachine &TM = MF.getTarget();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+ bool is64bit = MF.getSubtarget<PPCSubtarget>().isPPC64();
+ bool isELFv2 = MF.getSubtarget<PPCSubtarget>().isELFv2ABI();
+
+ unsigned LRReg = PPC::R0;
+ unsigned TOCReg = PPC::R2;
+ unsigned RGReg = PPC::R12;
+ unsigned TRAP = PPC::TW;
+ unsigned XOR = PPC::XOR;
+ unsigned LWZ = PPC::LWZ;
+ unsigned MFLR = PPC::MFLR;
+ if (is64bit) {
+ LRReg = PPC::X0;
+ TOCReg = PPC::X2;
+ RGReg = PPC::X12;
+ TRAP = PPC::TD;
+ XOR = PPC::XOR8;
+ LWZ = PPC::LWZ8;
+ MFLR = PPC::MFLR8;
+ }
+
+ if (!MBB.isLiveIn(LRReg))
+ MBB.addLiveIn(LRReg);
+ if (!MBB.isLiveIn(RGReg))
+ MBB.addLiveIn(RGReg);
+
+ if (is64bit) {
+ // PIC and non-PIC is the same
+ if (!isELFv2)
+ llvm_unreachable("ppc64 retguard requires ELFv2");
+ // Get the return address into LRReg
+ BuildMI(MBB, MI, MBBDL, TII->get(MFLR), LRReg);
+ // XOR the LRReg with the retguard cookie value
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ // Load the random cookie value into RGReg
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::ADDIStocHA8), RGReg)
+ .addReg(TOCReg)
+ .addGlobalAddress(cookie);
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LD), RGReg)
+ .addGlobalAddress(cookie, 0, PPCII::MO_TOC_LO)
+ .addReg(RGReg);
+ // Trap if they don't compare
+ BuildMI(MBB, MI, MBBDL, TII->get(TRAP))
+ .addImm(24)
+ .addReg(REG)
+ .addReg(RGReg);
+ } else {
+ // 32 bit
+ if (TM.isPositionIndependent()) {
+ // Get the PC into RGReg and the LR value into LRReg
+ MCSymbol *HereSym = MF.getContext().createTempSymbol();
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_PC), RGReg)
+ .addReg(LRReg, RegState::Define)
+ .addSym(HereSym);
+ // XOR the LRReg with the retguard cookie value
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ // Get the random cookie address into RGReg
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_GOT), RGReg)
+ .addReg(RGReg)
+ .addSym(HereSym);
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LWZtoc), RGReg)
+ .addGlobalAddress(cookie, 0, 0)
+ .addReg(RGReg);
+ // Load the cookie random balue
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::LWZ), RGReg)
+ .addImm(0)
+ .addReg(RGReg);
+ // Trap if they don't compare
+ BuildMI(MBB, MI, MBBDL, TII->get(TRAP))
+ .addImm(24)
+ .addReg(REG)
+ .addReg(RGReg);
+ } else {
+ // Get LR into a register
+ BuildMI(MBB, MI, MBBDL, TII->get(MFLR), LRReg);
+ // XOR the LR Reg with the retguard cookie value
+ BuildMI(MBB, MI, MBBDL, TII->get(XOR), REG)
+ .addReg(REG)
+ .addReg(LRReg);
+ BuildMI(MBB, MI, MBBDL, TII->get(PPC::RETGUARD_LOAD_COOKIE), RGReg)
+ .addGlobalAddress(cookie);
+ // Trap if they don't compare
+ BuildMI(MBB, MI, MBBDL, TII->get(TRAP))
+ .addImm(24)
+ .addReg(REG)
+ .addReg(RGReg);
+ }
+ }
+}
+
+bool PPCReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
+ switch (opcode) {
+ case PPC::BLR:
+ case PPC::BCCLR:
+ case PPC::BCLR:
+ case PPC::BCLRn:
+ case PPC::BDZLR:
+ case PPC::BDNZLR:
+ case PPC::BDZLRp:
+ case PPC::BDNZLRp:
+ case PPC::BDZLRm:
+ case PPC::BDNZLRm:
+ case PPC::BLR8:
+ case PPC::BDZLR8:
+ case PPC::BDNZLR8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void PPCReturnProtectorLowering::fillTempRegisters(
+ MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
+
+ const Function &F = MF.getFunction();
+
+ bool is64bit = MF.getSubtarget<PPCSubtarget>().isPPC64();
+
+ // R0/R12 are also the hardcoded temp regs for the rest of
+ // frame lowering, so leave them alone.
+ //TempRegs.push_back(is64bit ? PPC::X0 : PPC::R0);
+ //TempRegs.push_back(is64bit ? PPC::X12 : PPC::R12);
+ // X11 is also the 'nest' param or environment pointer
+ TempRegs.push_back(is64bit ? PPC::X11 : PPC::R11);
+
+ if (!F.isVarArg()) {
+ // We can use any of the caller saved unused arg registers
+ switch (F.arg_size()) {
+ case 0: // X3/R3 are used to return
+ case 1: // X4/R4 are used to return
+ case 2:
+ TempRegs.push_back(is64bit ? PPC::X5 : PPC::R5);
+ LLVM_FALLTHROUGH;
+ case 3:
+ TempRegs.push_back(is64bit ? PPC::X6 : PPC::R6);
+ LLVM_FALLTHROUGH;
+ case 4:
+ TempRegs.push_back(is64bit ? PPC::X7 : PPC::R7);
+ LLVM_FALLTHROUGH;
+ case 5:
+ TempRegs.push_back(is64bit ? PPC::X8 : PPC::R8);
+ LLVM_FALLTHROUGH;
+ case 6:
+ TempRegs.push_back(is64bit ? PPC::X9 : PPC::R9);
+ LLVM_FALLTHROUGH;
+ case 7:
+ TempRegs.push_back(is64bit ? PPC::X10 : PPC::R10);
+ LLVM_FALLTHROUGH;
+ default:
+ break;
+ }
+ }
+}

View file

@ -0,0 +1,52 @@
Add RETGUARD implementation for powerpc and powerpc64.
Index: lib/Target/PowerPC/PPCReturnProtectorLowering.h
--- lib/Target/PowerPC/PPCReturnProtectorLowering.h.orig
+++ lib/Target/PowerPC/PPCReturnProtectorLowering.h
@@ -0,0 +1,46 @@
+//===-- PPCReturnProtectorLowering.h - --------------------- -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the PPC implementation of ReturnProtectorLowering
+// class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_PPC_MIPSRETURNPROTECTORLOWERING_H
+#define LLVM_LIB_TARGET_PPC_MIPSRETURNPROTECTORLOWERING_H
+
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
+
+namespace llvm {
+
+class PPCReturnProtectorLowering : public ReturnProtectorLowering {
+public:
+ /// insertReturnProtectorPrologue/Epilogue - insert return protector
+ /// instrumentation in prologue or epilogue.
+ virtual void
+ insertReturnProtectorPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
+ GlobalVariable *cookie) const override;
+ virtual void
+ insertReturnProtectorEpilogue(MachineFunction &MF, MachineInstr &MI,
+ GlobalVariable *cookie) const override;
+
+ /// opcodeIsReturn - Reuturn true is the given opcode is a return
+ /// instruction needing return protection, false otherwise.
+ virtual bool opcodeIsReturn(unsigned opcode) const override;
+
+ /// fillTempRegisters - Fill the list of available temp registers we can
+ /// use as a return protector register.
+ virtual void
+ fillTempRegisters(MachineFunction &MF,
+ std::vector<unsigned> &TempRegs) const override;
+};
+
+} // namespace llvm
+
+#endif

View file

@ -0,0 +1,14 @@
Switch Powerpc64 Big Endian to ELFv2 on OpenBSD.
Index: lib/Target/PowerPC/PPCTargetMachine.cpp
--- lib/Target/PowerPC/PPCTargetMachine.cpp.orig
+++ lib/Target/PowerPC/PPCTargetMachine.cpp
@@ -228,6 +228,8 @@ static PPCTargetMachine::PPCABI computeTargetABI(const
case Triple::ppc64le:
return PPCTargetMachine::PPC_ABI_ELFv2;
case Triple::ppc64:
+ if (TT.isOSOpenBSD())
+ return PPCTargetMachine::PPC_ABI_ELFv2;
return PPCTargetMachine::PPC_ABI_ELFv1;
default:
return PPCTargetMachine::PPC_ABI_UNKNOWN;

View file

@ -0,0 +1,16 @@
- enable EmuTLS on RiscV.
Index: lib/Target/RISCV/RISCVISelLowering.cpp
--- lib/Target/RISCV/RISCVISelLowering.cpp.orig
+++ lib/Target/RISCV/RISCVISelLowering.cpp
@@ -2847,6 +2847,10 @@ SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalA
SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {
+ const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
+ if (DAG.getTarget().useEmulatedTLS())
+ return LowerToTLSEmulatedModel(GA, DAG);
+
SDLoc DL(Op);
EVT Ty = Op.getValueType();
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);

View file

@ -0,0 +1,18 @@
- Make sure that we really don't emit quad-precision unless the
"hard-quad-float" feature is available
Index: lib/Target/Sparc/SparcISelLowering.cpp
--- lib/Target/Sparc/SparcISelLowering.cpp.orig
+++ lib/Target/Sparc/SparcISelLowering.cpp
@@ -3116,6 +3116,11 @@ SparcTargetLowering::EmitInstrWithCustomInserter(Machi
case SP::SELECT_CC_DFP_ICC:
case SP::SELECT_CC_QFP_ICC:
return expandSelectCC(MI, BB, SP::BCOND);
+ case SP::SELECT_CC_Int_XCC:
+ case SP::SELECT_CC_FP_XCC:
+ case SP::SELECT_CC_DFP_XCC:
+ case SP::SELECT_CC_QFP_XCC:
+ return expandSelectCC(MI, BB, SP::BPXCC);
case SP::SELECT_CC_Int_FCC:
case SP::SELECT_CC_FP_FCC:
case SP::SELECT_CC_DFP_FCC:

View file

@ -0,0 +1,42 @@
Make sure that we really don't emit quad-precision unless the
"hard-quad-float" feature is available.
Index: lib/Target/Sparc/SparcInstr64Bit.td
--- lib/Target/Sparc/SparcInstr64Bit.td.orig
+++ lib/Target/Sparc/SparcInstr64Bit.td
@@ -336,6 +336,7 @@ def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs
"fmovd$cond %xcc, $rs2, $rd",
[(set f64:$rd,
(SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>;
+let Predicates = [Is64Bit, HasHardQuad] in
def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
"fmovq$cond %xcc, $rs2, $rd",
@@ -436,11 +437,11 @@ def FXTOD : F3_3u<2, 0b110100, 0b010001000,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fxtod $rs2, $rd",
[(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
+let Predicates = [Is64Bit, HasHardQuad] in
def FXTOQ : F3_3u<2, 0b110100, 0b010001100,
(outs QFPRegs:$rd), (ins DFPRegs:$rs2),
"fxtoq $rs2, $rd",
- [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>,
- Requires<[HasHardQuad]>;
+ [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
def FSTOX : F3_3u<2, 0b110100, 0b010000001,
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
@@ -450,11 +451,11 @@ def FDTOX : F3_3u<2, 0b110100, 0b010000010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fdtox $rs2, $rd",
[(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>;
+let Predicates = [Is64Bit, HasHardQuad] in
def FQTOX : F3_3u<2, 0b110100, 0b010000011,
(outs DFPRegs:$rd), (ins QFPRegs:$rs2),
"fqtox $rs2, $rd",
- [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>,
- Requires<[HasHardQuad]>;
+ [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>;
} // Predicates = [Is64Bit]

View file

@ -0,0 +1,113 @@
Make sure that we really don't emit quad-precision unless the
"hard-quad-float" feature is available
Index: lib/Target/Sparc/SparcInstrInfo.td
--- lib/Target/Sparc/SparcInstrInfo.td.orig
+++ lib/Target/Sparc/SparcInstrInfo.td
@@ -487,6 +487,27 @@ let Uses = [ICC], usesCustomInserter = 1 in {
[(set f128:$dst, (SPselecticc f128:$T, f128:$F, imm:$Cond))]>;
}
+let Uses = [ICC], usesCustomInserter = 1 in {
+ def SELECT_CC_Int_XCC
+ : Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_Int_XCC PSEUDO!",
+ [(set i32:$dst, (SPselectxcc i32:$T, i32:$F, imm:$Cond))]>;
+ def SELECT_CC_FP_XCC
+ : Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_FP_XCC PSEUDO!",
+ [(set f32:$dst, (SPselectxcc f32:$T, f32:$F, imm:$Cond))]>;
+
+ def SELECT_CC_DFP_XCC
+ : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_DFP_XCC PSEUDO!",
+ [(set f64:$dst, (SPselectxcc f64:$T, f64:$F, imm:$Cond))]>;
+
+ def SELECT_CC_QFP_XCC
+ : Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_QFP_XCC PSEUDO!",
+ [(set f128:$dst, (SPselectxcc f128:$T, f128:$F, imm:$Cond))]>;
+}
+
let usesCustomInserter = 1, Uses = [FCC0] in {
def SELECT_CC_Int_FCC
@@ -1418,12 +1439,12 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in
(ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
"fmovd$cond %icc, $rs2, $rd",
[(set f64:$rd, (SPselecticc f64:$rs2, f64:$f, imm:$cond))]>;
+ let Predicates = [HasV9, HasHardQuad] in
def FMOVQ_ICC
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
"fmovq$cond %icc, $rs2, $rd",
- [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>,
- Requires<[HasHardQuad]>;
+ [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>;
}
let Uses = [FCC0], intcc = 0, opf_cc = 0b00 in {
@@ -1437,12 +1458,12 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in
(ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
"fmovd$cond %fcc0, $rs2, $rd",
[(set f64:$rd, (SPselectfcc f64:$rs2, f64:$f, imm:$cond))]>;
+ let Predicates = [HasV9, HasHardQuad] in
def FMOVQ_FCC
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
"fmovq$cond %fcc0, $rs2, $rd",
- [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>,
- Requires<[HasHardQuad]>;
+ [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>;
}
}
@@ -1452,28 +1473,28 @@ let Predicates = [HasV9] in {
def FMOVD : F3_3u<2, 0b110100, 0b000000010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fmovd $rs2, $rd", []>;
+ let Predicates = [HasV9, HasHardQuad] in
def FMOVQ : F3_3u<2, 0b110100, 0b000000011,
(outs QFPRegs:$rd), (ins QFPRegs:$rs2),
- "fmovq $rs2, $rd", []>,
- Requires<[HasHardQuad]>;
+ "fmovq $rs2, $rd", []>;
def FNEGD : F3_3u<2, 0b110100, 0b000000110,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fnegd $rs2, $rd",
[(set f64:$rd, (fneg f64:$rs2))]>;
+ let Predicates = [HasV9, HasHardQuad] in
def FNEGQ : F3_3u<2, 0b110100, 0b000000111,
(outs QFPRegs:$rd), (ins QFPRegs:$rs2),
"fnegq $rs2, $rd",
- [(set f128:$rd, (fneg f128:$rs2))]>,
- Requires<[HasHardQuad]>;
+ [(set f128:$rd, (fneg f128:$rs2))]>;
def FABSD : F3_3u<2, 0b110100, 0b000001010,
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
"fabsd $rs2, $rd",
[(set f64:$rd, (fabs f64:$rs2))]>;
+ let Predicates = [HasV9, HasHardQuad] in
def FABSQ : F3_3u<2, 0b110100, 0b000001011,
(outs QFPRegs:$rd), (ins QFPRegs:$rs2),
"fabsq $rs2, $rd",
- [(set f128:$rd, (fabs f128:$rs2))]>,
- Requires<[HasHardQuad]>;
+ [(set f128:$rd, (fabs f128:$rs2))]>;
}
// Floating-point compare instruction with %fcc0-%fcc3.
@@ -1520,11 +1541,11 @@ let Predicates = [HasV9] in {
: F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
(ins FCCRegs:$opf_cc, DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
"fmovd$cond $opf_cc, $rs2, $rd", []>;
+ let Predicates = [HasV9, HasHardQuad] in
def V9FMOVQ_FCC
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
(ins FCCRegs:$opf_cc, QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
- "fmovq$cond $opf_cc, $rs2, $rd", []>,
- Requires<[HasHardQuad]>;
+ "fmovq$cond $opf_cc, $rs2, $rd", []>;
} // Constraints = "$f = $rd", ...
} // let Predicates = [hasV9]

View file

@ -0,0 +1,26 @@
- Add a clang pass that identifies potential ROP gadgets and replaces ROP
friendly instructions with safe alternatives. This initial commit fixes
3 instruction forms that will lower to include a c3 (return) byte.
Additional problematic instructions can be fixed incrementally using
this framework.
- Refactor retguard to make adding additional arches easier.
Index: lib/Target/X86/CMakeLists.txt
--- lib/Target/X86/CMakeLists.txt.orig
+++ lib/Target/X86/CMakeLists.txt
@@ -42,6 +42,7 @@ set(sources
X86ExpandPseudo.cpp
X86FastISel.cpp
X86FixupBWInsts.cpp
+ X86FixupGadgets.cpp
X86FixupLEAs.cpp
X86AvoidStoreForwardingBlocks.cpp
X86FixupSetCC.cpp
@@ -71,6 +72,7 @@ set(sources
X86PartialReduction.cpp
X86RegisterBankInfo.cpp
X86RegisterInfo.cpp
+ X86ReturnProtectorLowering.cpp
X86SelectionDAGInfo.cpp
X86ShuffleDecodeConstantPool.cpp
X86SpeculativeLoadHardening.cpp

View file

@ -0,0 +1,14 @@
Use int3 trap padding between functions instead of trapsleds with a leading jump.
Index: lib/Target/X86/X86AsmPrinter.h
--- lib/Target/X86/X86AsmPrinter.h.orig
+++ lib/Target/X86/X86AsmPrinter.h
@@ -128,6 +128,8 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public A
void emitInstruction(const MachineInstr *MI) override;
+ void emitTrapToAlignment(Align Alignment) const override;
+
void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {
AsmPrinter::emitBasicBlockEnd(MBB);
SMShadowTracker.emitShadowPadding(*OutStreamer, getSubtargetInfo());

View file

@ -0,0 +1,720 @@
- Add a clang pass that identifies potential ROP gadgets and replaces ROP
friendly instructions with safe alternatives. This initial commit fixes
3 instruction forms that will lower to include a c3 (return) byte.
Additional problematic instructions can be fixed incrementally using
this framework.
- Improve the X86FixupGadgets pass
- Optimize gadget fixups for MOV instructions
Index: lib/Target/X86/X86FixupGadgets.cpp
--- lib/Target/X86/X86FixupGadgets.cpp.orig
+++ lib/Target/X86/X86FixupGadgets.cpp
@@ -0,0 +1,708 @@
+//===-- X86FixupGadgets.cpp - Fixup Instructions that make ROP Gadgets ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines a function pass that checks instructions for sequences
+/// that will lower to a potentially useful ROP gadget, and attempts to
+/// replace those sequences with alternatives that are not useful for ROP.
+///
+//===----------------------------------------------------------------------===//
+
+#include "X86.h"
+#include "X86InstrBuilder.h"
+#include "X86InstrInfo.h"
+#include "X86MachineFunctionInfo.h"
+#include "X86Subtarget.h"
+#include "X86TargetMachine.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define FIXUPGADGETS_DESC "X86 ROP Gadget Fixup"
+#define FIXUPGADGETS_NAME "x86-fixup-gadgets"
+
+#define DEBUG_TYPE FIXUPGADGETS_NAME
+
+// Toggle with cc1 option: -mllvm -x86-fixup-gadgets=<true|false>
+static cl::opt<bool> FixupGadgets(
+ "x86-fixup-gadgets", cl::Hidden,
+ cl::desc("Replace ROP friendly instructions with safe alternatives"),
+ cl::init(true));
+
+namespace {
+class FixupGadgetsPass : public MachineFunctionPass {
+
+public:
+ static char ID;
+
+ StringRef getPassName() const override { return FIXUPGADGETS_DESC; }
+
+ FixupGadgetsPass()
+ : MachineFunctionPass(ID), STI(nullptr), TII(nullptr), TRI(nullptr) {}
+
+ /// Loop over all the instructions and replace ROP friendly
+ /// seuqences with less ROP friendly alternatives
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ MachineFunctionProperties getRequiredProperties() const override {
+ return MachineFunctionProperties().set(
+ MachineFunctionProperties::Property::NoVRegs);
+ }
+
+private:
+ const X86Subtarget *STI;
+ const X86InstrInfo *TII;
+ const X86RegisterInfo *TRI;
+ bool Is64Bit;
+
+ struct FixupInfo {
+ unsigned op1;
+ unsigned op2;
+ bool fixup;
+ bool align;
+ };
+
+ uint8_t getRegNum(const MachineOperand &MO) const;
+ uint8_t getRegNum(unsigned reg) const;
+ struct FixupInfo isROPFriendly(MachineInstr &MI) const;
+ bool isROPFriendlyImm(const MachineOperand &MO) const;
+ bool isROPFriendlyRegPair(const MachineOperand &Dst,
+ const MachineOperand &Src) const;
+ bool isROPFriendlyReg(const MachineOperand &Dst, uint8_t RegOpcode) const;
+ bool badModRM(uint8_t Mod, uint8_t RegOpcode, uint8_t RM) const;
+ void checkSIB(const MachineInstr &MI, unsigned CurOp,
+ struct FixupInfo &info) const;
+ bool needsFixup(struct FixupInfo &fi) const;
+ bool needsAlign(struct FixupInfo &fi) const;
+ unsigned getWidestRegForReg(unsigned reg) const;
+ unsigned getEquivalentRegForReg(unsigned oreg, unsigned nreg) const;
+ bool hasImplicitUseOrDef(const MachineInstr &MI, unsigned Reg1,
+ unsigned Reg2) const;
+ bool fixupWithoutExchange(MachineInstr &MI);
+
+ bool fixupInstruction(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineInstr &MI, struct FixupInfo Info);
+};
+char FixupGadgetsPass::ID = 0;
+} // namespace
+
+FunctionPass *llvm::createX86FixupGadgetsPass() {
+ return new FixupGadgetsPass();
+}
+
+uint8_t FixupGadgetsPass::getRegNum(const MachineOperand &MO) const {
+ return TRI->getEncodingValue(MO.getReg()) & 0x7;
+}
+
+uint8_t FixupGadgetsPass::getRegNum(unsigned reg) const {
+ return TRI->getEncodingValue(reg) & 0x7;
+}
+
+bool FixupGadgetsPass::isROPFriendlyImm(const MachineOperand &MO) const {
+ int64_t imm = MO.getImm();
+ for (int i = 0; i < 8; ++i) {
+ uint8_t byte = (imm & 0xff);
+ if (byte == 0xc2 || byte == 0xc3 || byte == 0xca || byte == 0xcb) {
+ return true;
+ }
+ imm = imm >> 8;
+ }
+ return false;
+}
+
+bool FixupGadgetsPass::isROPFriendlyRegPair(const MachineOperand &Dst,
+ const MachineOperand &Src) const {
+
+ if (!Dst.isReg() || !Src.isReg())
+ llvm_unreachable("Testing non registers for bad reg pair!");
+
+ uint8_t Mod = 3;
+ uint8_t RegOpcode = getRegNum(Src);
+ uint8_t RM = getRegNum(Dst);
+ return badModRM(Mod, RegOpcode, RM);
+}
+
+bool FixupGadgetsPass::isROPFriendlyReg(const MachineOperand &Dst, uint8_t RegOpcode) const {
+
+ if (!Dst.isReg())
+ llvm_unreachable("Testing non register for bad reg!");
+
+ uint8_t Mod = 3;
+ uint8_t RM = getRegNum(Dst);
+ return badModRM(Mod, RegOpcode, RM);
+}
+
+bool FixupGadgetsPass::badModRM(uint8_t Mod, uint8_t RegOpcode,
+ uint8_t RM) const {
+ uint8_t ModRM = ((Mod << 6) | (RegOpcode << 3) | RM);
+ if (ModRM == 0xc2 || ModRM == 0xc3 || ModRM == 0xca || ModRM == 0xcb)
+ return true;
+ return false;
+}
+
+void FixupGadgetsPass::checkSIB(const MachineInstr &MI, unsigned CurOp,
+ struct FixupInfo &info) const {
+
+ const MachineOperand &Base = MI.getOperand(CurOp + X86::AddrBaseReg);
+ const MachineOperand &Scale = MI.getOperand(CurOp + X86::AddrScaleAmt);
+ const MachineOperand &Index = MI.getOperand(CurOp + X86::AddrIndexReg);
+
+ if (!Scale.isImm() || !Base.isReg() || !Index.isReg())
+ llvm_unreachable("Wrong type operands");
+
+ if (Scale.getImm() != 8 || Base.getReg() == 0 || Index.getReg() == 0)
+ return;
+
+ if (badModRM(3, getRegNum(Index), getRegNum(Base))) {
+ info.op1 = CurOp + X86::AddrBaseReg;
+ info.op2 = CurOp + X86::AddrIndexReg;
+ info.fixup = true;
+ }
+}
+
+struct FixupGadgetsPass::FixupInfo
+FixupGadgetsPass::isROPFriendly(MachineInstr &MI) const {
+
+ const MCInstrDesc &Desc = MI.getDesc();
+ unsigned CurOp = X86II::getOperandBias(Desc);
+ uint64_t TSFlags = Desc.TSFlags;
+ uint64_t Form = TSFlags & X86II::FormMask;
+ bool HasVEX_4V = TSFlags & X86II::VEX_4V;
+ bool HasEVEX_K = TSFlags & X86II::EVEX_K;
+
+ struct FixupInfo info = {0, 0, false, false};
+
+ // Look for constants with c3 in them
+ for (const auto &MO : MI.operands()) {
+ if (MO.isImm() && isROPFriendlyImm(MO)) {
+ info.align = true;
+ break;
+ }
+ }
+
+ switch (Form) {
+ case X86II::Pseudo: {
+ // Pesudos that are replaced with real instructions later
+ switch (MI.getOpcode()) {
+ case X86::ADD64rr_DB:
+ case X86::ADD32rr_DB:
+ case X86::ADD16rr_DB:
+ goto Handle_MRMDestReg;
+ case X86::ADD16ri_DB:
+ case X86::ADD32ri_DB:
+ case X86::ADD64ri32_DB:
+ case X86::ADD16ri8_DB:
+ case X86::ADD32ri8_DB:
+ case X86::ADD64ri8_DB:
+ goto Handle_MRMXr;
+ default:
+ break;
+ }
+ break;
+ }
+ case X86II::AddRegFrm: {
+ uint8_t BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
+ uint8_t Opcode = BaseOpcode + getRegNum(MI.getOperand(CurOp));
+ if (Opcode == 0xc2 || Opcode == 0xc3 || Opcode == 0xca || Opcode == 0xcb) {
+ info.op1 = CurOp;
+ info.fixup = true;
+ }
+ break;
+ }
+ case X86II::MRMDestMem: {
+ checkSIB(MI, CurOp, info);
+ unsigned opcode = MI.getOpcode();
+ if (opcode == X86::MOVNTImr || opcode == X86::MOVNTI_64mr)
+ info.align = true;
+ break;
+ }
+ case X86II::MRMSrcMem: {
+ CurOp += 1;
+ if (HasVEX_4V)
+ CurOp += 1;
+ if (HasEVEX_K)
+ CurOp += 1;
+ checkSIB(MI, CurOp, info);
+ break;
+ }
+ case X86II::MRMSrcMem4VOp3: {
+ CurOp += 1;
+ checkSIB(MI, CurOp, info);
+ break;
+ }
+ case X86II::MRMSrcMemOp4: {
+ CurOp += 3;
+ checkSIB(MI, CurOp, info);
+ break;
+ }
+ case X86II::MRMXm:
+ case X86II::MRM0m:
+ case X86II::MRM1m:
+ case X86II::MRM2m:
+ case X86II::MRM3m:
+ case X86II::MRM4m:
+ case X86II::MRM5m:
+ case X86II::MRM6m:
+ case X86II::MRM7m: {
+ if (HasVEX_4V)
+ CurOp += 1;
+ if (HasEVEX_K)
+ CurOp += 1;
+ checkSIB(MI, CurOp, info);
+ break;
+ }
+ case X86II::MRMDestReg: {
+ Handle_MRMDestReg:
+ const MachineOperand &DstReg = MI.getOperand(CurOp);
+ info.op1 = CurOp;
+ CurOp += 1;
+ if (HasVEX_4V)
+ CurOp += 1;
+ if (HasEVEX_K)
+ CurOp += 1;
+ const MachineOperand &SrcReg = MI.getOperand(CurOp);
+ info.op2 = CurOp;
+ if (isROPFriendlyRegPair(DstReg, SrcReg))
+ info.fixup = true;
+ break;
+ }
+ case X86II::MRMSrcReg: {
+ const MachineOperand &DstReg = MI.getOperand(CurOp);
+ info.op1 = CurOp;
+ CurOp += 1;
+ if (HasVEX_4V)
+ CurOp += 1;
+ if (HasEVEX_K)
+ CurOp += 1;
+ const MachineOperand &SrcReg = MI.getOperand(CurOp);
+ info.op2 = CurOp;
+ if (isROPFriendlyRegPair(SrcReg, DstReg))
+ info.fixup = true;
+ break;
+ }
+ case X86II::MRMSrcReg4VOp3: {
+ const MachineOperand &DstReg = MI.getOperand(CurOp);
+ info.op1 = CurOp;
+ CurOp += 1;
+ const MachineOperand &SrcReg = MI.getOperand(CurOp);
+ info.op2 = CurOp;
+ if (isROPFriendlyRegPair(SrcReg, DstReg))
+ info.fixup = true;
+ break;
+ }
+ case X86II::MRMSrcRegOp4: {
+ const MachineOperand &DstReg = MI.getOperand(CurOp);
+ info.op1 = CurOp;
+ CurOp += 3;
+ const MachineOperand &SrcReg = MI.getOperand(CurOp);
+ info.op2 = CurOp;
+ if (isROPFriendlyRegPair(SrcReg, DstReg))
+ info.fixup = true;
+ break;
+ }
+ case X86II::MRMXr:
+ case X86II::MRM0r:
+ case X86II::MRM1r: {
+Handle_MRMXr:
+ if (HasVEX_4V)
+ CurOp += 1;
+ if (HasEVEX_K)
+ CurOp += 1;
+ const MachineOperand &DstReg = MI.getOperand(CurOp);
+ info.op1 = CurOp;
+ if (isROPFriendlyReg(DstReg, Form == X86II::MRM1r ? 1 : 0))
+ info.fixup = true;
+ break;
+ }
+ case X86II::MRM_C2:
+ case X86II::MRM_C3:
+ case X86II::MRM_CA:
+ case X86II::MRM_CB: {
+ info.align = true;
+ break;
+ }
+ default:
+ break;
+ }
+ return info;
+}
+
+bool FixupGadgetsPass::needsFixup(struct FixupInfo &fi) const {
+ return (fi.fixup == true);
+}
+
+bool FixupGadgetsPass::needsAlign(struct FixupInfo &fi) const {
+ return (fi.align == true);
+}
+
+unsigned FixupGadgetsPass::getWidestRegForReg(unsigned reg) const {
+
+ switch (reg) {
+ case X86::AL:
+ case X86::AH:
+ case X86::AX:
+ case X86::EAX:
+ case X86::RAX:
+ return Is64Bit ? X86::RAX : X86::EAX;
+ case X86::BL:
+ case X86::BH:
+ case X86::BX:
+ case X86::EBX:
+ case X86::RBX:
+ return Is64Bit ? X86::RBX : X86::EBX;
+ case X86::CL:
+ case X86::CH:
+ case X86::CX:
+ case X86::ECX:
+ case X86::RCX:
+ return Is64Bit ? X86::RCX : X86::ECX;
+ case X86::DL:
+ case X86::DH:
+ case X86::DX:
+ case X86::EDX:
+ case X86::RDX:
+ return Is64Bit ? X86::RDX : X86::EDX;
+ case X86::R8B:
+ case X86::R8W:
+ case X86::R8D:
+ case X86::R8:
+ return X86::R8;
+ case X86::R9B:
+ case X86::R9W:
+ case X86::R9D:
+ case X86::R9:
+ return X86::R9;
+ case X86::R10B:
+ case X86::R10W:
+ case X86::R10D:
+ case X86::R10:
+ return X86::R10;
+ case X86::R11B:
+ case X86::R11W:
+ case X86::R11D:
+ case X86::R11:
+ return X86::R11;
+ default:
+ return X86::NoRegister; // Non-GP Reg
+ }
+ return 0;
+}
+
+// For given register oreg return the equivalent size register
+// from the nreg register set. Eg. For oreg ebx and nreg ax, return eax.
+unsigned FixupGadgetsPass::getEquivalentRegForReg(unsigned oreg,
+ unsigned nreg) const {
+ unsigned compreg = getWidestRegForReg(nreg);
+
+ switch (oreg) {
+ case X86::AL:
+ case X86::BL:
+ case X86::CL:
+ case X86::DL:
+ case X86::R8B:
+ case X86::R9B:
+ case X86::R10B:
+ case X86::R11B:
+ switch (compreg) {
+ case X86::EAX:
+ case X86::RAX:
+ return X86::AL;
+ case X86::EBX:
+ case X86::RBX:
+ return X86::BL;
+ case X86::ECX:
+ case X86::RCX:
+ return X86::CL;
+ case X86::EDX:
+ case X86::RDX:
+ return X86::DL;
+ case X86::R8:
+ return X86::R8B;
+ case X86::R9:
+ return X86::R9B;
+ case X86::R10:
+ return X86::R10B;
+ case X86::R11:
+ return X86::R11B;
+ default:
+ llvm_unreachable("Unknown 8 bit register");
+ }
+ break;
+ case X86::AH:
+ case X86::BH:
+ case X86::CH:
+ case X86::DH:
+ switch (compreg) {
+ case X86::EAX:
+ return X86::AH;
+ case X86::EBX:
+ return X86::BH;
+ case X86::ECX:
+ return X86::CH;
+ case X86::EDX:
+ return X86::DH;
+ default:
+ llvm_unreachable("Using H registers in REX mode");
+ }
+ break;
+ case X86::AX:
+ case X86::BX:
+ case X86::CX:
+ case X86::DX:
+ case X86::R8W:
+ case X86::R9W:
+ case X86::R10W:
+ case X86::R11W:
+ switch (compreg) {
+ case X86::EAX:
+ case X86::RAX:
+ return X86::AX;
+ case X86::EBX:
+ case X86::RBX:
+ return X86::BX;
+ case X86::ECX:
+ case X86::RCX:
+ return X86::CX;
+ case X86::EDX:
+ case X86::RDX:
+ return X86::DX;
+ case X86::R8:
+ return X86::R8W;
+ case X86::R9:
+ return X86::R9W;
+ case X86::R10:
+ return X86::R10W;
+ case X86::R11:
+ return X86::R11W;
+ default:
+ llvm_unreachable("Unknown 16 bit register");
+ }
+ break;
+ case X86::EAX:
+ case X86::EBX:
+ case X86::ECX:
+ case X86::EDX:
+ case X86::R8D:
+ case X86::R9D:
+ case X86::R10D:
+ case X86::R11D:
+ switch (compreg) {
+ case X86::EAX:
+ case X86::RAX:
+ return X86::EAX;
+ case X86::EBX:
+ case X86::RBX:
+ return X86::EBX;
+ case X86::ECX:
+ case X86::RCX:
+ return X86::ECX;
+ case X86::EDX:
+ case X86::RDX:
+ return X86::EDX;
+ case X86::R8:
+ return X86::R8D;
+ case X86::R9:
+ return X86::R9D;
+ case X86::R10:
+ return X86::R10D;
+ case X86::R11:
+ return X86::R11D;
+ default:
+ llvm_unreachable("Unknown 32 bit register");
+ }
+ break;
+ case X86::RAX:
+ case X86::RBX:
+ case X86::RCX:
+ case X86::RDX:
+ case X86::R8:
+ case X86::R9:
+ case X86::R10:
+ case X86::R11:
+ return compreg;
+ default:
+ llvm_unreachable("Unknown input register!");
+ }
+}
+
+bool FixupGadgetsPass::hasImplicitUseOrDef(const MachineInstr &MI,
+ unsigned Reg1, unsigned Reg2) const {
+
+ const MCInstrDesc &Desc = MI.getDesc();
+
+ const MCPhysReg *ImpDefs = Desc.getImplicitDefs();
+ if (ImpDefs) {
+ for (; *ImpDefs; ++ImpDefs) {
+ unsigned w = getWidestRegForReg(*ImpDefs);
+ if (w == Reg1 || w == Reg2) {
+ return true;
+ }
+ }
+ }
+
+ const MCPhysReg *ImpUses = Desc.getImplicitUses();
+ if (ImpUses) {
+ for (; *ImpUses; ++ImpUses) {
+ unsigned w = getWidestRegForReg(*ImpUses);
+ if (w == Reg1 || w == Reg2) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool FixupGadgetsPass::fixupWithoutExchange(MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case X86::MOV8rr_REV:
+ MI.setDesc(TII->get(X86::MOV8rr));
+ break;
+ case X86::MOV16rr_REV:
+ MI.setDesc(TII->get(X86::MOV16rr));
+ break;
+ case X86::MOV32rr_REV:
+ MI.setDesc(TII->get(X86::MOV32rr));
+ break;
+ case X86::MOV64rr_REV:
+ MI.setDesc(TII->get(X86::MOV64rr));
+ break;
+ case X86::MOV8rr:
+ MI.setDesc(TII->get(X86::MOV8rr_REV));
+ break;
+ case X86::MOV16rr:
+ MI.setDesc(TII->get(X86::MOV16rr_REV));
+ break;
+ case X86::MOV32rr:
+ MI.setDesc(TII->get(X86::MOV32rr_REV));
+ break;
+ case X86::MOV64rr:
+ MI.setDesc(TII->get(X86::MOV64rr_REV));
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool FixupGadgetsPass::fixupInstruction(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineInstr &MI, FixupInfo Info) {
+
+ if (!needsAlign(Info) && !needsFixup(Info))
+ return false;
+
+ DebugLoc DL = MI.getDebugLoc();
+
+ // Check for only needs alignment
+ if (needsAlign(Info) && !needsFixup(Info)) {
+ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
+ return true;
+ }
+
+ unsigned XCHG = Is64Bit ? X86::XCHG64rr : X86::XCHG32rr;
+
+ unsigned OrigReg1 = MI.getOperand(Info.op1).getReg();
+ // Swap with RAX/EAX unless we have a second register to swap with
+ unsigned OrigReg2 = Is64Bit ? X86::RAX : X86::EAX;
+ if (Info.op2)
+ OrigReg2 = MI.getOperand(Info.op2).getReg();
+
+ unsigned SwapReg1 = getWidestRegForReg(OrigReg1);
+ unsigned SwapReg2 = getWidestRegForReg(OrigReg2);
+ unsigned CompReg1 = SwapReg1;
+ unsigned CompReg2 = SwapReg2;
+
+ // Just align if:
+ // - we have a non-GP reg to swap with
+ // - the instruction implicitly uses one of the registers we are swapping
+ // - if we are fixing an instruction that skips the xchg back
+ if (SwapReg1 == X86::NoRegister || SwapReg2 == X86::NoRegister ||
+ hasImplicitUseOrDef(MI, CompReg1, CompReg2) || MI.isCall() ||
+ MI.isReturn() || MI.isBranch() || MI.isIndirectBranch() ||
+ MI.isBarrier()) {
+ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
+ return true;
+ }
+
+ // Make sure our XCHG doesn't make a gadget
+ if (badModRM(3, getRegNum(SwapReg1), getRegNum(SwapReg2))) {
+ unsigned treg = SwapReg1;
+ SwapReg1 = SwapReg2;
+ SwapReg2 = treg;
+ }
+
+ // Check for specific instructions we can fix without the xchg dance
+ if (fixupWithoutExchange(MI)) {
+ return true;
+ }
+
+ // Swap the two registers to start
+ BuildMI(MBB, MI, DL, TII->get(XCHG))
+ .addReg(SwapReg1, RegState::Define)
+ .addReg(SwapReg2, RegState::Define)
+ .addReg(SwapReg1).addReg(SwapReg2);
+
+ // Check for needs alignment
+ if (needsAlign(Info))
+ BuildMI(MBB, MI, DL, TII->get(X86::JMP_TRAP));
+
+ // Swap the registers inside the instruction
+ for (MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg())
+ continue;
+
+ unsigned reg = MO.getReg();
+ unsigned match = getWidestRegForReg(reg);
+ if (match == CompReg1)
+ MO.setReg(getEquivalentRegForReg(reg, OrigReg2));
+ else if (match == CompReg2)
+ MO.setReg(getEquivalentRegForReg(reg, OrigReg1));
+ }
+
+ // And swap the two registers back
+ BuildMI(MBB, ++MachineBasicBlock::instr_iterator(MI), DL, TII->get(XCHG))
+ .addReg(SwapReg1, RegState::Define)
+ .addReg(SwapReg2, RegState::Define)
+ .addReg(SwapReg1).addReg(SwapReg2);
+
+ return true;
+}
+
+bool FixupGadgetsPass::runOnMachineFunction(MachineFunction &MF) {
+ if (!FixupGadgets)
+ return false;
+
+ STI = &MF.getSubtarget<X86Subtarget>();
+ TII = STI->getInstrInfo();
+ TRI = STI->getRegisterInfo();
+ Is64Bit = STI->is64Bit();
+ std::vector<std::pair<MachineInstr *, FixupInfo>> fixups;
+ FixupInfo info;
+
+ bool modified = false;
+
+ for (auto &MBB : MF) {
+ fixups.clear();
+ for (auto &MI : MBB) {
+ info = isROPFriendly(MI);
+ if (needsAlign(info) || needsFixup(info))
+ fixups.push_back(std::make_pair(&MI, info));
+ }
+ for (auto &fixup : fixups)
+ modified |= fixupInstruction(MF, MBB, *fixup.first, fixup.second);
+ }
+
+ return modified;
+}

View file

@ -0,0 +1,175 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
- implement -msave-args in clang/llvm, like the sun did for gcc
Index: lib/Target/X86/X86FrameLowering.cpp
--- lib/Target/X86/X86FrameLowering.cpp.orig
+++ lib/Target/X86/X86FrameLowering.cpp
@@ -14,6 +14,7 @@
#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
+#include "X86ReturnProtectorLowering.h"
#include "X86Subtarget.h"
#include "X86TargetMachine.h"
#include "llvm/ADT/SmallSet.h"
@@ -46,7 +47,7 @@ X86FrameLowering::X86FrameLowering(const X86Subtarget
MaybeAlign StackAlignOverride)
: TargetFrameLowering(StackGrowsDown, StackAlignOverride.valueOrOne(),
STI.is64Bit() ? -8 : -4),
- STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {
+ STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()), RPL() {
// Cache a bunch of frame-related predicates for this subtarget.
SlotSize = TRI->getSlotSize();
Is64Bit = STI.is64Bit();
@@ -54,6 +55,7 @@ X86FrameLowering::X86FrameLowering(const X86Subtarget
// standard x86_64 and NaCl use 64-bit frame/stack pointers, x32 - 32-bit.
Uses64BitFramePtr = STI.isTarget64BitLP64() || STI.isTargetNaCl64();
StackPtr = TRI->getStackRegister();
+ SaveArgs = Is64Bit ? STI.getSaveArgs() : 0;
}
bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
@@ -99,7 +101,8 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF
MF.getInfo<X86MachineFunctionInfo>()->hasPreallocatedCall() ||
MF.callsUnwindInit() || MF.hasEHFunclets() || MF.callsEHReturn() ||
MFI.hasStackMap() || MFI.hasPatchPoint() ||
- MFI.hasCopyImplyingStackAdjustment());
+ MFI.hasCopyImplyingStackAdjustment() ||
+ SaveArgs);
}
static unsigned getSUBriOpcode(bool IsLP64, int64_t Imm) {
@@ -1213,6 +1216,24 @@ void X86FrameLowering::BuildStackAlignAND(MachineBasic
}
}
+// FIXME: Get this from tablegen.
+static ArrayRef<MCPhysReg> get64BitArgumentGPRs(CallingConv::ID CallConv,
+ const X86Subtarget &Subtarget) {
+ assert(Subtarget.is64Bit());
+
+ if (Subtarget.isCallingConvWin64(CallConv)) {
+ static const MCPhysReg GPR64ArgRegsWin64[] = {
+ X86::RCX, X86::RDX, X86::R8, X86::R9
+ };
+ return makeArrayRef(std::begin(GPR64ArgRegsWin64), std::end(GPR64ArgRegsWin64));
+ }
+
+ static const MCPhysReg GPR64ArgRegs64Bit[] = {
+ X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9
+ };
+ return makeArrayRef(std::begin(GPR64ArgRegs64Bit), std::end(GPR64ArgRegs64Bit));
+}
+
bool X86FrameLowering::has128ByteRedZone(const MachineFunction& MF) const {
// x86-64 (non Win64) has a 128 byte red zone which is guaranteed not to be
// clobbered by any interrupt handler.
@@ -1537,6 +1558,43 @@ void X86FrameLowering::emitPrologue(MachineFunction &M
.addReg(StackPtr)
.setMIFlag(MachineInstr::FrameSetup);
+ if (SaveArgs && !Fn.arg_empty()) {
+ ArrayRef<MCPhysReg> GPRs =
+ get64BitArgumentGPRs(Fn.getCallingConv(), STI);
+ unsigned arg_size = Fn.arg_size();
+ unsigned RI = 0;
+ int64_t SaveSize = 0;
+
+ if (Fn.hasStructRetAttr()) {
+ GPRs = GPRs.drop_front(1);
+ arg_size--;
+ }
+
+ for (MCPhysReg Reg : GPRs) {
+ if (++RI > arg_size)
+ break;
+
+ SaveSize += SlotSize;
+
+ BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
+ .addReg(Reg)
+ .setMIFlag(MachineInstr::FrameSetup);
+ }
+
+ // Realign the stack. PUSHes are the most space efficient.
+ while (SaveSize % getStackAlignment()) {
+ BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64r))
+ .addReg(GPRs.front())
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ SaveSize += SlotSize;
+ }
+
+ //dlg StackSize -= SaveSize;
+ //dlg MFI.setStackSize(StackSize);
+ X86FI->setSaveArgSize(SaveSize);
+ }
+
if (NeedsDwarfCFI) {
// Mark effective beginning of when frame pointer becomes valid.
// Define the current CFA to use the EBP/RBP register.
@@ -2047,10 +2105,17 @@ void X86FrameLowering::emitEpilogue(MachineFunction &M
int Offset = 16 + mergeSPUpdates(MBB, MBBI, true);
emitSPUpdate(MBB, MBBI, DL, Offset, /*InEpilogue*/true);
}
- // Pop EBP.
- BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
+
+ if (X86FI->getSaveArgSize()) {
+ // LEAVE is effectively mov rbp,rsp; pop rbp
+ BuildMI(MBB, MBBI, DL, TII.get(X86::LEAVE64))
+ .setMIFlag(MachineInstr::FrameDestroy);
+ } else {
+ // Pop EBP.
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
+ }
// We need to reset FP to its untagged state on return. Bit 60 is currently
// used to show the presence of an extended frame.
@@ -2087,6 +2152,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &M
if (Opc != X86::DBG_VALUE && !PI->isTerminator()) {
if ((Opc != X86::POP32r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
(Opc != X86::POP64r || !PI->getFlag(MachineInstr::FrameDestroy)) &&
+ (Opc != X86::LEAVE64 || !PI->getFlag(MachineInstr::FrameDestroy)) &&
(Opc != X86::BTR64ri8 || !PI->getFlag(MachineInstr::FrameDestroy)) &&
(Opc != X86::ADD64ri8 || !PI->getFlag(MachineInstr::FrameDestroy)))
break;
@@ -2266,6 +2332,8 @@ StackOffset X86FrameLowering::getFrameIndexReference(c
"FPDelta isn't aligned per the Win64 ABI!");
}
+ if (FI >= 0)
+ Offset -= X86FI->getSaveArgSize();
if (TRI->hasBasePointer(MF)) {
assert(HasFP && "VLAs and dynamic stack realign, but no FP?!");
@@ -3699,6 +3767,10 @@ void X86FrameLowering::adjustFrameForMsvcCxxEh(Machine
addFrameReference(BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64mi32)),
UnwindHelpFI)
.addImm(-2);
+}
+
+const ReturnProtectorLowering *X86FrameLowering::getReturnProtector() const {
+ return &RPL;
}
void X86FrameLowering::processFunctionBeforeFrameIndicesReplaced(

View file

@ -0,0 +1,59 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Refactor retguard to make adding additional arches easier.
- implement -msave-args in clang/llvm, like the sun did for gcc
Index: lib/Target/X86/X86FrameLowering.h
--- lib/Target/X86/X86FrameLowering.h.orig
+++ lib/Target/X86/X86FrameLowering.h
@@ -13,6 +13,7 @@
#ifndef LLVM_LIB_TARGET_X86_X86FRAMELOWERING_H
#define LLVM_LIB_TARGET_X86_X86FRAMELOWERING_H
+#include "X86ReturnProtectorLowering.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/Support/TypeSize.h"
@@ -23,6 +24,7 @@ class MCCFIInstruction;
class X86InstrInfo;
class X86Subtarget;
class X86RegisterInfo;
+class X86ReturnProtectorLowering;
class X86FrameLowering : public TargetFrameLowering {
public:
@@ -33,7 +35,10 @@ class X86FrameLowering : public TargetFrameLowering {
const X86Subtarget &STI;
const X86InstrInfo &TII;
const X86RegisterInfo *TRI;
+ const X86ReturnProtectorLowering RPL;
+ bool SaveArgs;
+
unsigned SlotSize;
/// Is64Bit implies that x86_64 instructions are available.
@@ -71,6 +76,8 @@ class X86FrameLowering : public TargetFrameLowering {
/// the function.
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+
+ const ReturnProtectorLowering *getReturnProtector() const override;
void adjustForSegmentedStacks(MachineFunction &MF,
MachineBasicBlock &PrologueMBB) const override;

View file

@ -0,0 +1,13 @@
Add lfence after ret in retpoline thunk.
Index: lib/Target/X86/X86IndirectThunks.cpp
--- lib/Target/X86/X86IndirectThunks.cpp.orig
+++ lib/Target/X86/X86IndirectThunks.cpp
@@ -249,6 +249,7 @@ void RetpolineThunkInserter::populateThunk(MachineFunc
CallTarget->back().setPreInstrSymbol(MF, TargetSym);
BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc));
+ BuildMI(CallTarget, DebugLoc(), TII->get(X86::LFENCE));
}
FunctionPass *llvm::createX86IndirectThunksPass() {

View file

@ -0,0 +1,48 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Improve the X86FixupGadgets pass
Index: lib/Target/X86/X86InstrCompiler.td
--- lib/Target/X86/X86InstrCompiler.td.orig
+++ lib/Target/X86/X86InstrCompiler.td
@@ -277,6 +277,25 @@ def MORESTACK_RET_RESTORE_R10 : I<0, Pseudo, (outs), (
}
//===----------------------------------------------------------------------===//
+// Pseudo instruction used by retguard
+
+// This is lowered to a JE 2; INT3; INT3. Prior to this pseudo should be a
+// compare instruction to ensure the retguard cookie is correct.
+// We use a pseudo here in order to avoid splitting the BB just before the return.
+// Splitting the BB and inserting a JE_1 over a new INT3 BB occasionally
+// resulted in incorrect code when a value from a byte register (CL) was
+// used as a return value. When emitted as a split BB, the single byte
+// register would sometimes be widened to 4 bytes, which would corrupt
+// the return value (ie mov %ecx, %eax instead of mov %cl, %al).
+let isCodeGenOnly = 1, hasNoSchedulingInfo = 1, Uses = [EFLAGS] in {
+def RETGUARD_JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
+}
+
+let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
+def JMP_TRAP: I<0, Pseudo, (outs), (ins), "", []>;
+}
+
+//===----------------------------------------------------------------------===//
// Alias Instructions
//===----------------------------------------------------------------------===//

View file

@ -0,0 +1,87 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Use int3 trap padding between functions instead of trapsleds with a leading jump.
- Emit variable length trap padding in retguard epilogue.
This adds more trap padding before the return while ensuring that the
return is still in the same cache line.
Index: lib/Target/X86/X86MCInstLower.cpp
--- lib/Target/X86/X86MCInstLower.cpp.orig
+++ lib/Target/X86/X86MCInstLower.cpp
@@ -2570,6 +2570,50 @@ void X86AsmPrinter::emitInstruction(const MachineInstr
MCInstBuilder(X86::MOV64rr).addReg(X86::R10).addReg(X86::RAX));
return;
+ case X86::RETGUARD_JMP_TRAP: {
+ // Make a symbol for the end of the trapsled and emit a jump to it
+ MCSymbol *RGSuccSym = OutContext.createTempSymbol();
+ const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext);
+ EmitAndCountInstruction(MCInstBuilder(X86::JCC_1)
+ .addExpr(RGSuccExpr)
+ .addImm(X86::COND_E));
+
+ // Emit at least two trap instructions
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+
+ // Now .fill up to 0xe byte, so the ret happens on 0xf
+ MCSymbol *Dot = OutContext.createTempSymbol();
+ OutStreamer->emitLabel(Dot);
+ const MCExpr *DotE = MCSymbolRefExpr::create(Dot, OutContext);
+ const MCExpr *BaseE = MCSymbolRefExpr::create(
+ TM.getSymbol(&MF->getFunction()), OutContext);
+ // .fill (0xf - ((DotE - BaseE) & 0xf)), 1, 0xcc
+ const MCExpr *FillE = MCBinaryExpr::createSub(
+ MCConstantExpr::create(0xf, OutContext),
+ MCBinaryExpr::createAnd(
+ MCBinaryExpr::createSub(DotE, BaseE, OutContext),
+ MCConstantExpr::create(0xf, OutContext),
+ OutContext),
+ OutContext);
+ OutStreamer->emitFill(*FillE, 0xCC);
+
+ // And finally emit the jump target symbol
+ OutStreamer->emitLabel(RGSuccSym);
+ return;
+ }
+
+ case X86::JMP_TRAP: {
+ MCSymbol *RGSuccSym = OutContext.createTempSymbol();
+ const MCExpr *RGSuccExpr = MCSymbolRefExpr::create(RGSuccSym, OutContext);
+ EmitAndCountInstruction(MCInstBuilder(X86::JMP_1).addExpr(RGSuccExpr));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ EmitAndCountInstruction(MCInstBuilder(X86::INT3));
+ OutStreamer->emitValueToAlignment(8, 0xCC, 1);
+ OutStreamer->emitLabel(RGSuccSym);
+ return;
+ }
+
case X86::SEH_PushReg:
case X86::SEH_SaveReg:
case X86::SEH_SaveXMM:
@@ -2628,4 +2672,10 @@ void X86AsmPrinter::emitInstruction(const MachineInstr
}
EmitAndCountInstruction(TmpInst);
+}
+
+/// Emit Trap bytes to the specified power of two alignment
+void X86AsmPrinter::emitTrapToAlignment(Align Alignment) const {
+ if (Alignment == Align(1)) return;
+ OutStreamer->emitValueToAlignment(Alignment.value(), 0xCC, 1);
}

View file

@ -0,0 +1,25 @@
implement -msave-args in clang/llvm, like the sun did for gcc
Index: lib/Target/X86/X86MachineFunctionInfo.h
--- lib/Target/X86/X86MachineFunctionInfo.h.orig
+++ lib/Target/X86/X86MachineFunctionInfo.h
@@ -45,6 +45,9 @@ class X86MachineFunctionInfo : public MachineFunctionI
/// stack frame in bytes.
unsigned CalleeSavedFrameSize = 0;
+ // SaveArgSize - Number of register arguments saved on the stack
+ unsigned SaveArgSize = 0;
+
/// BytesToPopOnReturn - Number of bytes function pops on return (in addition
/// to the space used by the return address).
/// Used on windows platform for stdcall & fastcall name decoration
@@ -145,6 +148,9 @@ class X86MachineFunctionInfo : public MachineFunctionI
unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; }
void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; }
+
+ unsigned getSaveArgSize() const { return SaveArgSize; }
+ void setSaveArgSize(unsigned bytes) { SaveArgSize = bytes; }
unsigned getBytesToPopOnReturn() const { return BytesToPopOnReturn; }
void setBytesToPopOnReturn (unsigned bytes) { BytesToPopOnReturn = bytes;}

View file

@ -0,0 +1,43 @@
- The compiler is generally free to allocate general purpose registers in
whatever order it chooses. Reasons for choosing one register before another
usually include compiled instruction size (avoidance of REX prefixes, etc.)
or usage conventions, but somehow haven't included security implications in
the compiled bytecode. Some bytecode is more useful in polymorphic ROP
sequences than others, so it seems prudent to try to avoid that bytecode
when possible.
This patch moves EBX/RBX towards the end of the allocation preference for 32
and 64 bit general purpose registers. Some instructions using RBX/EBX/BX/BL
as a destination register end up with a ModR/M byte of C3 or CB, which is often
useful in ROP gadgets. Because these gadgets often occur in the middle of
functions, they exhibit somewhat higher diversity than some other C3/CB
terminated gadgets. This change removes about 3% of total gadgets from the
kernel, but about 6% of unique gadgets.
There are other possible changes in this direction. BX/BL are obvious next
targets for avoidance, and MM3/XMM3 may also be useful to try to avoid if
possible.
Index: lib/Target/X86/X86RegisterInfo.td
--- lib/Target/X86/X86RegisterInfo.td.orig
+++ lib/Target/X86/X86RegisterInfo.td
@@ -424,8 +424,8 @@ def GRH16 : RegisterClass<"X86", [i16], 16,
R15WH)>;
def GR32 : RegisterClass<"X86", [i32], 32,
- (add EAX, ECX, EDX, ESI, EDI, EBX, EBP, ESP,
- R8D, R9D, R10D, R11D, R14D, R15D, R12D, R13D)>;
+ (add EAX, ECX, EDX, ESI, EDI,
+ R8D, R9D, R10D, R11D, R14D, R15D, R12D, R13D, EBX, EBP, ESP)>;
// GR64 - 64-bit GPRs. This oddly includes RIP, which isn't accurate, since
// RIP isn't really a register and it can't be used anywhere except in an
@@ -434,7 +434,7 @@ def GR32 : RegisterClass<"X86", [i32], 32,
// tests because of the inclusion of RIP in this register class.
def GR64 : RegisterClass<"X86", [i64], 64,
(add RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11,
- RBX, R14, R15, R12, R13, RBP, RSP, RIP)>;
+ R14, R15, R12, R13, RBX, RBP, RSP, RIP)>;
// Segment registers for use by MOV instructions (and others) that have a
// segment register as one operand. Always contain a 16-bit segment

View file

@ -0,0 +1,130 @@
- Refactor retguard to make adding additional arches easier.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: lib/Target/X86/X86ReturnProtectorLowering.cpp
--- lib/Target/X86/X86ReturnProtectorLowering.cpp.orig
+++ lib/Target/X86/X86ReturnProtectorLowering.cpp
@@ -0,0 +1,121 @@
+//===-- X86ReturnProtectorLowering.cpp - ----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the X86 implementation of ReturnProtectorLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "X86ReturnProtectorLowering.h"
+#include "X86InstrBuilder.h"
+#include "X86InstrInfo.h"
+#include "X86MachineFunctionInfo.h"
+#include "X86Subtarget.h"
+#include "X86TargetMachine.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Target/TargetOptions.h"
+#include <cstdlib>
+
+using namespace llvm;
+
+void X86ReturnProtectorLowering::insertReturnProtectorPrologue(
+ MachineFunction &MF, MachineBasicBlock &MBB, GlobalVariable *cookie) const {
+
+ MachineBasicBlock::instr_iterator MI = MBB.instr_begin();
+ DebugLoc MBBDL = MBB.findDebugLoc(MI);
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ BuildMI(MBB, MI, MBBDL, TII->get(X86::MOV64rm), REG)
+ .addReg(X86::RIP)
+ .addImm(0)
+ .addReg(0)
+ .addGlobalAddress(cookie)
+ .addReg(0);
+ addDirectMem(BuildMI(MBB, MI, MBBDL, TII->get(X86::XOR64rm), REG).addReg(REG),
+ X86::RSP);
+}
+
+void X86ReturnProtectorLowering::insertReturnProtectorEpilogue(
+ MachineFunction &MF, MachineInstr &MI, GlobalVariable *cookie) const {
+
+ MachineBasicBlock &MBB = *MI.getParent();
+ DebugLoc MBBDL = MI.getDebugLoc();
+ const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
+ unsigned REG = MF.getFrameInfo().getReturnProtectorRegister();
+
+ addDirectMem(BuildMI(MBB, MI, MBBDL, TII->get(X86::XOR64rm), REG).addReg(REG),
+ X86::RSP);
+ BuildMI(MBB, MI, MBBDL, TII->get(X86::CMP64rm))
+ .addReg(REG)
+ .addReg(X86::RIP)
+ .addImm(0)
+ .addReg(0)
+ .addGlobalAddress(cookie)
+ .addReg(0);
+ BuildMI(MBB, MI, MBBDL, TII->get(X86::RETGUARD_JMP_TRAP));
+}
+
+bool X86ReturnProtectorLowering::opcodeIsReturn(unsigned opcode) const {
+ switch (opcode) {
+ case X86::RET:
+ case X86::RETL:
+ case X86::RETQ:
+ case X86::RETW:
+ case X86::RETIL:
+ case X86::RETIQ:
+ case X86::RETIW:
+ case X86::LRETL:
+ case X86::LRETQ:
+ case X86::LRETW:
+ case X86::LRETIL:
+ case X86::LRETIQ:
+ case X86::LRETIW:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void X86ReturnProtectorLowering::fillTempRegisters(
+ MachineFunction &MF, std::vector<unsigned> &TempRegs) const {
+
+ TempRegs.push_back(X86::R11);
+ TempRegs.push_back(X86::R10);
+ const Function &F = MF.getFunction();
+ if (!F.isVarArg()) {
+ // We can use any of the caller saved unused arg registers
+ switch (F.arg_size()) {
+ case 0:
+ TempRegs.push_back(X86::RDI);
+ LLVM_FALLTHROUGH;
+ case 1:
+ TempRegs.push_back(X86::RSI);
+ LLVM_FALLTHROUGH;
+ case 2: // RDX is the 2nd return register
+ case 3:
+ TempRegs.push_back(X86::RCX);
+ LLVM_FALLTHROUGH;
+ case 4:
+ TempRegs.push_back(X86::R8);
+ LLVM_FALLTHROUGH;
+ case 5:
+ TempRegs.push_back(X86::R9);
+ LLVM_FALLTHROUGH;
+ default:
+ break;
+ }
+ }
+}

View file

@ -0,0 +1,51 @@
Refactor retguard to make adding additional arches easier.
Index: lib/Target/X86/X86ReturnProtectorLowering.h
--- lib/Target/X86/X86ReturnProtectorLowering.h.orig
+++ lib/Target/X86/X86ReturnProtectorLowering.h
@@ -0,0 +1,45 @@
+//===-- X86ReturnProtectorLowering.h - ------------------------- -*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the X86 implementation of ReturnProtectorLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_X86_X86RETURNPROTECTORLOWERING_H
+#define LLVM_LIB_TARGET_X86_X86RETURNPROTECTORLOWERING_H
+
+#include "llvm/CodeGen/ReturnProtectorLowering.h"
+
+namespace llvm {
+
+class X86ReturnProtectorLowering : public ReturnProtectorLowering {
+public:
+ /// insertReturnProtectorPrologue/Epilogue - insert return protector
+ /// instrumentation in prologue or epilogue.
+ virtual void
+ insertReturnProtectorPrologue(MachineFunction &MF, MachineBasicBlock &MBB,
+ GlobalVariable *cookie) const override;
+ virtual void
+ insertReturnProtectorEpilogue(MachineFunction &MF, MachineInstr &MI,
+ GlobalVariable *cookie) const override;
+
+ /// opcodeIsReturn - Reuturn true is the given opcode is a return
+ /// instruction needing return protection, false otherwise.
+ virtual bool opcodeIsReturn(unsigned opcode) const override;
+
+ /// fillTempRegisters - Fill the list of available temp registers we can
+ /// use as a return protector register.
+ virtual void
+ fillTempRegisters(MachineFunction &MF,
+ std::vector<unsigned> &TempRegs) const override;
+};
+
+} // namespace llvm
+
+#endif

View file

@ -0,0 +1,33 @@
- implement -msave-args in clang/llvm, like the sun did for gcc
- Turn on -mretpoline by default in clang on amd64.
Index: lib/Target/X86/X86Subtarget.h
--- lib/Target/X86/X86Subtarget.h.orig
+++ lib/Target/X86/X86Subtarget.h
@@ -481,6 +481,9 @@ class X86Subtarget final : public X86GenSubtargetInfo
Align TileConfigAlignment = Align(4);
+ /// Whether function prologues should save register arguments on the stack.
+ bool SaveArgs = false;
+
/// Max. memset / memcpy size that is turned into rep/movs, rep/stos ops.
///
// FIXME: this is a known good value for Yonah. How about others?
@@ -567,6 +570,8 @@ class X86Subtarget final : public X86GenSubtargetInfo
unsigned getTileConfigSize() const { return 64; }
Align getTileConfigAlignment() const { return TileConfigAlignment; }
+ bool getSaveArgs() const { return SaveArgs; }
+
/// Returns the minimum alignment known to hold of the
/// stack frame on entry to the function and which must be maintained by every
/// function for this subtarget.
@@ -832,6 +837,7 @@ class X86Subtarget final : public X86GenSubtargetInfo
bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); }
bool isTargetFreeBSD() const { return TargetTriple.isOSFreeBSD(); }
+ bool isTargetOpenBSD() const { return TargetTriple.isOSOpenBSD(); }
bool isTargetDragonFly() const { return TargetTriple.isOSDragonFly(); }
bool isTargetSolaris() const { return TargetTriple.isOSSolaris(); }
bool isTargetPS4() const { return TargetTriple.isPS4CPU(); }

View file

@ -0,0 +1,17 @@
Add a clang pass that identifies potential ROP gadgets and replaces ROP
friendly instructions with safe alternatives. This initial commit fixes
3 instruction forms that will lower to include a c3 (return) byte.
Additional problematic instructions can be fixed incrementally using
this framework.
Index: lib/Target/X86/X86TargetMachine.cpp
--- lib/Target/X86/X86TargetMachine.cpp.orig
+++ lib/Target/X86/X86TargetMachine.cpp
@@ -546,6 +546,7 @@ void X86PassConfig::addPreEmitPass() {
addPass(createX86EvexToVexInsts());
addPass(createX86DiscriminateMemOpsPass());
addPass(createX86InsertPrefetchPass());
+ addPass(createX86FixupGadgetsPass());
addPass(createX86InsertX87waitPass());
}

View file

@ -0,0 +1,20 @@
Add a clang pass that identifies potential ROP gadgets and replaces ROP
friendly instructions with safe alternatives. This initial commit fixes
3 instruction forms that will lower to include a c3 (return) byte.
Additional problematic instructions can be fixed incrementally using
this framework.
Index: lib/Target/X86/X86.h
--- lib/Target/X86/X86.h.orig
+++ lib/Target/X86/X86.h
@@ -122,6 +122,10 @@ FunctionPass *createX86FixupBWInsts();
/// to another, when profitable.
FunctionPass *createX86DomainReassignmentPass();
+/// Return a Machine Function pass that attempts to replace
+/// ROP friendly instructions with alternatives.
+FunctionPass *createX86FixupGadgetsPass();
+
/// This pass replaces EVEX encoded of AVX-512 instructiosn by VEX
/// encoding when possible in order to reduce code size.
FunctionPass *createX86EvexToVexInsts();

View file

@ -0,0 +1,15 @@
implement -msave-args in clang/llvm, like the sun did for gcc
Index: lib/Target/X86/X86.td
--- lib/Target/X86/X86.td.orig
+++ lib/Target/X86/X86.td
@@ -321,6 +321,9 @@ def FeatureLZCNTFalseDeps : SubtargetFeature<"false-de
"LZCNT/TZCNT have a false dependency on dest register">;
def FeaturePCONFIG : SubtargetFeature<"pconfig", "HasPCONFIG", "true",
"platform configuration instruction">;
+def FeatureSaveArgs
+ : SubtargetFeature<"save-args", "SaveArgs", "true",
+ "Save register arguments on the stack.">;
// On recent X86 (port bound) processors, its preferable to combine to a single shuffle
// using a variable mask over multiple fixed shuffles.
def FeatureFastVariableCrossLaneShuffle

View file

@ -0,0 +1,17 @@
Disable loop idiom recognition for _libc_memset and _libc_memcpy. These are
the internal names we use in libc for memset and memcpy and having the
compiler optimize them as calls to memset and memcpy will lead to infinite
recursion.
Index: lib/Transforms/Scalar/LoopIdiomRecognize.cpp
--- lib/Transforms/Scalar/LoopIdiomRecognize.cpp.orig
+++ lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -367,6 +367,8 @@ bool LoopIdiomRecognize::runOnLoop(Loop *L) {
StringRef Name = L->getHeader()->getParent()->getName();
if (Name == "memset" || Name == "memcpy")
return false;
+ if (Name == "_libc_memset" || Name == "_libc_memcpy")
+ return false;
// Determine if code size heuristics need to be applied.
ApplyCodeSizeHeuristics =

View file

@ -0,0 +1,20 @@
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length specifiers
and type check like it is used by the regular case.
Index: tools/clang/include/clang/AST/FormatString.h
--- tools/clang/include/clang/AST/FormatString.h.orig
+++ tools/clang/include/clang/AST/FormatString.h
@@ -227,8 +227,10 @@ class ConversionSpecifier { (public)
bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||
kind == FreeBSDrArg || kind == FreeBSDyArg; }
- bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }
- bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }
+ bool isUIntArg() const { return (kind >= UIntArgBeg && kind <= UIntArgEnd) ||
+ kind == FreeBSDbArg; }
+ bool isAnyIntArg() const { return (kind >= IntArgBeg && kind <= UIntArgEnd) ||
+ kind == FreeBSDbArg; }
bool isDoubleArg() const {
return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
}

View file

@ -0,0 +1,32 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Disable strict floating point if not X86.
Index: tools/clang/include/clang/Basic/CodeGenOptions.def
--- tools/clang/include/clang/Basic/CodeGenOptions.def.orig
+++ tools/clang/include/clang/Basic/CodeGenOptions.def
@@ -340,6 +340,9 @@ VALUE_CODEGENOPT(SmallDataLimit, 32, 0)
/// The lower bound for a buffer to be considered for stack protection.
VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
+/// Whether to use return protectors
+CODEGENOPT(ReturnProtector, 1, 0)
+
/// The kind of generated debug info.
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 4, codegenoptions::NoDebugInfo)

View file

@ -0,0 +1,72 @@
- Disable -Waddress-of-packed-member by default.
While these warnings have the potential to be useful, there are too many
false positives right now.
- Disable -Wpointer-sign warnings per default
base gcc does the same.
- Add a new warning for %n format specifier usage in printf(3) family functions
- allow out-of-class defaulting of comparison operators
this is backport of the following upstream commit:
commit 5fbe21a7748f91adbd1b16c95bbfe180642320a3
Index: tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
--- tools/clang/include/clang/Basic/DiagnosticSemaKinds.td.orig
+++ tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6768,7 +6768,7 @@ def warn_pointer_indirection_from_incompatible_type :
InGroup<UndefinedReinterpretCast>, DefaultIgnore;
def warn_taking_address_of_packed_member : Warning<
"taking address of packed member %0 of class or structure %q1 may result in an unaligned pointer value">,
- InGroup<DiagGroup<"address-of-packed-member">>;
+ InGroup<DiagGroup<"address-of-packed-member">>, DefaultIgnore;
def warn_param_mismatched_alignment : Warning<
"passing %0-byte aligned argument to %1-byte aligned parameter %2 of %3 may result in an unaligned pointer access">,
InGroup<DiagGroup<"align-mismatch">>;
@@ -7980,7 +7980,7 @@ def ext_typecheck_convert_incompatible_pointer_sign :
"|%diff{casting $ to type $|casting between types}0,1}2"
" converts between pointers to integer types %select{with different sign|"
"where one is of the unique plain 'char' type and the other is not}3">,
- InGroup<DiagGroup<"pointer-sign">>;
+ InGroup<DiagGroup<"pointer-sign">>, DefaultIgnore;
def err_typecheck_convert_incompatible_pointer_sign :
Error<ext_typecheck_convert_incompatible_pointer_sign.Text>;
def ext_typecheck_convert_incompatible_pointer : ExtWarn<
@@ -9100,15 +9100,22 @@ def warn_cxx17_compat_defaulted_comparison : Warning<
"before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def err_defaulted_comparison_template : Error<
"comparison operator template cannot be defaulted">;
-def err_defaulted_comparison_out_of_class : Error<
- "%sub{select_defaulted_comparison_kind}0 can only be defaulted in a class "
- "definition">;
+def err_defaulted_comparison_num_args : Error<
+ "%select{non-member|member}0 %sub{select_defaulted_comparison_kind}1"
+ " comparison operator must have %select{2|1}0 parameters">;
def err_defaulted_comparison_param : Error<
"invalid parameter type for defaulted %sub{select_defaulted_comparison_kind}0"
"; found %1, expected %2%select{| or %4}3">;
+def err_defaulted_comparison_param_unknown : Error<
+ "invalid parameter type for non-member defaulted"
+ " %sub{select_defaulted_comparison_kind}0"
+ "; found %1, expected class or reference to a constant class">;
def err_defaulted_comparison_param_mismatch : Error<
"parameters for defaulted %sub{select_defaulted_comparison_kind}0 "
"must have the same type%diff{ (found $ vs $)|}1,2">;
+def err_defaulted_comparison_not_friend : Error<
+ "%sub{select_defaulted_comparison_kind}0 is not a friend of"
+ " %select{|incomplete class }1%2">;
def err_defaulted_comparison_non_const : Error<
"defaulted member %sub{select_defaulted_comparison_kind}0 must be "
"const-qualified">;
@@ -9512,6 +9519,9 @@ def err_os_log_argument_too_big : Error<
"os_log() argument %0 is too big (%1 bytes, max %2)">;
def warn_os_log_format_narg : Error<
"os_log() '%%n' format specifier is not allowed">, DefaultError;
+
+def warn_format_narg : Warning<
+ "'%%n' format specifier support is deactivated and will call abort(3)">;
// Statements.
def err_continue_not_in_loop : Error<

View file

@ -0,0 +1,53 @@
- Add ret protector options as no-ops.
- Improve the X86FixupGadgets pass
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
- Alias the command line parameter -p to -pg.
- implement -msave-args in clang/llvm, like the sun did for gcc
Index: tools/clang/include/clang/Driver/Options.td
--- tools/clang/include/clang/Driver/Options.td.orig
+++ tools/clang/include/clang/Driver/Options.td
@@ -2528,6 +2528,16 @@ def ftrivial_auto_var_init : Joined<["-"], "ftrivial-a
def enable_trivial_var_init_zero : Flag<["-"], "enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">,
Flags<[CC1Option, CoreOption]>,
HelpText<"Trivial automatic variable initialization to zero is only here for benchmarks, it'll eventually be removed, and I'm OK with that because I'm only using it to benchmark">;
+def ret_protector : Flag<["-"], "ret-protector">, Flags<[CC1Option]>,
+ HelpText<"Enable Return Protectors">;
+def fno_ret_protector : Flag<["-"], "fno-ret-protector">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Disable return protector">;
+def fret_protector : Flag<["-"], "fret-protector">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Enable return protector">;
+def fno_fixup_gadgets : Flag<["-"], "fno-fixup-gadgets">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Disable FixupGadgets pass (x86 only)">;
+def ffixup_gadgets : Flag<["-"], "ffixup-gadgets">, Group<f_Group>, Flags<[CoreOption]>,
+ HelpText<"Replace ROP friendly instructions with safe alternatives (x86 only)">;
def ftrivial_auto_var_init_stop_after : Joined<["-"], "ftrivial-auto-var-init-stop-after=">, Group<f_Group>,
Flags<[CC1Option, CoreOption]>, HelpText<"Stop initializing trivial automatic stack variables after the specified number of instances">,
MarshallingInfoInt<LangOpts<"TrivialAutoVarInitStopAfter">>;
@@ -3493,6 +3503,8 @@ def mno_check_zero_division : Flag<["-"], "mno-check-z
Group<m_mips_Features_Group>;
def mcompact_branches_EQ : Joined<["-"], "mcompact-branches=">,
Group<m_mips_Features_Group>;
+def mfix_loongson2f_btb : Flag<["-"], "mfix-loongson2f-btb">,
+ Group<m_mips_Features_Group>;
def mbranch_likely : Flag<["-"], "mbranch-likely">, Group<m_Group>,
IgnoredGCCCompat;
def mno_branch_likely : Flag<["-"], "mno-branch-likely">, Group<m_Group>,
@@ -3721,7 +3733,7 @@ defm pthread : BoolOption<"", "pthread",
LangOpts<"POSIXThreads">, DefaultFalse,
PosFlag<SetTrue, [], "Support POSIX threads in generated code">,
NegFlag<SetFalse>, BothFlags<[CC1Option]>>;
-def p : Flag<["-"], "p">;
+def p : Flag<["-"], "p">, Alias<pg>;
def pie : Flag<["-"], "pie">, Group<Link_Group>;
def static_pie : Flag<["-"], "static-pie">, Group<Link_Group>;
def read__only__relocs : Separate<["-"], "read_only_relocs">;
@@ -4252,6 +4264,8 @@ def mshstk : Flag<["-"], "mshstk">, Group<m_x86_Featur
def mno_shstk : Flag<["-"], "mno-shstk">, Group<m_x86_Features_Group>;
def mretpoline_external_thunk : Flag<["-"], "mretpoline-external-thunk">, Group<m_x86_Features_Group>;
def mno_retpoline_external_thunk : Flag<["-"], "mno-retpoline-external-thunk">, Group<m_x86_Features_Group>;
+def msave_args : Flag<["-"], "msave-args">, Group<m_x86_Features_Group>;
+def mno_save_args : Flag<["-"], "mno-save-args">, Group<m_x86_Features_Group>;
def mvzeroupper : Flag<["-"], "mvzeroupper">, Group<m_x86_Features_Group>;
def mno_vzeroupper : Flag<["-"], "mno-vzeroupper">, Group<m_x86_Features_Group>;

View file

@ -0,0 +1,13 @@
Teach Clang about syslog format attribute
Index: tools/clang/include/clang/Sema/Sema.h
--- tools/clang/include/clang/Sema/Sema.h.orig
+++ tools/clang/include/clang/Sema/Sema.h
@@ -12648,6 +12648,7 @@ class Sema final { (public)
FST_FreeBSDKPrintf,
FST_OSTrace,
FST_OSLog,
+ FST_Syslog,
FST_Unknown
};
static FormatStringType GetFormatStringType(const FormatAttr *Format);

View file

@ -0,0 +1,37 @@
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length specifiers
and type check like it is used by the regular case.
Index: tools/clang/lib/AST/FormatString.cpp
--- tools/clang/lib/AST/FormatString.cpp.orig
+++ tools/clang/lib/AST/FormatString.cpp
@@ -759,6 +759,10 @@ bool FormatSpecifier::hasValidLengthModifier(const Tar
case ConversionSpecifier::XArg:
case ConversionSpecifier::nArg:
return true;
+ case ConversionSpecifier::FreeBSDbArg:
+ return Target.getTriple().isOSFreeBSD() ||
+ Target.getTriple().isPS4() ||
+ Target.getTriple().isOSOpenBSD();
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
@@ -794,6 +798,10 @@ bool FormatSpecifier::hasValidLengthModifier(const Tar
case ConversionSpecifier::ScanListArg:
case ConversionSpecifier::ZArg:
return true;
+ case ConversionSpecifier::FreeBSDbArg:
+ return Target.getTriple().isOSFreeBSD() ||
+ Target.getTriple().isPS4() ||
+ Target.getTriple().isOSOpenBSD();
case ConversionSpecifier::FreeBSDrArg:
case ConversionSpecifier::FreeBSDyArg:
return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();
@@ -953,6 +961,7 @@ bool FormatSpecifier::hasStandardLengthConversionCombi
case ConversionSpecifier::uArg:
case ConversionSpecifier::xArg:
case ConversionSpecifier::XArg:
+ case ConversionSpecifier::FreeBSDbArg:
return false;
default:
return true;

View file

@ -0,0 +1,14 @@
- Our malloc(3) guarantees 16-byte alignment.
Index: tools/clang/lib/Basic/TargetInfo.cpp
--- tools/clang/lib/Basic/TargetInfo.cpp.orig
+++ tools/clang/lib/Basic/TargetInfo.cpp
@@ -70,7 +70,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Target
// the alignment is 16 bytes on both 64-bit and 32-bit systems.
if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid())
NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0;
- else if (T.isOSDarwin())
+ else if (T.isOSDarwin() || T.isOSOpenBSD())
NewAlign = 128;
else
NewAlign = 0; // Infer from basic type alignment.

View file

@ -0,0 +1,20 @@
- Implement the 'h' register constraint on mips64. This lets clang build
pieces of software that use the constraint if the compiler claims
to be compatible with GCC 4.2.1.
Note that the constraint was removed in GCC 4.4. The reason was that
'h' could generate code whose result is unpredictable. The underlying
reason is that the HI and LO registers are special, and the optimizer
has to be careful when choosing the order of HI/LO accesses. It looks
that LLVM has the needed logic.
Index: tools/clang/lib/Basic/Targets/Mips.h
--- tools/clang/lib/Basic/Targets/Mips.h.orig
+++ tools/clang/lib/Basic/Targets/Mips.h
@@ -239,6 +239,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public
case 'y': // Equivalent to "r", backward compatibility only.
case 'f': // floating-point registers.
case 'c': // $25 for indirect jumps
+ case 'h': // hi register
case 'l': // lo register
case 'x': // hilo register pair
Info.setAllowsRegister();

View file

@ -0,0 +1,22 @@
implement -msave-args in clang/llvm, like the sun did for gcc
Index: tools/clang/lib/Basic/Targets/X86.cpp
--- tools/clang/lib/Basic/Targets/X86.cpp.orig
+++ tools/clang/lib/Basic/Targets/X86.cpp
@@ -309,6 +309,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<s
HasPTWRITE = true;
} else if (Feature == "+invpcid") {
HasINVPCID = true;
+ } else if (Feature == "+save-args") {
+ HasSaveArgs = true;
} else if (Feature == "+enqcmd") {
HasENQCMD = true;
} else if (Feature == "+hreset") {
@@ -984,6 +986,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) cons
.Case("movbe", HasMOVBE)
.Case("movdiri", HasMOVDIRI)
.Case("movdir64b", HasMOVDIR64B)
+ .Case("save-args", HasSaveArgs)
.Case("mwaitx", HasMWAITX)
.Case("pclmul", HasPCLMUL)
.Case("pconfig", HasPCONFIG)

View file

@ -0,0 +1,13 @@
- implement -msave-args in clang/llvm, like the sun did for gcc.
Index: tools/clang/lib/Basic/Targets/X86.h
--- tools/clang/lib/Basic/Targets/X86.h.orig
+++ tools/clang/lib/Basic/Targets/X86.h
@@ -131,6 +131,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public T
bool HasMOVDIR64B = false;
bool HasPTWRITE = false;
bool HasINVPCID = false;
+ bool HasSaveArgs = false;
bool HasENQCMD = false;
bool HasKL = false; // For key locker
bool HasWIDEKL = false; // For wide key locker

View file

@ -0,0 +1,31 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: tools/clang/lib/CodeGen/CGCall.cpp
--- tools/clang/lib/CodeGen/CGCall.cpp.orig
+++ tools/clang/lib/CodeGen/CGCall.cpp
@@ -2215,6 +2215,9 @@ void CodeGenModule::ConstructAttributeList(StringRef N
// CPU/feature overrides. addDefaultFunctionDefinitionAttributes
// handles these separately to set them based on the global defaults.
GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs);
+
+ if (CodeGenOpts.ReturnProtector)
+ FuncAttrs.addAttribute("ret-protector");
}
// Collect attributes from arguments and return values.

View file

@ -0,0 +1,14 @@
- Downgrade riscv64-specific LTO error to a warning
Index: tools/clang/lib/CodeGen/CodeGenModule.cpp
--- tools/clang/lib/CodeGen/CodeGenModule.cpp.orig
+++ tools/clang/lib/CodeGen/CodeGenModule.cpp
@@ -846,7 +846,7 @@ void CodeGenModule::EmitBackendOptionsMetadata(
break;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
- getModule().addModuleFlag(llvm::Module::Error, "SmallDataLimit",
+ getModule().addModuleFlag(llvm::Module::Warning, "SmallDataLimit",
CodeGenOpts.SmallDataLimit);
break;
}

View file

@ -0,0 +1,74 @@
- Report versioned lib.so in cc --print-file-name given short name
Index: tools/clang/lib/Driver/Driver.cpp
--- tools/clang/lib/Driver/Driver.cpp.orig
+++ tools/clang/lib/Driver/Driver.cpp
@@ -5089,7 +5089,50 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
}
}
+
+namespace {
+static Optional<std::string> findFile(StringRef path1, const Twine &path2) {
+ SmallString<128> s;
+ llvm::sys::path::append(s, path1, path2);
+
+ if (llvm::sys::fs::exists(s))
+ return std::string(s);
+ return None;
+}
+
+// Must be in sync with findMajMinShlib in lld/ELF/DriverUtils.cpp.
+llvm::Optional<std::string> findMajMinShlib(StringRef dir, const Twine& libNameSo) {
+ // Handle OpenBSD-style maj/min shlib scheme
+ llvm::SmallString<128> Scratch;
+ const StringRef LibName = (libNameSo + ".").toStringRef(Scratch);
+ int MaxMaj = -1, MaxMin = -1;
+ std::error_code EC;
+ for (llvm::sys::fs::directory_iterator LI(dir, EC), LE;
+ LI != LE; LI = LI.increment(EC)) {
+ StringRef FilePath = LI->path();
+ StringRef FileName = llvm::sys::path::filename(FilePath);
+ if (!(FileName.startswith(LibName)))
+ continue;
+ std::pair<StringRef, StringRef> MajMin =
+ FileName.substr(LibName.size()).split('.');
+ int Maj, Min;
+ if (MajMin.first.getAsInteger(10, Maj) || Maj < 0)
+ continue;
+ if (MajMin.second.getAsInteger(10, Min) || Min < 0)
+ continue;
+ if (Maj > MaxMaj)
+ MaxMaj = Maj, MaxMin = Min;
+ if (MaxMaj == Maj && Min > MaxMin)
+ MaxMin = Min;
+ }
+ if (MaxMaj >= 0)
+ return findFile(dir, LibName + Twine(MaxMaj) + "." + Twine(MaxMin));
+ return None;
+}
+} // namespace
+
std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
+ const bool lookForLibDotSo = Name.startswith("lib") && Name.endswith(".so");
// Search for Name in a list of paths.
auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P)
-> llvm::Optional<std::string> {
@@ -5099,9 +5142,14 @@ std::string Driver::GetFilePath(StringRef Name, const
if (Dir.empty())
continue;
SmallString<128> P(Dir[0] == '=' ? SysRoot + Dir.substr(1) : Dir);
- llvm::sys::path::append(P, Name);
- if (llvm::sys::fs::exists(Twine(P)))
- return std::string(P);
+ if (!lookForLibDotSo) {
+ llvm::sys::path::append(P, Name);
+ if (llvm::sys::fs::exists(Twine(P)))
+ return std::string(P);
+ } else {
+ if (auto s = findMajMinShlib(P, Name))
+ return std::string(*s);
+ }
}
return None;
};

View file

@ -0,0 +1,25 @@
- ld.lld doesn't properly support R_RISCV_RELAX relocations, switch the default to -no-relax
Index: tools/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
--- tools/clang/lib/Driver/ToolChains/Arch/RISCV.cpp.orig
+++ tools/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -556,11 +556,19 @@ void riscv::getRISCVTargetFeatures(const Driver &D, co
if (Args.hasArg(options::OPT_ffixed_x31))
Features.push_back("+reserve-x31");
+#ifdef __OpenBSD__
+ // -mno-relax is default, unless -mrelax is specified.
+ if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false))
+ Features.push_back("+relax");
+ else
+ Features.push_back("-relax");
+#else
// -mrelax is default, unless -mno-relax is specified.
if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
Features.push_back("+relax");
else
Features.push_back("-relax");
+#endif
// GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
// specified.

View file

@ -0,0 +1,18 @@
- Turn on -mretpoline by default in clang on amd64.
Index: tools/clang/lib/Driver/ToolChains/Arch/X86.cpp
--- tools/clang/lib/Driver/ToolChains/Arch/X86.cpp.orig
+++ tools/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -149,6 +149,12 @@ void x86::getX86TargetFeatures(const Driver &D, const
// consider deprecating this and instead warn if the user requests external
// retpoline thunks and *doesn't* request some form of retpolines.
auto SpectreOpt = clang::driver::options::ID::OPT_INVALID;
+ if (Triple.isOSOpenBSD() && Triple.getArch() == llvm::Triple::x86_64 &&
+ Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline, true)) {
+ Features.push_back("+retpoline-indirect-calls");
+ Features.push_back("+retpoline-indirect-branches");
+ SpectreOpt = options::OPT_mretpoline;
+ } else
if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline,
options::OPT_mspeculative_load_hardening,
options::OPT_mno_speculative_load_hardening)) {

View file

@ -0,0 +1,188 @@
- Switch Powerpc64 Big Endian to ELFv2 on OpenBSD.
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
- Disable -fstrict-aliasing per default on OpenBSD.
- Enable -fwrapv by default
- Add ret protector options as no-ops.
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Add retguard for arm64.
- Add retguard for octeon/mips64.
- Add RETGUARD implementation for powerpc and powerpc64.
- Improve the X86FixupGadgets pass
- On OpenBSD disable the malloc/calloc/realloc/free/str*dup builtins, since
they can perform strange transforms and optimizations. Some of those could
gain a slight advantage, but would avoid the variety of important runtime
checks our malloc(3) code does. In essence, the transforms performed are
considered "anti-mitigation".
- Make -mbranch-protection=bti the default on OpenBSD.
- On openbsd amd64, emit IBT endbr64 instructions by default (meaning,
-fcf-protection=branch is the default).
- On openbsd amd64, the compiler has been found to generate some nasty jump
table variations (calculate address into %rax, jmp %rax) which is not
compatible with IBT endbr64. So we will have to disable jump tables by
default.
- Turn on pointer-authentication on arm64 as well by default. This means
we effectively enable -mbranch-protection=standard on arm64 now.
- Make sure -msign-return-address doesn't disable BTI support.
Index: tools/clang/lib/Driver/ToolChains/Clang.cpp
--- tools/clang/lib/Driver/ToolChains/Clang.cpp.orig
+++ tools/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1800,7 +1800,10 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
D.Diag(diag::err_invalid_branch_protection)
<< Scope << A->getAsString(Args);
Key = "a_key";
- IndirectBranches = false;
+ if (Triple.isOSOpenBSD())
+ IndirectBranches = true;
+ else
+ IndirectBranches = false;
} else {
StringRef Err;
llvm::AArch64::ParsedBranchProtection PBP;
@@ -1818,6 +1821,12 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
+ } else {
+ if (Triple.isOSOpenBSD()) {
+ CmdArgs.push_back("-msign-return-address=non-leaf");
+ CmdArgs.push_back("-msign-return-address-key=a_key");
+ CmdArgs.push_back("-mbranch-target-enforce");
+ }
}
// Handle -msve_vector_bits=<bits>
@@ -2489,6 +2498,11 @@ static void CollectArgsForIntegratedAssembler(Compilat
CmdArgs.push_back("-soft-float");
continue;
}
+ if (Value.startswith("-mfix-loongson2f-btb")) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-fix-loongson2f-btb");
+ continue;
+ }
MipsTargetFeature = llvm::StringSwitch<const char *>(Value)
.Case("-mips1", "+mips1")
@@ -4943,9 +4957,12 @@ void Clang::ConstructJob(Compilation &C, const JobActi
OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing;
// We turn strict aliasing off by default if we're in CL mode, since MSVC
// doesn't do any TBAA.
- bool TBAAOnByDefault = !D.IsCLMode();
+ bool StrictAliasingDefault = !D.IsCLMode();
+ // We also turn off strict aliasing on OpenBSD.
+ if (getToolChain().getTriple().isOSOpenBSD())
+ StrictAliasingDefault = false;
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
- options::OPT_fno_strict_aliasing, TBAAOnByDefault))
+ options::OPT_fno_strict_aliasing, StrictAliasingDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
options::OPT_fno_struct_path_tbaa))
@@ -5868,7 +5885,8 @@ void Clang::ConstructJob(Compilation &C, const JobActi
options::OPT_fno_strict_overflow)) {
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
- }
+ } else if (getToolChain().getTriple().isOSOpenBSD())
+ CmdArgs.push_back("-fwrapv");
if (Arg *A = Args.getLastArg(options::OPT_freroll_loops,
options::OPT_fno_reroll_loops))
@@ -5888,7 +5906,48 @@ void Clang::ConstructJob(Compilation &C, const JobActi
options::OPT_mno_speculative_load_hardening, false))
CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
- RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
+ // -ret-protector
+ unsigned RetProtector = 1;
+ if (Arg *A = Args.getLastArg(options::OPT_fno_ret_protector,
+ options::OPT_fret_protector)) {
+ if (A->getOption().matches(options::OPT_fno_ret_protector))
+ RetProtector = 0;
+ else if (A->getOption().matches(options::OPT_fret_protector))
+ RetProtector = 1;
+ }
+
+ if (RetProtector &&
+ ((getToolChain().getArch() == llvm::Triple::x86_64) ||
+ (getToolChain().getArch() == llvm::Triple::mips64) ||
+ (getToolChain().getArch() == llvm::Triple::mips64el) ||
+ (getToolChain().getArch() == llvm::Triple::ppc) ||
+ (getToolChain().getArch() == llvm::Triple::ppc64) ||
+ (getToolChain().getArch() == llvm::Triple::ppc64le) ||
+ (getToolChain().getArch() == llvm::Triple::aarch64)) &&
+ !Args.hasArg(options::OPT_fno_stack_protector) &&
+ !Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back(Args.MakeArgString("-D_RET_PROTECTOR"));
+ CmdArgs.push_back(Args.MakeArgString("-ret-protector"));
+ // Consume the stack protector arguments to prevent warning
+ Args.getLastArg(options::OPT_fstack_protector_all,
+ options::OPT_fstack_protector_strong,
+ options::OPT_fstack_protector,
+ options::OPT__param); // ssp-buffer-size
+ } else {
+ // If we're not using retguard, then do the usual stack protector
+ RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
+ }
+
+ // -fixup-gadgets
+ if (Arg *A = Args.getLastArg(options::OPT_fno_fixup_gadgets,
+ options::OPT_ffixup_gadgets)) {
+ CmdArgs.push_back(Args.MakeArgString(Twine("-mllvm")));
+ if (A->getOption().matches(options::OPT_fno_fixup_gadgets))
+ CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=false")));
+ else if (A->getOption().matches(options::OPT_ffixup_gadgets))
+ CmdArgs.push_back(Args.MakeArgString(Twine("-x86-fixup-gadgets=true")));
+ }
+
RenderSCPOptions(TC, Args, CmdArgs);
RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs);
@@ -5961,6 +6020,11 @@ void Clang::ConstructJob(Compilation &C, const JobActi
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
+ } else if (Triple.isOSOpenBSD() && Triple.getArch() == llvm::Triple::x86_64) {
+ // Emit IBT endbr64 instructions by default
+ CmdArgs.push_back("-fcf-protection=branch");
+ // jump-table can generate indirect jumps, which are not permitted
+ CmdArgs.push_back("-fno-jump-tables");
}
// Forward -f options with positive and negative forms; we translate these by
@@ -6445,6 +6509,18 @@ void Clang::ConstructJob(Compilation &C, const JobActi
options::OPT_fno_rewrite_imports, false);
if (RewriteImports)
CmdArgs.push_back("-frewrite-imports");
+
+ // Disable some builtins on OpenBSD because they are just not
+ // right...
+ if (getToolChain().getTriple().isOSOpenBSD()) {
+ CmdArgs.push_back("-fno-builtin-malloc");
+ CmdArgs.push_back("-fno-builtin-calloc");
+ CmdArgs.push_back("-fno-builtin-realloc");
+ CmdArgs.push_back("-fno-builtin-valloc");
+ CmdArgs.push_back("-fno-builtin-free");
+ CmdArgs.push_back("-fno-builtin-strdup");
+ CmdArgs.push_back("-fno-builtin-strndup");
+ }
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.

View file

@ -0,0 +1,14 @@
- Disable IAS for OpenBSD SPARC.
Index: tools/clang/lib/Driver/ToolChains/Gnu.cpp
--- tools/clang/lib/Driver/ToolChains/Gnu.cpp.orig
+++ tools/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2763,7 +2763,7 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
- if (getTriple().isOSFreeBSD() || getTriple().isOSOpenBSD() ||
+ if (getTriple().isOSFreeBSD() ||
getTriple().isOSSolaris())
return true;
return false;

View file

@ -0,0 +1,156 @@
- Add support for building against libestdc++ from ports-gcc.
- Allow the compiler driver to link the libclang_rt.profile library.
- Use Component in OpenBSD::getCompilerRT to find libraries.
- Enable kernel-address sanitizer for clang openbsd target
Index: tools/clang/lib/Driver/ToolChains/OpenBSD.cpp
--- tools/clang/lib/Driver/ToolChains/OpenBSD.cpp.orig
+++ tools/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -12,10 +12,13 @@
#include "CommonArgs.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -197,7 +200,13 @@ void openbsd::Linker::ConstructJob(Compilation &C, con
}
// FIXME: For some reason GCC passes -lgcc before adding
// the default system libraries. Just mimic this for now.
- CmdArgs.push_back("-lcompiler_rt");
+ if (ToolChain.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+ CmdArgs.push_back("-lcompiler_rt");
+ else {
+ CmdArgs.push_back("-L${LOCALBASE}/lib/gcc/${GCC_CONFIG}/${GCC_VER}");
+ CmdArgs.push_back("-L${LOCALBASE}/lib"); // XXX nasty
+ CmdArgs.push_back("-lgcc");
+ }
if (Args.hasArg(options::OPT_pthread)) {
if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg))
@@ -213,7 +222,10 @@ void openbsd::Linker::ConstructJob(Compilation &C, con
CmdArgs.push_back("-lc");
}
- CmdArgs.push_back("-lcompiler_rt");
+ if (ToolChain.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
+ CmdArgs.push_back("-lcompiler_rt");
+ else
+ CmdArgs.push_back("-lgcc");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
@@ -247,6 +259,10 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const
Res |= SanitizerKind::FuzzerNoLink;
}
+ if (IsX86_64) {
+ Res |= SanitizerKind::KernelAddress;
+ }
+
return Res;
}
@@ -301,17 +317,34 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
bool Profiling = Args.hasArg(options::OPT_pg);
- CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
- CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
- CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
+ switch (GetCXXStdlibType(Args)) {
+ case ToolChain::CST_Libcxx:
+ CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
+ CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
+ CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ CmdArgs.push_back("-lestdc++");
+ break;
+ }
}
std::string OpenBSD::getCompilerRT(const ArgList &Args,
StringRef Component,
FileType Type) const {
- SmallString<128> Path(getDriver().SysRoot);
- llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
- return std::string(Path.str());
+ if (Component == "builtins") {
+ SmallString<128> Path(getDriver().SysRoot);
+ llvm::sys::path::append(Path, "/usr/lib/libcompiler_rt.a");
+ return std::string(Path.str());
+ } else {
+ SmallString<128> P(getDriver().ResourceDir);
+ std::string CRTBasename =
+ buildCompilerRTBasename(Args, Component, Type, /*AddArch=*/false);
+ llvm::sys::path::append(P, "lib", CRTBasename);
+ if (getVFS().exists(P))
+ return std::string(P.str());
+ return ToolChain::getCompilerRT(Args, Component, Type);
+ }
}
Tool *OpenBSD::buildAssembler() const {
@@ -321,3 +354,54 @@ Tool *OpenBSD::buildAssembler() const {
Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
bool OpenBSD::HasNativeLLVMSupport() const { return true; }
+
+ToolChain::CXXStdlibType OpenBSD::GetCXXStdlibType(const ArgList &Args) const {
+ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) {
+ StringRef Value = A->getValue();
+ if (Value == "libstdc++")
+ return ToolChain::CST_Libstdcxx;
+ if (Value == "libc++")
+ return ToolChain::CST_Libcxx;
+
+ getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
+ }
+ switch (getTriple().getArch()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::riscv64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return ToolChain::CST_Libcxx;
+ break;
+ default:
+ return ToolChain::CST_Libstdcxx;
+ break;
+ }
+}
+
+void OpenBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ switch (GetCXXStdlibType(DriverArgs)) {
+ case ToolChain::CST_Libcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "/usr/include/c++/v1");
+ break;
+ case ToolChain::CST_Libstdcxx:
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "${LOCALBASE}/include/c++/${GCC_VER}");
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "${LOCALBASE}/include/c++/${GCC_VER}/${GCC_CONFIG}");
+ addSystemInclude(DriverArgs, CC1Args,
+ getDriver().SysRoot + "${LOCALBASE}/include/c++/${GCC_VER}/backward");
+ break;
+ }
+}

View file

@ -0,0 +1,30 @@
- Add support for building against libestdc++ from ports-gcc.
- Enable unwind tables on all clang architectures.
- Arm is not ready for unwinding yet. Disable unwind info generation for now.
Index: tools/clang/lib/Driver/ToolChains/OpenBSD.h
--- tools/clang/lib/Driver/ToolChains/OpenBSD.h.orig
+++ tools/clang/lib/Driver/ToolChains/OpenBSD.h
@@ -77,8 +77,22 @@ class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
+ void AddClangCXXStdlibIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+
std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
FileType Type = ToolChain::FT_Static) const override;
+
+ bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
+ switch (getArch()) {
+ case llvm::Triple::arm:
+ return false;
+ default:
+ return true;
+ }
+ }
LangOptions::StackProtectorMode
GetDefaultStackProtectorLevel(bool KernelOrKext) const override {

View file

@ -0,0 +1,41 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: tools/clang/lib/Frontend/CompilerInvocation.cpp
--- tools/clang/lib/Frontend/CompilerInvocation.cpp.orig
+++ tools/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1470,6 +1470,10 @@ void CompilerInvocation::GenerateCodeGenArgs(
F.Filename, SA);
}
+ if (Opts.ReturnProtector) {
+ GenerateArg(Args, OPT_ret_protector, SA);
+ }
+
// TODO: Consider removing marshalling annotations from f[no_]emulated_tls.
// That would make it easy to generate the option only **once** if it was
// explicitly set to non-default value.
@@ -1805,6 +1809,8 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptio
}
Opts.LinkBitcodeFiles.push_back(F);
}
+
+ Opts.ReturnProtector = Args.hasArg(OPT_ret_protector);
if (Args.getLastArg(OPT_femulated_tls) ||
Args.getLastArg(OPT_fno_emulated_tls)) {

View file

@ -0,0 +1,108 @@
- Teach Clang about syslog format attribute
- Enable the kprintf format attribute
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length
specifiers and type check like it is used by the regular case.
- Add a new warning for %n format specifier usage in printf(3) family functions
Index: tools/clang/lib/Sema/SemaChecking.cpp
--- tools/clang/lib/Sema/SemaChecking.cpp.orig
+++ tools/clang/lib/Sema/SemaChecking.cpp
@@ -7847,7 +7847,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)
- .Cases("printf", "printf0", FST_Printf)
+ .Cases("printf", "printf0", "syslog", FST_Printf)
.Cases("NSString", "CFString", FST_NSString)
.Case("strftime", FST_Strftime)
.Case("strfmon", FST_Strfmon)
@@ -7944,6 +7944,7 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *>
case FST_Kprintf:
case FST_FreeBSDKPrintf:
case FST_Printf:
+ case FST_Syslog:
Diag(FormatLoc, diag::note_format_security_fixit)
<< FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
break;
@@ -8769,19 +8770,34 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyz
// Claim the second argument.
CoveredArgs.set(argIndex + 1);
- // Type check the first argument (int for %b, pointer for %D)
const Expr *Ex = getDataArg(argIndex);
- const analyze_printf::ArgType &AT =
- (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ?
- ArgType(S.Context.IntTy) : ArgType::CPointerTy;
- if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
- EmitFormatDiagnostic(
+ if (CS.getKind() == ConversionSpecifier::FreeBSDDArg) {
+ // Type check the first argument (pointer for %D)
+ const analyze_printf::ArgType &AT = ArgType::CPointerTy;
+ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
+ EmitFormatDiagnostic(
S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
- << false << Ex->getSourceRange(),
- Ex->getBeginLoc(), /*IsStringLocation*/ false,
+ << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
+ << false << Ex->getSourceRange(),
+ Ex->getBeginLoc(), /*IsStringLocation*/false,
getSpecifierRange(startSpecifier, specifierLen));
+ } else {
+ // Check the length modifier for %b
+ if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+ S.getLangOpts()))
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_nonsensical_length);
+ else if (!FS.hasStandardLengthModifier())
+ HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+ else if (!FS.hasStandardLengthConversionCombination())
+ HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+ diag::warn_format_non_standard_conversion_spec);
+ // Type check the first argument of %b
+ if (!checkFormatExpr(FS, startSpecifier, specifierLen, Ex))
+ return false;
+ }
+
// Type check the second argument (char * for both %b and %D)
Ex = getDataArg(argIndex + 1);
const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
@@ -8819,6 +8835,15 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyz
return true;
}
+ // %n is not allowed anywhere
+ if (CS.getKind() == ConversionSpecifier::nArg) {
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_narg),
+ getLocationOfByte(CS.getStart()),
+ /*IsStringLocation*/ false,
+ getSpecifierRange(startSpecifier, specifierLen));
+ return true;
+ }
+
// Only scalars are allowed for os_trace.
if (FSType == Sema::FST_OSTrace &&
(CS.getKind() == ConversionSpecifier::PArg ||
@@ -9565,8 +9590,9 @@ static void CheckFormatString(Sema &S, const FormatStr
}
if (Type == Sema::FST_Printf || Type == Sema::FST_NSString ||
- Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog ||
- Type == Sema::FST_OSTrace) {
+ Type == Sema::FST_Kprintf || Type == Sema::FST_FreeBSDKPrintf ||
+ Type == Sema::FST_OSLog || Type == Sema::FST_OSTrace ||
+ Type == Sema::FST_Syslog) {
CheckPrintfHandler H(
S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs,
(Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str,
@@ -9576,7 +9602,7 @@ static void CheckFormatString(Sema &S, const FormatStr
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
S.getLangOpts(),
S.Context.getTargetInfo(),
- Type == Sema::FST_FreeBSDKPrintf))
+ Type == Sema::FST_Kprintf || Type == Sema::FST_FreeBSDKPrintf))
H.DoneProcessing();
} else if (Type == Sema::FST_Scanf) {
CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,

View file

@ -0,0 +1,13 @@
Teach Clang about syslog format attribute
Index: tools/clang/lib/Sema/SemaDeclAttr.cpp
--- tools/clang/lib/Sema/SemaDeclAttr.cpp.orig
+++ tools/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3411,6 +3411,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Form
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
.Case("os_trace", SupportedFormat)
.Case("os_log", SupportedFormat)
+ .Case("syslog", SupportedFormat)
.Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
.Default(InvalidFormat);

View file

@ -0,0 +1,266 @@
- allow out-of-class defaulting of comparison operators
this is backport of the following upstream commit:
commit 5fbe21a7748f91adbd1b16c95bbfe180642320a3
Index: tools/clang/lib/Sema/SemaDeclCXX.cpp
--- tools/clang/lib/Sema/SemaDeclCXX.cpp.orig
+++ tools/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8371,9 +8371,6 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S
DefaultedComparisonKind DCK) {
assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison");
- CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
- assert(RD && "defaulted comparison is not defaulted in a class");
-
// Perform any unqualified lookups we're going to need to default this
// function.
if (S) {
@@ -8391,43 +8388,17 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S
// const C&, or
// -- a friend of C having two parameters of type const C& or two
// parameters of type C.
- QualType ExpectedParmType1 = Context.getRecordType(RD);
- QualType ExpectedParmType2 =
- Context.getLValueReferenceType(ExpectedParmType1.withConst());
- if (isa<CXXMethodDecl>(FD))
- ExpectedParmType1 = ExpectedParmType2;
- for (const ParmVarDecl *Param : FD->parameters()) {
- if (!Param->getType()->isDependentType() &&
- !Context.hasSameType(Param->getType(), ExpectedParmType1) &&
- !Context.hasSameType(Param->getType(), ExpectedParmType2)) {
- // Don't diagnose an implicit 'operator=='; we will have diagnosed the
- // corresponding defaulted 'operator<=>' already.
- if (!FD->isImplicit()) {
- Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
- << (int)DCK << Param->getType() << ExpectedParmType1
- << !isa<CXXMethodDecl>(FD)
- << ExpectedParmType2 << Param->getSourceRange();
- }
- return true;
- }
- }
- if (FD->getNumParams() == 2 &&
- !Context.hasSameType(FD->getParamDecl(0)->getType(),
- FD->getParamDecl(1)->getType())) {
- if (!FD->isImplicit()) {
- Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch)
- << (int)DCK
- << FD->getParamDecl(0)->getType()
- << FD->getParamDecl(0)->getSourceRange()
- << FD->getParamDecl(1)->getType()
- << FD->getParamDecl(1)->getSourceRange();
- }
- return true;
- }
- // ... non-static const member ...
- if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
+ bool IsMethod = isa<CXXMethodDecl>(FD);
+ if (IsMethod) {
+ auto *MD = cast<CXXMethodDecl>(FD);
assert(!MD->isStatic() && "comparison function cannot be a static member");
+
+ // If we're out-of-class, this is the class we're comparing.
+ if (!RD)
+ RD = MD->getParent();
+
if (!MD->isConst()) {
SourceLocation InsertLoc;
if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
@@ -8436,7 +8407,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S
// corresponding defaulted 'operator<=>' already.
if (!MD->isImplicit()) {
Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const)
- << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
+ << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
}
// Add the 'const' to the type to recover.
@@ -8446,9 +8417,100 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S
MD->setType(Context.getFunctionType(FPT->getReturnType(),
FPT->getParamTypes(), EPI));
}
- } else {
- // A non-member function declared in a class must be a friend.
+ }
+
+ if (FD->getNumParams() != (IsMethod ? 1 : 2)) {
+ // Let's not worry about using a variadic template pack here -- who would do
+ // such a thing?
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_num_args)
+ << int(IsMethod) << int(DCK);
+ return true;
+ }
+
+ const ParmVarDecl *KnownParm = nullptr;
+ for (const ParmVarDecl *Param : FD->parameters()) {
+ QualType ParmTy = Param->getType();
+ if (ParmTy->isDependentType())
+ continue;
+ if (!KnownParm) {
+ auto CTy = ParmTy;
+ // Is it `T const &`?
+ bool Ok = !IsMethod;
+ QualType ExpectedTy;
+ if (RD)
+ ExpectedTy = Context.getRecordType(RD);
+ if (auto *Ref = CTy->getAs<ReferenceType>()) {
+ CTy = Ref->getPointeeType();
+ if (RD)
+ ExpectedTy.addConst();
+ Ok = true;
+ }
+
+ // Is T a class?
+ if (!Ok) {
+ } else if (RD) {
+ if (!RD->isDependentType() && !Context.hasSameType(CTy, ExpectedTy))
+ Ok = false;
+ } else if (auto *CRD = CTy->getAsRecordDecl()) {
+ RD = cast<CXXRecordDecl>(CRD);
+ } else {
+ Ok = false;
+ }
+
+ if (Ok) {
+ KnownParm = Param;
+ } else {
+ // Don't diagnose an implicit 'operator=='; we will have diagnosed the
+ // corresponding defaulted 'operator<=>' already.
+ if (!FD->isImplicit()) {
+ if (RD) {
+ QualType PlainTy = Context.getRecordType(RD);
+ QualType RefTy =
+ Context.getLValueReferenceType(PlainTy.withConst());
+ if (IsMethod)
+ PlainTy = QualType();
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
+ << int(DCK) << ParmTy << RefTy << int(!IsMethod) << PlainTy
+ << Param->getSourceRange();
+ } else {
+ assert(!IsMethod && "should know expected type for method");
+ Diag(FD->getLocation(),
+ diag::err_defaulted_comparison_param_unknown)
+ << int(DCK) << ParmTy << Param->getSourceRange();
+ }
+ }
+ return true;
+ }
+ } else if (!Context.hasSameType(KnownParm->getType(), ParmTy)) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch)
+ << int(DCK) << KnownParm->getType() << KnownParm->getSourceRange()
+ << ParmTy << Param->getSourceRange();
+ return true;
+ }
+ }
+
+ assert(RD && "must have determined class");
+ if (IsMethod) {
+ } else if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ // In-class, must be a friend decl.
assert(FD->getFriendObjectKind() && "expected a friend declaration");
+ } else {
+ // Out of class, require the defaulted comparison to be a friend (of a
+ // complete type).
+ if (RequireCompleteType(FD->getLocation(), Context.getRecordType(RD),
+ diag::err_defaulted_comparison_not_friend, int(DCK),
+ int(1)))
+ return true;
+
+ if (llvm::find_if(RD->friends(), [&](const FriendDecl *F) {
+ return FD->getCanonicalDecl() ==
+ F->getFriendDecl()->getCanonicalDecl();
+ }) == RD->friends().end()) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_not_friend)
+ << int(DCK) << int(0) << RD;
+ Diag(RD->getCanonicalDecl()->getLocation(), diag::note_declared_at);
+ return true;
+ }
}
// C++2a [class.eq]p1, [class.rel]p1:
@@ -8606,7 +8668,10 @@ void Sema::DefineDefaultedComparison(SourceLocation Us
{
// Build and set up the function body.
- CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
+ // The first parameter has type maybe-ref-to maybe-const T, use that to get
+ // the type of the class being compared.
+ auto PT = FD->getParamDecl(0)->getType();
+ CXXRecordDecl *RD = PT.getNonReferenceType()->getAsCXXRecordDecl();
SourceLocation BodyLoc =
FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
StmtResult Body =
@@ -17088,13 +17153,6 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation
return;
}
- if (DefKind.isComparison() &&
- !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
- Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class)
- << (int)DefKind.asComparison();
- return;
- }
-
// Issue compatibility warning. We already warned if the operator is
// 'operator<=>' when parsing the '<=>' token.
if (DefKind.isComparison() &&
@@ -17116,31 +17174,37 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation
// that we've marked it as defaulted.
FD->setWillHaveBody(false);
- // If this definition appears within the record, do the checking when
- // the record is complete. This is always the case for a defaulted
- // comparison.
- if (DefKind.isComparison())
+ // If this is a comparison's defaulted definition within the record, do
+ // the checking when the record is complete.
+ if (DefKind.isComparison() && isa<CXXRecordDecl>(FD->getLexicalDeclContext()))
return;
- auto *MD = cast<CXXMethodDecl>(FD);
- const FunctionDecl *Primary = FD;
- if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
- // Ask the template instantiation pattern that actually had the
- // '= default' on it.
- Primary = Pattern;
-
- // If the method was defaulted on its first declaration, we will have
+ // If this member fn was defaulted on its first declaration, we will have
// already performed the checking in CheckCompletedCXXClass. Such a
// declaration doesn't trigger an implicit definition.
- if (Primary->getCanonicalDecl()->isDefaulted())
- return;
+ if (isa<CXXMethodDecl>(FD)) {
+ const FunctionDecl *Primary = FD;
+ if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+ // Ask the template instantiation pattern that actually had the
+ // '= default' on it.
+ Primary = Pattern;
+ if (Primary->getCanonicalDecl()->isDefaulted())
+ return;
+ }
- // FIXME: Once we support defining comparisons out of class, check for a
- // defaulted comparison here.
- if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
- MD->setInvalidDecl();
- else
- DefineDefaultedFunction(*this, MD, DefaultLoc);
+ if (DefKind.isComparison()) {
+ if (CheckExplicitlyDefaultedComparison(nullptr, FD, DefKind.asComparison()))
+ FD->setInvalidDecl();
+ else
+ DefineDefaultedComparison(DefaultLoc, FD, DefKind.asComparison());
+ } else {
+ auto *MD = cast<CXXMethodDecl>(FD);
+
+ if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
+ MD->setInvalidDecl();
+ else
+ DefineDefaultedFunction(*this, MD, DefaultLoc);
+ }
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {

View file

@ -0,0 +1,13 @@
-Bsymbolic-functions is not supported by our ld.bfd version.
Index: tools/clang/tools/clang-shlib/CMakeLists.txt
--- tools/clang/tools/clang-shlib/CMakeLists.txt.orig
+++ tools/clang/tools/clang-shlib/CMakeLists.txt
@@ -50,6 +50,6 @@ add_clang_library(clang-cpp
${_DEPS})
# Optimize function calls for default visibility definitions to avoid PLT and
# reduce dynamic relocations.
-if (NOT APPLE AND NOT MINGW)
+if (NOT APPLE AND NOT MINGW AND ${OPENBSD_LD_IS_LLD})
target_link_options(clang-cpp PRIVATE LINKER:-Bsymbolic-functions)
endif()

View file

@ -0,0 +1,16 @@
Our default compilers are cc/c++.
Index: tools/clang/tools/scan-build/libexec/ccc-analyzer
--- tools/clang/tools/scan-build/libexec/ccc-analyzer.orig
+++ tools/clang/tools/scan-build/libexec/ccc-analyzer
@@ -84,8 +84,8 @@ if (`uname -a` =~ m/Darwin/) {
$DefaultCCompiler = 'cc';
$DefaultCXXCompiler = 'c++';
} else {
- $DefaultCCompiler = 'gcc';
- $DefaultCXXCompiler = 'g++';
+ $DefaultCCompiler = 'cc';
+ $DefaultCXXCompiler = 'c++';
}
if ($FindBin::Script =~ /c\+\+-analyzer/) {

View file

@ -0,0 +1,14 @@
Don't build MachO2 support in lld. This code reaches into libunwind
internals.
Index: tools/lld/CMakeLists.txt
--- tools/lld/CMakeLists.txt.orig
+++ tools/lld/CMakeLists.txt
@@ -206,7 +206,6 @@ endif()
add_subdirectory(docs)
add_subdirectory(COFF)
add_subdirectory(ELF)
-add_subdirectory(MachO)
add_subdirectory(MinGW)
add_subdirectory(wasm)

View file

@ -0,0 +1,36 @@
- Enable BTI PLT entries by default.
Index: tools/lld/ELF/Arch/AArch64.cpp
--- tools/lld/ELF/Arch/AArch64.cpp.orig
+++ tools/lld/ELF/Arch/AArch64.cpp
@@ -621,7 +621,11 @@ class AArch64BtiPac final : public AArch64 { (private)
} // namespace
AArch64BtiPac::AArch64BtiPac() {
+#ifdef __OpenBSD__
+ btiHeader = true;
+#else
btiHeader = (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
+#endif
// A BTI (Branch Target Indicator) Plt Entry is only required if the
// address of the PLT entry can be taken by the program, which permits an
// indirect jump to the PLT entry. This can happen when the address
@@ -717,6 +721,10 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbo
}
static TargetInfo *getTargetInfo() {
+#ifdef __OpenBSD__
+ static AArch64BtiPac t;
+ return &t;
+#else
if (config->andFeatures & (GNU_PROPERTY_AARCH64_FEATURE_1_BTI |
GNU_PROPERTY_AARCH64_FEATURE_1_PAC)) {
static AArch64BtiPac t;
@@ -724,6 +732,7 @@ static TargetInfo *getTargetInfo() {
}
static AArch64 t;
return &t;
+#endif
}
TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }

View file

@ -0,0 +1,59 @@
- Change the emitted .glink stub on powerpc64 to use an instruction sequence
to compose the offset to the PLT instead of having a constant pool in .text.
Make --execute-only work on powerpc64.
Index: tools/lld/ELF/Arch/PPC64.cpp
--- tools/lld/ELF/Arch/PPC64.cpp.orig
+++ tools/lld/ELF/Arch/PPC64.cpp
@@ -573,7 +573,11 @@ PPC64::PPC64() {
relativeRel = R_PPC64_RELATIVE;
iRelativeRel = R_PPC64_IRELATIVE;
symbolicRel = R_PPC64_ADDR64;
+#ifdef __OpenBSD__
+ pltHeaderSize = 52;
+#else
pltHeaderSize = 60;
+#endif
pltEntrySize = 4;
ipltEntrySize = 16; // PPC64PltCallStub::size
gotBaseSymInGotPlt = false;
@@ -1072,26 +1076,38 @@ void PPC64::writeGotHeader(uint8_t *buf) const {
}
void PPC64::writePltHeader(uint8_t *buf) const {
+ int64_t gotPltOffset = in.gotPlt->getVA() - (in.plt->getVA() + 8);
+
// The generic resolver stub goes first.
write32(buf + 0, 0x7c0802a6); // mflr r0
write32(buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8>
write32(buf + 8, 0x7d6802a6); // mflr r11
write32(buf + 12, 0x7c0803a6); // mtlr r0
write32(buf + 16, 0x7d8b6050); // subf r12, r11, r12
+#ifdef __OpenBSD__
+ write32(buf + 20, 0x380cffd4); // subi r0,r12,44
+#else
write32(buf + 20, 0x380cffcc); // subi r0,r12,52
+#endif
write32(buf + 24, 0x7800f082); // srdi r0,r0,62,2
+#ifdef __OpenBSD__
+ write32(buf + 28, 0x3d6b0000 | ha(gotPltOffset)); // addis r11,r11,offset@ha
+ write32(buf + 32, 0x396b0000 | lo(gotPltOffset)); // addi r11,r11,offset@l
+#else
write32(buf + 28, 0xe98b002c); // ld r12,44(r11)
write32(buf + 32, 0x7d6c5a14); // add r11,r12,r11
+#endif
write32(buf + 36, 0xe98b0000); // ld r12,0(r11)
write32(buf + 40, 0xe96b0008); // ld r11,8(r11)
write32(buf + 44, 0x7d8903a6); // mtctr r12
write32(buf + 48, 0x4e800420); // bctr
+#ifndef __OpenBSD__
// The 'bcl' instruction will set the link register to the address of the
// following instruction ('mflr r11'). Here we store the offset from that
// instruction to the first entry in the GotPlt section.
- int64_t gotPltOffset = in.gotPlt->getVA() - (in.plt->getVA() + 8);
write64(buf + 52, gotPltOffset);
+#endif
}
void PPC64::writePlt(uint8_t *buf, const Symbol &sym,

Some files were not shown because too many files have changed in this diff Show more