SecBSD's official ports repository
This commit is contained in:
commit
2c0afcbbf3
64331 changed files with 5339189 additions and 0 deletions
14
devel/llvm/patches/patch-cmake_modules_GetLibraryName_cmake
Normal file
14
devel/llvm/patches/patch-cmake_modules_GetLibraryName_cmake
Normal 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)
|
|
@ -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")
|
21
devel/llvm/patches/patch-docs_CommandGuide_llvm-ranlib_rst
Normal file
21
devel/llvm/patches/patch-docs_CommandGuide_llvm-ranlib_rst
Normal 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``.
|
20
devel/llvm/patches/patch-include_llvm_BinaryFormat_ELF_h
Normal file
20
devel/llvm/patches/patch-include_llvm_BinaryFormat_ELF_h
Normal 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.
|
29
devel/llvm/patches/patch-include_llvm_CodeGen_AsmPrinter_h
Normal file
29
devel/llvm/patches/patch-include_llvm_CodeGen_AsmPrinter_h
Normal 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;
|
|
@ -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.
|
31
devel/llvm/patches/patch-include_llvm_CodeGen_Passes_h
Normal file
31
devel/llvm/patches/patch-include_llvm_CodeGen_Passes_h
Normal 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.
|
||||
///
|
|
@ -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
|
|
@ -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.
|
29
devel/llvm/patches/patch-include_llvm_InitializePasses_h
Normal file
29
devel/llvm/patches/patch-include_llvm_InitializePasses_h
Normal 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&);
|
|
@ -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
|
31
devel/llvm/patches/patch-lib_CodeGen_CMakeLists_txt
Normal file
31
devel/llvm/patches/patch-lib_CodeGen_CMakeLists_txt
Normal 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
|
|
@ -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.
|
348
devel/llvm/patches/patch-lib_CodeGen_ReturnProtectorLowering_cpp
Normal file
348
devel/llvm/patches/patch-lib_CodeGen_ReturnProtectorLowering_cpp
Normal 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);
|
||||
+}
|
91
devel/llvm/patches/patch-lib_CodeGen_ReturnProtectorPass_cpp
Normal file
91
devel/llvm/patches/patch-lib_CodeGen_ReturnProtectorPass_cpp
Normal 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(); }
|
30
devel/llvm/patches/patch-lib_CodeGen_TargetPassConfig_cpp
Normal file
30
devel/llvm/patches/patch-lib_CodeGen_TargetPassConfig_cpp
Normal 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());
|
14
devel/llvm/patches/patch-lib_MC_MCAsmInfoELF_cpp
Normal file
14
devel/llvm/patches/patch-lib_MC_MCAsmInfoELF_cpp
Normal 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";
|
19
devel/llvm/patches/patch-lib_MC_MCELFStreamer_cpp
Normal file
19
devel/llvm/patches/patch-lib_MC_MCELFStreamer_cpp
Normal 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) {
|
22
devel/llvm/patches/patch-lib_MC_MCParser_AsmParser_cpp
Normal file
22
devel/llvm/patches/patch-lib_MC_MCParser_AsmParser_cpp
Normal 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.
|
|
@ -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.
|
|
@ -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 {
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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)>;
|
||||
|
|
@ -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()));
|
||||
+}
|
|
@ -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
|
|
@ -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(); }
|
|
@ -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())) {
|
13
devel/llvm/patches/patch-lib_Target_AArch64_CMakeLists_txt
Normal file
13
devel/llvm/patches/patch-lib_Target_AArch64_CMakeLists_txt
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
22
devel/llvm/patches/patch-lib_Target_Mips_CMakeLists_txt
Normal file
22
devel/llvm/patches/patch-lib_Target_Mips_CMakeLists_txt
Normal 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
|
|
@ -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};
|
||||
|
89
devel/llvm/patches/patch-lib_Target_Mips_MipsAsmPrinter_cpp
Normal file
89
devel/llvm/patches/patch-lib_Target_Mips_MipsAsmPrinter_cpp
Normal 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 &&
|
|
@ -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;
|
||||
}
|
35
devel/llvm/patches/patch-lib_Target_Mips_MipsFrameLowering_h
Normal file
35
devel/llvm/patches/patch-lib_Target_Mips_MipsFrameLowering_h
Normal 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,
|
|
@ -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)
|
37
devel/llvm/patches/patch-lib_Target_Mips_MipsInstrInfo_td
Normal file
37
devel/llvm/patches/patch-lib_Target_Mips_MipsInstrInfo_td
Normal 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
|
||||
//===----------------------------------------------------------------------===//
|
|
@ -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;
|
||||
+}
|
|
@ -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);
|
||||
+}
|
|
@ -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
|
|
@ -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
|
21
devel/llvm/patches/patch-lib_Target_Mips_Mips_h
Normal file
21
devel/llvm/patches/patch-lib_Target_Mips_Mips_h
Normal 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
|
11
devel/llvm/patches/patch-lib_Target_PowerPC_CMakeLists_txt
Normal file
11
devel/llvm/patches/patch-lib_Target_PowerPC_CMakeLists_txt
Normal 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
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
37
devel/llvm/patches/patch-lib_Target_PowerPC_PPCInstrInfo_td
Normal file
37
devel/llvm/patches/patch-lib_Target_PowerPC_PPCInstrInfo_td
Normal 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
|
|
@ -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;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -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
|
|
@ -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;
|
|
@ -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);
|
|
@ -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:
|
42
devel/llvm/patches/patch-lib_Target_Sparc_SparcInstr64Bit_td
Normal file
42
devel/llvm/patches/patch-lib_Target_Sparc_SparcInstr64Bit_td
Normal 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]
|
||||
|
113
devel/llvm/patches/patch-lib_Target_Sparc_SparcInstrInfo_td
Normal file
113
devel/llvm/patches/patch-lib_Target_Sparc_SparcInstrInfo_td
Normal 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]
|
||||
|
26
devel/llvm/patches/patch-lib_Target_X86_CMakeLists_txt
Normal file
26
devel/llvm/patches/patch-lib_Target_X86_CMakeLists_txt
Normal 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
|
14
devel/llvm/patches/patch-lib_Target_X86_X86AsmPrinter_h
Normal file
14
devel/llvm/patches/patch-lib_Target_X86_X86AsmPrinter_h
Normal 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());
|
720
devel/llvm/patches/patch-lib_Target_X86_X86FixupGadgets_cpp
Normal file
720
devel/llvm/patches/patch-lib_Target_X86_X86FixupGadgets_cpp
Normal 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;
|
||||
+}
|
175
devel/llvm/patches/patch-lib_Target_X86_X86FrameLowering_cpp
Normal file
175
devel/llvm/patches/patch-lib_Target_X86_X86FrameLowering_cpp
Normal 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(
|
59
devel/llvm/patches/patch-lib_Target_X86_X86FrameLowering_h
Normal file
59
devel/llvm/patches/patch-lib_Target_X86_X86FrameLowering_h
Normal 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;
|
|
@ -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() {
|
48
devel/llvm/patches/patch-lib_Target_X86_X86InstrCompiler_td
Normal file
48
devel/llvm/patches/patch-lib_Target_X86_X86InstrCompiler_td
Normal 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
87
devel/llvm/patches/patch-lib_Target_X86_X86MCInstLower_cpp
Normal file
87
devel/llvm/patches/patch-lib_Target_X86_X86MCInstLower_cpp
Normal 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);
|
||||
}
|
|
@ -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;}
|
43
devel/llvm/patches/patch-lib_Target_X86_X86RegisterInfo_td
Normal file
43
devel/llvm/patches/patch-lib_Target_X86_X86RegisterInfo_td
Normal 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
|
|
@ -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;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -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
|
33
devel/llvm/patches/patch-lib_Target_X86_X86Subtarget_h
Normal file
33
devel/llvm/patches/patch-lib_Target_X86_X86Subtarget_h
Normal 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(); }
|
17
devel/llvm/patches/patch-lib_Target_X86_X86TargetMachine_cpp
Normal file
17
devel/llvm/patches/patch-lib_Target_X86_X86TargetMachine_cpp
Normal 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());
|
||||
}
|
||||
|
20
devel/llvm/patches/patch-lib_Target_X86_X86_h
Normal file
20
devel/llvm/patches/patch-lib_Target_X86_X86_h
Normal 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();
|
15
devel/llvm/patches/patch-lib_Target_X86_X86_td
Normal file
15
devel/llvm/patches/patch-lib_Target_X86_X86_td
Normal 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
|
|
@ -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 =
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
@ -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<
|
|
@ -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>;
|
||||
|
|
@ -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);
|
|
@ -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;
|
|
@ -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.
|
|
@ -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();
|
|
@ -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)
|
13
devel/llvm/patches/patch-tools_clang_lib_Basic_Targets_X86_h
Normal file
13
devel/llvm/patches/patch-tools_clang_lib_Basic_Targets_X86_h
Normal 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
|
31
devel/llvm/patches/patch-tools_clang_lib_CodeGen_CGCall_cpp
Normal file
31
devel/llvm/patches/patch-tools_clang_lib_CodeGen_CGCall_cpp
Normal 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.
|
|
@ -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;
|
||||
}
|
74
devel/llvm/patches/patch-tools_clang_lib_Driver_Driver_cpp
Normal file
74
devel/llvm/patches/patch-tools_clang_lib_Driver_Driver_cpp
Normal 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;
|
||||
};
|
|
@ -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.
|
|
@ -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)) {
|
|
@ -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.
|
|
@ -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;
|
|
@ -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;
|
||||
+ }
|
||||
+}
|
|
@ -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 {
|
|
@ -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)) {
|
108
devel/llvm/patches/patch-tools_clang_lib_Sema_SemaChecking_cpp
Normal file
108
devel/llvm/patches/patch-tools_clang_lib_Sema_SemaChecking_cpp
Normal 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,
|
|
@ -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);
|
266
devel/llvm/patches/patch-tools_clang_lib_Sema_SemaDeclCXX_cpp
Normal file
266
devel/llvm/patches/patch-tools_clang_lib_Sema_SemaDeclCXX_cpp
Normal 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) {
|
|
@ -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()
|
|
@ -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/) {
|
14
devel/llvm/patches/patch-tools_lld_CMakeLists_txt
Normal file
14
devel/llvm/patches/patch-tools_lld_CMakeLists_txt
Normal 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)
|
||||
|
36
devel/llvm/patches/patch-tools_lld_ELF_Arch_AArch64_cpp
Normal file
36
devel/llvm/patches/patch-tools_lld_ELF_Arch_AArch64_cpp
Normal 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(); }
|
59
devel/llvm/patches/patch-tools_lld_ELF_Arch_PPC64_cpp
Normal file
59
devel/llvm/patches/patch-tools_lld_ELF_Arch_PPC64_cpp
Normal 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
Loading…
Add table
Add a link
Reference in a new issue