sync ports with The Matrix
This commit is contained in:
parent
ec769495ab
commit
f5034afcba
3108 changed files with 91999 additions and 80269 deletions
18
devel/llvm/13/Makefile
Normal file
18
devel/llvm/13/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
LLVM_MAJOR = 13
|
||||
LLVM_VERSION = ${LLVM_MAJOR}.0.0
|
||||
LLVM_PKGSPEC = >=13,<14
|
||||
|
||||
REVISION-main = 10
|
||||
REVISION-lldb = 4
|
||||
REVISION-python = 3
|
||||
|
||||
SHARED_LIBS += LTO 6.0 \
|
||||
Remarks 0.0 \
|
||||
clang-cpp 1.0 \
|
||||
clang 8.2 \
|
||||
lldb 3.0
|
||||
|
||||
# Apache License v2.0 with LLVM Exceptions
|
||||
PERMIT_PACKAGE = Yes
|
||||
|
||||
.include <bsd.port.mk>
|
2
devel/llvm/13/distinfo
Normal file
2
devel/llvm/13/distinfo
Normal file
|
@ -0,0 +1,2 @@
|
|||
SHA256 (llvm-project-13.0.0.src.tar.xz) = YHWtMPGsDhXwfBvwYsHhJowkHWdPEb0yzfDgQMcfK/M=
|
||||
SIZE (llvm-project-13.0.0.src.tar.xz) = 97577404
|
|
@ -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: clang/include/clang/AST/FormatString.h
|
||||
--- clang/include/clang/AST/FormatString.h.orig
|
||||
+++ 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: clang/include/clang/Basic/CodeGenOptions.def
|
||||
--- clang/include/clang/Basic/CodeGenOptions.def.orig
|
||||
+++ 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: clang/include/clang/Basic/DiagnosticSemaKinds.td
|
||||
--- clang/include/clang/Basic/DiagnosticSemaKinds.td.orig
|
||||
+++ 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: clang/include/clang/Driver/Options.td
|
||||
--- clang/include/clang/Driver/Options.td.orig
|
||||
+++ 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>;
|
||||
|
13
devel/llvm/13/patches/patch-clang_include_clang_Sema_Sema_h
Normal file
13
devel/llvm/13/patches/patch-clang_include_clang_Sema_Sema_h
Normal file
|
@ -0,0 +1,13 @@
|
|||
Teach Clang about syslog format attribute
|
||||
|
||||
Index: clang/include/clang/Sema/Sema.h
|
||||
--- clang/include/clang/Sema/Sema.h.orig
|
||||
+++ 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);
|
37
devel/llvm/13/patches/patch-clang_lib_AST_FormatString_cpp
Normal file
37
devel/llvm/13/patches/patch-clang_lib_AST_FormatString_cpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
|
||||
there are various %llb formats. Adjust the code to handle the length specifiers
|
||||
and type check like it is used by the regular case.
|
||||
|
||||
Index: clang/lib/AST/FormatString.cpp
|
||||
--- clang/lib/AST/FormatString.cpp.orig
|
||||
+++ 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;
|
14
devel/llvm/13/patches/patch-clang_lib_Basic_TargetInfo_cpp
Normal file
14
devel/llvm/13/patches/patch-clang_lib_Basic_TargetInfo_cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
- Our malloc(3) guarantees 16-byte alignment.
|
||||
|
||||
Index: clang/lib/Basic/TargetInfo.cpp
|
||||
--- clang/lib/Basic/TargetInfo.cpp.orig
|
||||
+++ 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.
|
20
devel/llvm/13/patches/patch-clang_lib_Basic_Targets_Mips_h
Normal file
20
devel/llvm/13/patches/patch-clang_lib_Basic_Targets_Mips_h
Normal file
|
@ -0,0 +1,20 @@
|
|||
- Implement the 'h' register constraint on mips64. This lets clang build
|
||||
pieces of software that use the constraint if the compiler claims
|
||||
to be compatible with GCC 4.2.1.
|
||||
Note that the constraint was removed in GCC 4.4. The reason was that
|
||||
'h' could generate code whose result is unpredictable. The underlying
|
||||
reason is that the HI and LO registers are special, and the optimizer
|
||||
has to be careful when choosing the order of HI/LO accesses. It looks
|
||||
that LLVM has the needed logic.
|
||||
|
||||
Index: clang/lib/Basic/Targets/Mips.h
|
||||
--- clang/lib/Basic/Targets/Mips.h.orig
|
||||
+++ 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();
|
22
devel/llvm/13/patches/patch-clang_lib_Basic_Targets_X86_cpp
Normal file
22
devel/llvm/13/patches/patch-clang_lib_Basic_Targets_X86_cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
implement -msave-args in clang/llvm, like the sun did for gcc
|
||||
|
||||
Index: clang/lib/Basic/Targets/X86.cpp
|
||||
--- clang/lib/Basic/Targets/X86.cpp.orig
|
||||
+++ 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/13/patches/patch-clang_lib_Basic_Targets_X86_h
Normal file
13
devel/llvm/13/patches/patch-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: clang/lib/Basic/Targets/X86.h
|
||||
--- clang/lib/Basic/Targets/X86.h.orig
|
||||
+++ 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/13/patches/patch-clang_lib_CodeGen_CGCall_cpp
Normal file
31
devel/llvm/13/patches/patch-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: clang/lib/CodeGen/CGCall.cpp
|
||||
--- clang/lib/CodeGen/CGCall.cpp.orig
|
||||
+++ 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: clang/lib/CodeGen/CodeGenModule.cpp
|
||||
--- clang/lib/CodeGen/CodeGenModule.cpp.orig
|
||||
+++ 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/13/patches/patch-clang_lib_Driver_Driver_cpp
Normal file
74
devel/llvm/13/patches/patch-clang_lib_Driver_Driver_cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
- Report versioned lib.so in cc --print-file-name given short name
|
||||
|
||||
Index: clang/lib/Driver/Driver.cpp
|
||||
--- clang/lib/Driver/Driver.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/Arch/RISCV.cpp
|
||||
--- clang/lib/Driver/ToolChains/Arch/RISCV.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/Arch/X86.cpp
|
||||
--- clang/lib/Driver/ToolChains/Arch/X86.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/Clang.cpp
|
||||
--- clang/lib/Driver/ToolChains/Clang.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/Gnu.cpp
|
||||
--- clang/lib/Driver/ToolChains/Gnu.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/OpenBSD.cpp
|
||||
--- clang/lib/Driver/ToolChains/OpenBSD.cpp.orig
|
||||
+++ 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: clang/lib/Driver/ToolChains/OpenBSD.h
|
||||
--- clang/lib/Driver/ToolChains/OpenBSD.h.orig
|
||||
+++ 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: clang/lib/Frontend/CompilerInvocation.cpp
|
||||
--- clang/lib/Frontend/CompilerInvocation.cpp.orig
|
||||
+++ 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/13/patches/patch-clang_lib_Sema_SemaChecking_cpp
Normal file
108
devel/llvm/13/patches/patch-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: clang/lib/Sema/SemaChecking.cpp
|
||||
--- clang/lib/Sema/SemaChecking.cpp.orig
|
||||
+++ 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,
|
13
devel/llvm/13/patches/patch-clang_lib_Sema_SemaDeclAttr_cpp
Normal file
13
devel/llvm/13/patches/patch-clang_lib_Sema_SemaDeclAttr_cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
Teach Clang about syslog format attribute
|
||||
|
||||
Index: clang/lib/Sema/SemaDeclAttr.cpp
|
||||
--- clang/lib/Sema/SemaDeclAttr.cpp.orig
|
||||
+++ 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/13/patches/patch-clang_lib_Sema_SemaDeclCXX_cpp
Normal file
266
devel/llvm/13/patches/patch-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: clang/lib/Sema/SemaDeclCXX.cpp
|
||||
--- clang/lib/Sema/SemaDeclCXX.cpp.orig
|
||||
+++ 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,12 @@
|
|||
Index: clang/tools/clang-format/clang-format-sublime.py
|
||||
--- clang/tools/clang-format/clang-format-sublime.py.orig
|
||||
+++ clang/tools/clang-format/clang-format-sublime.py
|
||||
@@ -18,7 +18,7 @@ import sublime_plugin
|
||||
import subprocess
|
||||
|
||||
# Change this to the full path if clang-format is not on the path.
|
||||
-binary = 'clang-format'
|
||||
+binary = 'clang-format-${LLVM_MAJOR}'
|
||||
|
||||
# Change this to format according to other formatting styles. See the output of
|
||||
# 'clang-format --help' for a list of supported styles. The default looks for
|
|
@ -0,0 +1,12 @@
|
|||
Index: clang/tools/clang-format/clang-format.py
|
||||
--- clang/tools/clang-format/clang-format.py.orig
|
||||
+++ clang/tools/clang-format/clang-format.py
|
||||
@@ -48,7 +48,7 @@ import vim
|
||||
|
||||
# set g:clang_format_path to the path to clang-format if it is not on the path
|
||||
# Change this to the full path if clang-format is not on the path.
|
||||
-binary = 'clang-format'
|
||||
+binary = 'clang-format-${LLVM_MAJOR}'
|
||||
if vim.eval('exists("g:clang_format_path")') == "1":
|
||||
binary = vim.eval('g:clang_format_path')
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
Index: clang/tools/clang-format/git-clang-format
|
||||
--- clang/tools/clang-format/git-clang-format.orig
|
||||
+++ clang/tools/clang-format/git-clang-format
|
||||
@@ -92,7 +92,7 @@ def main():
|
||||
usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=desc)
|
||||
p.add_argument('--binary',
|
||||
- default=config.get('clangformat.binary', 'clang-format'),
|
||||
+ default=config.get('clangformat.binary', 'clang-format-${LLVM_MAJOR}'),
|
||||
help='path to clang-format'),
|
||||
p.add_argument('--commit',
|
||||
default=config.get('clangformat.commit', 'HEAD'),
|
||||
@@ -361,7 +361,7 @@ def create_tree_from_workdir(filenames):
|
||||
|
||||
|
||||
def run_clang_format_and_save_to_tree(changed_lines, revision=None,
|
||||
- binary='clang-format', style=None):
|
||||
+ binary='clang-format-${LLVM_MAJOR}', style=None):
|
||||
"""Run clang-format on each file and save the result to a git tree.
|
||||
|
||||
Returns the object ID (SHA-1) of the created tree."""
|
||||
@@ -414,7 +414,7 @@ def create_tree(input_lines, mode):
|
||||
|
||||
|
||||
def clang_format_to_blob(filename, line_ranges, revision=None,
|
||||
- binary='clang-format', style=None):
|
||||
+ binary='clang-format-${LLVM_MAJOR}', style=None):
|
||||
"""Run clang-format on the given file and save the result to a git blob.
|
||||
|
||||
Runs on the file in `revision` if not None, or on the file in the working
|
|
@ -0,0 +1,13 @@
|
|||
-Bsymbolic-functions is not supported by our ld.bfd version.
|
||||
|
||||
Index: clang/tools/clang-shlib/CMakeLists.txt
|
||||
--- clang/tools/clang-shlib/CMakeLists.txt.orig
|
||||
+++ 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: clang/tools/scan-build/libexec/ccc-analyzer
|
||||
--- clang/tools/scan-build/libexec/ccc-analyzer.orig
|
||||
+++ 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/13/patches/patch-lld_CMakeLists_txt
Normal file
14
devel/llvm/13/patches/patch-lld_CMakeLists_txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
Don't build MachO2 support in lld. This code reaches into libunwind
|
||||
internals.
|
||||
|
||||
Index: lld/CMakeLists.txt
|
||||
--- lld/CMakeLists.txt.orig
|
||||
+++ 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/13/patches/patch-lld_ELF_Arch_AArch64_cpp
Normal file
36
devel/llvm/13/patches/patch-lld_ELF_Arch_AArch64_cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
- Enable BTI PLT entries by default.
|
||||
|
||||
Index: lld/ELF/Arch/AArch64.cpp
|
||||
--- lld/ELF/Arch/AArch64.cpp.orig
|
||||
+++ 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/13/patches/patch-lld_ELF_Arch_PPC64_cpp
Normal file
59
devel/llvm/13/patches/patch-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: lld/ELF/Arch/PPC64.cpp
|
||||
--- lld/ELF/Arch/PPC64.cpp.orig
|
||||
+++ 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,
|
16
devel/llvm/13/patches/patch-lld_ELF_Arch_RISCV_cpp
Normal file
16
devel/llvm/13/patches/patch-lld_ELF_Arch_RISCV_cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
- Downgrade RISCV ABI mismatch error to a warning
|
||||
|
||||
Index: lld/ELF/Arch/RISCV.cpp
|
||||
--- lld/ELF/Arch/RISCV.cpp.orig
|
||||
+++ lld/ELF/Arch/RISCV.cpp
|
||||
@@ -124,8 +124,8 @@ uint32_t RISCV::calcEFlags() const {
|
||||
target |= EF_RISCV_RVC;
|
||||
|
||||
if ((eflags & EF_RISCV_FLOAT_ABI) != (target & EF_RISCV_FLOAT_ABI))
|
||||
- error(toString(f) +
|
||||
- ": cannot link object files with different floating-point ABI");
|
||||
+ warn(toString(f) +
|
||||
+ ": linking object files with different floating-point ABI");
|
||||
|
||||
if ((eflags & EF_RISCV_RVE) != (target & EF_RISCV_RVE))
|
||||
error(toString(f) +
|
72
devel/llvm/13/patches/patch-lld_ELF_Arch_X86_64_cpp
Normal file
72
devel/llvm/13/patches/patch-lld_ELF_Arch_X86_64_cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
- Add IBT support to the retpoline PLTs. Since we use retpoline PLTs by
|
||||
default on OpenBSD this will give us IBT support by default. Fixes
|
||||
indirect function calls for functions in shared libraries.
|
||||
- Add IBT support to the retpoline+znow PLTs
|
||||
|
||||
Index: lld/ELF/Arch/X86_64.cpp
|
||||
--- lld/ELF/Arch/X86_64.cpp.orig
|
||||
+++ lld/ELF/Arch/X86_64.cpp
|
||||
@@ -1050,7 +1050,7 @@ Retpoline::Retpoline() {
|
||||
}
|
||||
|
||||
void Retpoline::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
- write64le(buf, s.getPltVA() + 17);
|
||||
+ write64le(buf, s.getPltVA() + 21);
|
||||
}
|
||||
|
||||
void Retpoline::writePltHeader(uint8_t *buf) const {
|
||||
@@ -1078,22 +1078,23 @@ void Retpoline::writePltHeader(uint8_t *buf) const {
|
||||
void Retpoline::writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const {
|
||||
const uint8_t insn[] = {
|
||||
- 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11
|
||||
- 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20
|
||||
- 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12
|
||||
- 0x68, 0, 0, 0, 0, // 11: pushq <relocation index>
|
||||
- 0xe9, 0, 0, 0, 0, // 16: jmp plt+0
|
||||
- 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding
|
||||
+ 0xf3, 0x0f, 0x1e, 0xfa, // 0: endbr64
|
||||
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 4: mov foo@GOTPLT(%rip), %r11
|
||||
+ 0xe8, 0, 0, 0, 0, // b: callq plt+0x20
|
||||
+ 0xe9, 0, 0, 0, 0, // 10: jmp plt+0x12
|
||||
+ 0x68, 0, 0, 0, 0, // 15: pushq <relocation index>
|
||||
+ 0xe9, 0, 0, 0, 0, // 1a: jmp plt+0
|
||||
+ 0xcc, // 1f: int3; padding
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
|
||||
uint64_t off = pltEntryAddr - in.plt->getVA();
|
||||
|
||||
- write32le(buf + 3, sym.getGotPltVA() - pltEntryAddr - 7);
|
||||
- write32le(buf + 8, -off - 12 + 32);
|
||||
- write32le(buf + 13, -off - 17 + 18);
|
||||
- write32le(buf + 18, sym.pltIndex);
|
||||
- write32le(buf + 23, -off - 27);
|
||||
+ write32le(buf + 7, sym.getGotPltVA() - pltEntryAddr - 11);
|
||||
+ write32le(buf + 12, -off - 16 + 32);
|
||||
+ write32le(buf + 17, -off - 21 + 18);
|
||||
+ write32le(buf + 22, sym.pltIndex);
|
||||
+ write32le(buf + 27, -off - 31);
|
||||
}
|
||||
|
||||
RetpolineZNow::RetpolineZNow() {
|
||||
@@ -1121,14 +1122,14 @@ void RetpolineZNow::writePltHeader(uint8_t *buf) const
|
||||
void RetpolineZNow::writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const {
|
||||
const uint8_t insn[] = {
|
||||
- 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11
|
||||
- 0xe9, 0, 0, 0, 0, // jmp plt+0
|
||||
- 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding
|
||||
+ 0xf3, 0x0f, 0x1e, 0xfa, // 0: endbr64
|
||||
+ 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 4: mov foo@GOTPLT(%rip), %r11
|
||||
+ 0xe9, 0, 0, 0, 0, // b: jmp plt+0
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
|
||||
- write32le(buf + 3, sym.getGotPltVA() - pltEntryAddr - 7);
|
||||
- write32le(buf + 8, in.plt->getVA() - pltEntryAddr - 12);
|
||||
+ write32le(buf + 7, sym.getGotPltVA() - pltEntryAddr - 11);
|
||||
+ write32le(buf + 12, in.plt->getVA() - pltEntryAddr - 16);
|
||||
}
|
||||
|
||||
static TargetInfo *getTargetInfo() {
|
29
devel/llvm/13/patches/patch-lld_ELF_Config_h
Normal file
29
devel/llvm/13/patches/patch-lld_ELF_Config_h
Normal file
|
@ -0,0 +1,29 @@
|
|||
- XXX no comment
|
||||
- Implement support for PT_OPENBSD_NOBTCFI in lld(1). This can be set using
|
||||
the -z nobtcfi option.
|
||||
|
||||
Index: lld/ELF/Config.h
|
||||
--- lld/ELF/Config.h.orig
|
||||
+++ lld/ELF/Config.h
|
||||
@@ -236,6 +236,7 @@ struct Configuration {
|
||||
bool zInitfirst;
|
||||
bool zInterpose;
|
||||
bool zKeepTextSectionPrefix;
|
||||
+ bool zNoBtCfi;
|
||||
bool zNodefaultlib;
|
||||
bool zNodelete;
|
||||
bool zNodlopen;
|
||||
@@ -266,8 +267,13 @@ struct Configuration {
|
||||
ELFKind ekind = ELFNoneKind;
|
||||
uint16_t emachine = llvm::ELF::EM_NONE;
|
||||
llvm::Optional<uint64_t> imageBase;
|
||||
+ // commonPageSize and maxPageSize are influenced by nmagic or omagic
|
||||
+ // so may be set to 1 if either of those options is given.
|
||||
uint64_t commonPageSize;
|
||||
uint64_t maxPageSize;
|
||||
+ // textAlignPageSize is the target max page size for the purpose
|
||||
+ // of aligning text sections, which may be unaligned if given nmagic
|
||||
+ uint64_t textAlignPageSize;
|
||||
uint64_t mipsGotSize;
|
||||
uint64_t zStackSize;
|
||||
unsigned ltoPartitions;
|
56
devel/llvm/13/patches/patch-lld_ELF_DriverUtils_cpp
Normal file
56
devel/llvm/13/patches/patch-lld_ELF_DriverUtils_cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
- Handle the OpenBSD-style major/minor shared library version scheme.
|
||||
- Report versioned lib.so in cc --print-file-name given short name
|
||||
|
||||
Index: lld/ELF/DriverUtils.cpp
|
||||
--- lld/ELF/DriverUtils.cpp.orig
|
||||
+++ lld/ELF/DriverUtils.cpp
|
||||
@@ -230,13 +230,48 @@ Optional<std::string> elf::findFromSearchPaths(StringR
|
||||
return None;
|
||||
}
|
||||
|
||||
+namespace {
|
||||
+// Must be in sync with findMajMinShlib in clang/lib/Driver/Driver.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
|
||||
+
|
||||
// This is for -l<basename>. We'll look for lib<basename>.so or lib<basename>.a from
|
||||
// search paths.
|
||||
Optional<std::string> elf::searchLibraryBaseName(StringRef name) {
|
||||
for (StringRef dir : config->searchPaths) {
|
||||
- if (!config->isStatic)
|
||||
+ if (!config->isStatic) {
|
||||
if (Optional<std::string> s = findFile(dir, "lib" + name + ".so"))
|
||||
return s;
|
||||
+ if (Optional<std::string> s = findMajMinShlib(dir, "lib" + name + ".so"))
|
||||
+ return s;
|
||||
+ }
|
||||
if (Optional<std::string> s = findFile(dir, "lib" + name + ".a"))
|
||||
return s;
|
||||
}
|
175
devel/llvm/13/patches/patch-lld_ELF_Driver_cpp
Normal file
175
devel/llvm/13/patches/patch-lld_ELF_Driver_cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
- enable retpoline by default
|
||||
- enable PIE by default.
|
||||
- arm64 and riscv64 can now do --execute-only by default
|
||||
- enable --exec-only as default on AMD64
|
||||
- Make --execute-only the default on powerpc64.
|
||||
- Permit the --exec-only option on i386 also.
|
||||
- make --execute-only the default on powerpc
|
||||
- default sparc64 ld.lld to --execute-only
|
||||
- switch mips64 ld.lld to execute-only
|
||||
- Implement support for PT_OPENBSD_NOBTCFI in lld(1). This can be set using
|
||||
the -z nobtcfi option.
|
||||
|
||||
Index: lld/ELF/Driver.cpp
|
||||
--- lld/ELF/Driver.cpp.orig
|
||||
+++ lld/ELF/Driver.cpp
|
||||
@@ -358,8 +358,19 @@ static void checkOptions() {
|
||||
}
|
||||
|
||||
if (config->executeOnly) {
|
||||
- if (config->emachine != EM_AARCH64)
|
||||
- error("-execute-only is only supported on AArch64 targets");
|
||||
+ switch (config->emachine) {
|
||||
+ case EM_386:
|
||||
+ case EM_AARCH64:
|
||||
+ case EM_MIPS:
|
||||
+ case EM_PPC:
|
||||
+ case EM_PPC64:
|
||||
+ case EM_RISCV:
|
||||
+ case EM_SPARCV9:
|
||||
+ case EM_X86_64:
|
||||
+ break;
|
||||
+ default:
|
||||
+ error("-execute-only is not supported on this target");
|
||||
+ }
|
||||
|
||||
if (config->singleRoRx && !script->hasSectionsCommand)
|
||||
error("-execute-only and -no-rosegment cannot be used together");
|
||||
@@ -451,10 +462,12 @@ static bool isKnownZFlag(StringRef s) {
|
||||
s == "initfirst" || s == "interpose" ||
|
||||
s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" ||
|
||||
s == "separate-code" || s == "separate-loadable-segments" ||
|
||||
- s == "start-stop-gc" || s == "nocombreloc" || s == "nocopyreloc" ||
|
||||
+ s == "start-stop-gc" || s == "nobtcfi" ||
|
||||
+ s == "nocombreloc" || s == "nocopyreloc" ||
|
||||
s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" ||
|
||||
s == "noexecstack" || s == "nognustack" ||
|
||||
s == "nokeep-text-section-prefix" || s == "norelro" ||
|
||||
+ s == "noretpolineplt" ||
|
||||
s == "noseparate-code" || s == "nostart-stop-gc" || s == "notext" ||
|
||||
s == "now" || s == "origin" || s == "pac-plt" || s == "rel" ||
|
||||
s == "rela" || s == "relro" || s == "retpolineplt" ||
|
||||
@@ -1045,8 +1058,6 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
errorHandler().errorHandlingScript =
|
||||
args.getLastArgValue(OPT_error_handling_script);
|
||||
|
||||
- config->executeOnly =
|
||||
- args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
|
||||
config->exportDynamic =
|
||||
args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false);
|
||||
config->filterList = args::getStrings(args, OPT_filter);
|
||||
@@ -1064,7 +1075,8 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
config->ignoreDataAddressEquality =
|
||||
args.hasArg(OPT_ignore_data_address_equality);
|
||||
config->ignoreFunctionAddressEquality =
|
||||
- args.hasArg(OPT_ignore_function_address_equality);
|
||||
+ args.hasFlag(OPT_ignore_function_address_equality,
|
||||
+ OPT_no_ignore_function_address_equality, true);
|
||||
config->init = args.getLastArgValue(OPT_init, "_init");
|
||||
config->ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline);
|
||||
config->ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate);
|
||||
@@ -1118,7 +1130,12 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
config->optimize = args::getInteger(args, OPT_O, 1);
|
||||
config->orphanHandling = getOrphanHandling(args);
|
||||
config->outputFile = args.getLastArgValue(OPT_o);
|
||||
+#ifdef __OpenBSD__
|
||||
+ config->pie = args.hasFlag(OPT_pie, OPT_no_pie,
|
||||
+ !args.hasArg(OPT_shared) && !args.hasArg(OPT_relocatable));
|
||||
+#else
|
||||
config->pie = args.hasFlag(OPT_pie, OPT_no_pie, false);
|
||||
+#endif
|
||||
config->printIcfSections =
|
||||
args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false);
|
||||
config->printGcSections =
|
||||
@@ -1181,6 +1198,7 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
config->zInterpose = hasZOption(args, "interpose");
|
||||
config->zKeepTextSectionPrefix = getZFlag(
|
||||
args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
|
||||
+ config->zNoBtCfi = hasZOption(args, "nobtcfi");
|
||||
config->zNodefaultlib = hasZOption(args, "nodefaultlib");
|
||||
config->zNodelete = hasZOption(args, "nodelete");
|
||||
config->zNodlopen = hasZOption(args, "nodlopen");
|
||||
@@ -1188,7 +1206,11 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
config->zOrigin = hasZOption(args, "origin");
|
||||
config->zPacPlt = hasZOption(args, "pac-plt");
|
||||
config->zRelro = getZFlag(args, "relro", "norelro", true);
|
||||
- config->zRetpolineplt = hasZOption(args, "retpolineplt");
|
||||
+#ifndef __OpenBSD__
|
||||
+ config->zRetpolineplt = getZFlag(args, "retpolineplt", "noretpolineplt", false);
|
||||
+#else
|
||||
+ config->zRetpolineplt = getZFlag(args, "retpolineplt", "noretpolineplt", true);
|
||||
+#endif
|
||||
config->zRodynamic = hasZOption(args, "rodynamic");
|
||||
config->zSeparate = getZSeparate(args);
|
||||
config->zShstk = hasZOption(args, "shstk");
|
||||
@@ -1459,6 +1481,23 @@ static void setConfigs(opt::InputArgList &args) {
|
||||
args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, m == EM_PPC64);
|
||||
config->pcRelOptimize =
|
||||
args.hasFlag(OPT_pcrel_optimize, OPT_no_pcrel_optimize, m == EM_PPC64);
|
||||
+
|
||||
+ config->executeOnly = false;
|
||||
+#ifdef __OpenBSD__
|
||||
+ switch (m) {
|
||||
+ case EM_AARCH64:
|
||||
+ case EM_MIPS:
|
||||
+ case EM_PPC:
|
||||
+ case EM_PPC64:
|
||||
+ case EM_RISCV:
|
||||
+ case EM_SPARCV9:
|
||||
+ case EM_X86_64:
|
||||
+ config->executeOnly = true;
|
||||
+ break;
|
||||
+ }
|
||||
+#endif
|
||||
+ config->executeOnly =
|
||||
+ args.hasFlag(OPT_execute_only, OPT_no_execute_only, config->executeOnly);
|
||||
}
|
||||
|
||||
// Returns a value of "-format" option.
|
||||
@@ -1596,7 +1635,7 @@ void LinkerDriver::inferMachineType() {
|
||||
}
|
||||
|
||||
// Parse -z max-page-size=<value>. The default value is defined by
|
||||
-// each target.
|
||||
+// each target. Is set to 1 if given nmagic or omagic.
|
||||
static uint64_t getMaxPageSize(opt::InputArgList &args) {
|
||||
uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
|
||||
target->defaultMaxPageSize);
|
||||
@@ -1611,7 +1650,7 @@ static uint64_t getMaxPageSize(opt::InputArgList &args
|
||||
}
|
||||
|
||||
// Parse -z common-page-size=<value>. The default value is defined by
|
||||
-// each target.
|
||||
+// each target. Is set to 1 if given nmagic or omagic.
|
||||
static uint64_t getCommonPageSize(opt::InputArgList &args) {
|
||||
uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size",
|
||||
target->defaultCommonPageSize);
|
||||
@@ -1628,6 +1667,16 @@ static uint64_t getCommonPageSize(opt::InputArgList &a
|
||||
return val;
|
||||
}
|
||||
|
||||
+// Parse -z max-page-size=<value>. The default value is defined by
|
||||
+// each target.
|
||||
+static uint64_t getRealMaxPageSize(opt::InputArgList &args) {
|
||||
+ uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size",
|
||||
+ target->defaultMaxPageSize);
|
||||
+ if (!isPowerOf2_64(val))
|
||||
+ error("max-page-size: value isn't a power of 2");
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
// Parses -image-base option.
|
||||
static Optional<uint64_t> getImageBase(opt::InputArgList &args) {
|
||||
// Because we are using "Config->maxPageSize" here, this function has to be
|
||||
@@ -2414,6 +2463,11 @@ template <class ELFT> void LinkerDriver::link(opt::Inp
|
||||
// optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it
|
||||
// is limited to writing trap instructions on the last executable segment.
|
||||
config->commonPageSize = getCommonPageSize(args);
|
||||
+ // textAlignPageSize is the alignment page size to use when aligning PT_LOAD
|
||||
+ // sections. This is the same as maxPageSize except under -omagic, where data
|
||||
+ // sections are non-aligned (maxPageSize set to 1) but text sections are aligned
|
||||
+ // to the target page size.
|
||||
+ config->textAlignPageSize = config->omagic ? getRealMaxPageSize(args) : config->maxPageSize;
|
||||
|
||||
config->imageBase = getImageBase(args);
|
||||
|
83
devel/llvm/13/patches/patch-lld_ELF_InputFiles_cpp
Normal file
83
devel/llvm/13/patches/patch-lld_ELF_InputFiles_cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
- lld: do not report undefined weak references in shared libraries
|
||||
https://github.com/llvm/llvm-project/commit/52bfd2c1ccd86ff813ee6df5a6700690acdd
|
||||
- add .gnu.warning.SYMBOL support to ld.lld(1)
|
||||
|
||||
Index: lld/ELF/InputFiles.cpp
|
||||
--- lld/ELF/InputFiles.cpp.orig
|
||||
+++ lld/ELF/InputFiles.cpp
|
||||
@@ -52,6 +52,8 @@ std::vector<SharedFile *> elf::sharedFiles;
|
||||
|
||||
std::unique_ptr<TarWriter> elf::tar;
|
||||
|
||||
+DenseMap<StringRef, StringRef> elf::gnuWarnings;
|
||||
+
|
||||
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
|
||||
std::string lld::toString(const InputFile *f) {
|
||||
if (!f)
|
||||
@@ -66,6 +68,17 @@ std::string lld::toString(const InputFile *f) {
|
||||
return f->toStringCache;
|
||||
}
|
||||
|
||||
+// .gnu.warning.SYMBOL are treated as warning symbols for the given symbol
|
||||
+void lld::parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size) {
|
||||
+ if (!name.empty() && name.startswith(".gnu.warning.")) {
|
||||
+ StringRef wsym = name.substr(13);
|
||||
+ StringRef s(data.begin());
|
||||
+ StringRef wng(s.substr(0, size));
|
||||
+ symtab->insert(wsym)->gwarn = true;
|
||||
+ gnuWarnings.insert({wsym, wng});
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
|
||||
unsigned char size;
|
||||
unsigned char endian;
|
||||
@@ -647,6 +660,14 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComd
|
||||
case SHT_RELA:
|
||||
case SHT_NULL:
|
||||
break;
|
||||
+ case SHT_PROGBITS: {
|
||||
+ this->sections[i] = createInputSection(sec);
|
||||
+ StringRef name = CHECK(obj.getSectionName(sec, this->sectionStringTable), this);
|
||||
+ ArrayRef<char> data =
|
||||
+ CHECK(obj.template getSectionContentsAsArray<char>(sec), this);
|
||||
+ parseGNUWarning(name, data, sec.sh_size);
|
||||
+ }
|
||||
+ break;
|
||||
default:
|
||||
this->sections[i] = createInputSection(sec);
|
||||
}
|
||||
@@ -1450,6 +1471,9 @@ template <class ELFT> void SharedFile::parse() {
|
||||
const ELFFile<ELFT> obj = this->getObj<ELFT>();
|
||||
ArrayRef<Elf_Shdr> sections = CHECK(obj.sections(), this);
|
||||
|
||||
+ StringRef sectionStringTable =
|
||||
+ CHECK(obj.getSectionStringTable(sections), this);
|
||||
+
|
||||
const Elf_Shdr *versymSec = nullptr;
|
||||
const Elf_Shdr *verdefSec = nullptr;
|
||||
const Elf_Shdr *verneedSec = nullptr;
|
||||
@@ -1472,7 +1496,14 @@ template <class ELFT> void SharedFile::parse() {
|
||||
case SHT_GNU_verneed:
|
||||
verneedSec = &sec;
|
||||
break;
|
||||
+ case SHT_PROGBITS: {
|
||||
+ StringRef name = CHECK(obj.getSectionName(sec, sectionStringTable), this);
|
||||
+ ArrayRef<char> data =
|
||||
+ CHECK(obj.template getSectionContentsAsArray<char>(sec), this);
|
||||
+ parseGNUWarning(name, data, sec.sh_size);
|
||||
+ break;
|
||||
}
|
||||
+ }
|
||||
}
|
||||
|
||||
if (versymSec && numELFSyms == 0) {
|
||||
@@ -1567,7 +1598,7 @@ template <class ELFT> void SharedFile::parse() {
|
||||
Symbol *s = symtab->addSymbol(
|
||||
Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()});
|
||||
s->exportDynamic = true;
|
||||
- if (s->isUndefined() && !s->isWeak() &&
|
||||
+ if (s->isUndefined() && sym.getBinding() != STB_WEAK &&
|
||||
config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore)
|
||||
requiredSymbols.push_back(s);
|
||||
continue;
|
14
devel/llvm/13/patches/patch-lld_ELF_InputFiles_h
Normal file
14
devel/llvm/13/patches/patch-lld_ELF_InputFiles_h
Normal file
|
@ -0,0 +1,14 @@
|
|||
- add .gnu.warning.SYMBOL support to ld.lld(1)
|
||||
|
||||
Index: lld/ELF/InputFiles.h
|
||||
--- lld/ELF/InputFiles.h.orig
|
||||
+++ lld/ELF/InputFiles.h
|
||||
@@ -37,6 +37,8 @@ class DWARFCache;
|
||||
// Returns "<internal>", "foo.a(bar.o)" or "baz.o".
|
||||
std::string toString(const elf::InputFile *f);
|
||||
|
||||
+void parseGNUWarning(StringRef name, ArrayRef<char> data, size_t size);
|
||||
+
|
||||
namespace elf {
|
||||
|
||||
using llvm::object::Archive;
|
22
devel/llvm/13/patches/patch-lld_ELF_LinkerScript_cpp
Normal file
22
devel/llvm/13/patches/patch-lld_ELF_LinkerScript_cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
- XXX no comment
|
||||
|
||||
Index: lld/ELF/LinkerScript.cpp
|
||||
--- lld/ELF/LinkerScript.cpp.orig
|
||||
+++ lld/ELF/LinkerScript.cpp
|
||||
@@ -954,7 +954,6 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
ctx->memRegion->name, sec->name);
|
||||
}
|
||||
|
||||
- switchTo(sec);
|
||||
|
||||
// ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or
|
||||
// AT>, recompute ctx->lmaOffset; otherwise, if both previous/current LMA
|
||||
@@ -968,6 +967,8 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
ctx->lmaOffset = alignTo(mr->curPos, sec->alignment) - dot;
|
||||
else if (!sameMemRegion || !prevLMARegionIsDefault)
|
||||
ctx->lmaOffset = 0;
|
||||
+
|
||||
+ switchTo(sec);
|
||||
|
||||
// Propagate ctx->lmaOffset to the first "non-header" section.
|
||||
if (PhdrEntry *l = ctx->outSec->ptLoad)
|
26
devel/llvm/13/patches/patch-lld_ELF_Options_td
Normal file
26
devel/llvm/13/patches/patch-lld_ELF_Options_td
Normal file
|
@ -0,0 +1,26 @@
|
|||
- [ELF] Add -nopie alias for -no-pie
|
||||
- defm ignore_function_address_equality: TODO (document it)
|
||||
|
||||
Index: lld/ELF/Options.td
|
||||
--- lld/ELF/Options.td.orig
|
||||
+++ lld/ELF/Options.td
|
||||
@@ -248,8 +248,9 @@ def icf_safe: F<"icf=safe">, HelpText<"Enable safe ide
|
||||
|
||||
def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">;
|
||||
|
||||
-def ignore_function_address_equality: F<"ignore-function-address-equality">,
|
||||
- HelpText<"lld can break the address equality of functions">;
|
||||
+defm ignore_function_address_equality: B<"ignore-function-address-equality",
|
||||
+ "lld can break the address equality of functions",
|
||||
+ "lld cannot break the address equality of functions">;
|
||||
|
||||
def ignore_data_address_equality: F<"ignore-data-address-equality">,
|
||||
HelpText<"lld can break the address equality of data">;
|
||||
@@ -520,6 +521,7 @@ def: Separate<["-"], "F">, Alias<filter>, HelpText<"Al
|
||||
def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">;
|
||||
def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">;
|
||||
def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">;
|
||||
+def: F<"nopie">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
|
||||
def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">;
|
||||
def: Flag<["-"], "n">, Alias<nmagic>, HelpText<"Alias for --nmagic">;
|
||||
def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">;
|
45
devel/llvm/13/patches/patch-lld_ELF_Relocations_cpp
Normal file
45
devel/llvm/13/patches/patch-lld_ELF_Relocations_cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
- add .gnu.warning.SYMBOL support to ld.lld(1)
|
||||
- fix https://reviews.llvm.org/D114982
|
||||
|
||||
Index: lld/ELF/Relocations.cpp
|
||||
--- lld/ELF/Relocations.cpp.orig
|
||||
+++ lld/ELF/Relocations.cpp
|
||||
@@ -954,6 +954,18 @@ template <class ELFT> void elf::reportUndefinedSymbols
|
||||
undefs.clear();
|
||||
}
|
||||
|
||||
+static void reportGNUWarning(Symbol &sym, InputSectionBase &sec,
|
||||
+ uint64_t offset) {
|
||||
+ if (sym.gwarn) {
|
||||
+ StringRef gnuWarning = gnuWarnings.lookup(sym.getName());
|
||||
+ // report first occurance only
|
||||
+ sym.gwarn = false;
|
||||
+ if (!gnuWarning.empty())
|
||||
+ message(sec.getSrcMsg(sym, offset) + "(" + sec.getObjMsg(offset) +
|
||||
+ "): warning: " + gnuWarning);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
// Report an undefined symbol if necessary.
|
||||
// Returns true if the undefined symbol will produce an error message.
|
||||
static bool maybeReportUndefined(Symbol &sym, InputSectionBase &sec,
|
||||
@@ -1327,6 +1339,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGet
|
||||
if (symIndex != 0 && maybeReportUndefined(sym, sec, rel.r_offset))
|
||||
return;
|
||||
|
||||
+ reportGNUWarning(sym, sec, rel.r_offset);
|
||||
+
|
||||
const uint8_t *relocatedAddr = sec.data().begin() + rel.r_offset;
|
||||
RelExpr expr = target->getRelExpr(type, sym, relocatedAddr);
|
||||
|
||||
@@ -1403,8 +1417,8 @@ static void scanReloc(InputSectionBase &sec, OffsetGet
|
||||
// The 4 types that relative GOTPLT are all x86 and x86-64 specific.
|
||||
if (oneof<R_GOTPLTONLY_PC, R_GOTPLTREL, R_GOTPLT, R_TLSGD_GOTPLT>(expr)) {
|
||||
in.gotPlt->hasGotPltOffRel = true;
|
||||
- } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC64_TOCBASE, R_PPC64_RELAX_TOC>(
|
||||
- expr)) {
|
||||
+ } else if (oneof<R_GOTONLY_PC, R_GOTREL, R_PPC32_PLTREL, R_PPC64_TOCBASE,
|
||||
+ R_PPC64_RELAX_TOC>(expr)) {
|
||||
in.got->hasGotOffRel = true;
|
||||
}
|
||||
|
15
devel/llvm/13/patches/patch-lld_ELF_ScriptParser_cpp
Normal file
15
devel/llvm/13/patches/patch-lld_ELF_ScriptParser_cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
- 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.
|
||||
|
||||
Index: lld/ELF/ScriptParser.cpp
|
||||
--- lld/ELF/ScriptParser.cpp.orig
|
||||
+++ lld/ELF/ScriptParser.cpp
|
||||
@@ -1478,6 +1478,7 @@ unsigned ScriptParser::readPhdrType() {
|
||||
.Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
|
||||
.Case("PT_GNU_STACK", PT_GNU_STACK)
|
||||
.Case("PT_GNU_RELRO", PT_GNU_RELRO)
|
||||
+ .Case("PT_OPENBSD_MUTABLE", PT_OPENBSD_MUTABLE)
|
||||
.Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
|
||||
.Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
|
||||
.Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
|
13
devel/llvm/13/patches/patch-lld_ELF_SymbolTable_cpp
Normal file
13
devel/llvm/13/patches/patch-lld_ELF_SymbolTable_cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
- add .gnu.warning.SYMBOL support to ld.lld(1)
|
||||
|
||||
Index: lld/ELF/SymbolTable.cpp
|
||||
--- lld/ELF/SymbolTable.cpp.orig
|
||||
+++ lld/ELF/SymbolTable.cpp
|
||||
@@ -90,6 +90,7 @@ Symbol *SymbolTable::insert(StringRef name) {
|
||||
sym->canInline = true;
|
||||
sym->referenced = false;
|
||||
sym->traced = false;
|
||||
+ sym->gwarn = false;
|
||||
sym->scriptDefined = false;
|
||||
sym->partition = 1;
|
||||
return sym;
|
14
devel/llvm/13/patches/patch-lld_ELF_Symbols_cpp
Normal file
14
devel/llvm/13/patches/patch-lld_ELF_Symbols_cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
Generate __data_start symbol that marks the start of .data when __data_start
|
||||
is referenced from code being linked.
|
||||
|
||||
Index: lld/ELF/Symbols.cpp
|
||||
--- lld/ELF/Symbols.cpp.orig
|
||||
+++ lld/ELF/Symbols.cpp
|
||||
@@ -48,6 +48,7 @@ std::string lld::toELFString(const Archive::Symbol &b)
|
||||
}
|
||||
|
||||
Defined *ElfSym::bss;
|
||||
+Defined *ElfSym::data;
|
||||
Defined *ElfSym::etext1;
|
||||
Defined *ElfSym::etext2;
|
||||
Defined *ElfSym::edata1;
|
53
devel/llvm/13/patches/patch-lld_ELF_Symbols_h
Normal file
53
devel/llvm/13/patches/patch-lld_ELF_Symbols_h
Normal file
|
@ -0,0 +1,53 @@
|
|||
- Generate __data_start symbol that marks the start of .data when __data_start
|
||||
is referenced from code being linked.
|
||||
- add .gnu.warning.SYMBOL support to ld.lld(1)
|
||||
|
||||
Index: lld/ELF/Symbols.h
|
||||
--- lld/ELF/Symbols.h.orig
|
||||
+++ lld/ELF/Symbols.h
|
||||
@@ -142,6 +142,9 @@ class Symbol { (public)
|
||||
// True if this symbol is specified by --trace-symbol option.
|
||||
uint8_t traced : 1;
|
||||
|
||||
+ // True if the .gnu.warning.SYMBOL is set for the symbol
|
||||
+ uint8_t gwarn : 1;
|
||||
+
|
||||
inline void replace(const Symbol &newSym);
|
||||
|
||||
bool includeInDynsym() const;
|
||||
@@ -247,7 +250,7 @@ class Symbol { (public)
|
||||
type(type), stOther(stOther), symbolKind(k), visibility(stOther & 3),
|
||||
isUsedInRegularObj(!file || file->kind() == InputFile::ObjKind),
|
||||
exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false),
|
||||
- canInline(false), referenced(false), traced(false), needsPltAddr(false),
|
||||
+ canInline(false), referenced(false), traced(false), gwarn(false), needsPltAddr(false),
|
||||
isInIplt(false), gotInIgot(false), isPreemptible(false),
|
||||
used(!config->gcSections), needsTocRestore(false),
|
||||
scriptDefined(false) {}
|
||||
@@ -436,6 +439,9 @@ struct ElfSym {
|
||||
// __bss_start
|
||||
static Defined *bss;
|
||||
|
||||
+ // __data_start
|
||||
+ static Defined *data;
|
||||
+
|
||||
// etext and _etext
|
||||
static Defined *etext1;
|
||||
static Defined *etext2;
|
||||
@@ -557,6 +563,7 @@ void Symbol::replace(const Symbol &newSym) {
|
||||
canInline = old.canInline;
|
||||
referenced = old.referenced;
|
||||
traced = old.traced;
|
||||
+ gwarn = old.gwarn;
|
||||
isPreemptible = old.isPreemptible;
|
||||
scriptDefined = old.scriptDefined;
|
||||
partition = old.partition;
|
||||
@@ -575,6 +582,8 @@ void Symbol::replace(const Symbol &newSym) {
|
||||
void maybeWarnUnorderableSymbol(const Symbol *sym);
|
||||
bool computeIsPreemptible(const Symbol &sym);
|
||||
void reportBackrefs();
|
||||
+
|
||||
+extern llvm::DenseMap<StringRef, StringRef> gnuWarnings;
|
||||
|
||||
// A mapping from a symbol to an InputFile referencing it backward. Used by
|
||||
// --warn-backrefs.
|
15
devel/llvm/13/patches/patch-lld_ELF_SyntheticSections_cpp
Normal file
15
devel/llvm/13/patches/patch-lld_ELF_SyntheticSections_cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
- Don't create IBT .plt if there are no PLT entries. Cherry picked from
|
||||
upstream.
|
||||
|
||||
Index: lld/ELF/SyntheticSections.cpp
|
||||
--- lld/ELF/SyntheticSections.cpp.orig
|
||||
+++ lld/ELF/SyntheticSections.cpp
|
||||
@@ -2729,6 +2729,8 @@ size_t IBTPltSection::getSize() const {
|
||||
return 16 + in.plt->getNumEntries() * target->pltEntrySize;
|
||||
}
|
||||
|
||||
+bool IBTPltSection::isNeeded() const { return in.plt->getNumEntries() > 0; }
|
||||
+
|
||||
// The string hash function for .gdb_index.
|
||||
static uint32_t computeGdbHash(StringRef s) {
|
||||
uint32_t h = 0;
|
14
devel/llvm/13/patches/patch-lld_ELF_SyntheticSections_h
Normal file
14
devel/llvm/13/patches/patch-lld_ELF_SyntheticSections_h
Normal file
|
@ -0,0 +1,14 @@
|
|||
- Don't create IBT .plt if there are no PLT entries. Cherry picked from
|
||||
upstream.
|
||||
|
||||
Index: lld/ELF/SyntheticSections.h
|
||||
--- lld/ELF/SyntheticSections.h.orig
|
||||
+++ lld/ELF/SyntheticSections.h
|
||||
@@ -769,6 +769,7 @@ class IBTPltSection : public SyntheticSection {
|
||||
public:
|
||||
IBTPltSection();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
+ bool isNeeded() const override;
|
||||
size_t getSize() const override;
|
||||
};
|
||||
|
112
devel/llvm/13/patches/patch-lld_ELF_Writer_cpp
Normal file
112
devel/llvm/13/patches/patch-lld_ELF_Writer_cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
- Merge '.openbsd.randomdata.*' sections into a single '.openbsd.randomdata'
|
||||
section when linking, as we do when using ld from binutils.
|
||||
- Generate __data_start symbol that marks the start of .data when __data_start
|
||||
is referenced from code being linked.
|
||||
- Put .got.plt in RELRO.
|
||||
- On i386, produce binaries that are compatible with our W^X implementation.
|
||||
- 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: lld/ELF/Writer.cpp
|
||||
--- lld/ELF/Writer.cpp.orig
|
||||
+++ lld/ELF/Writer.cpp
|
||||
@@ -145,7 +145,8 @@ StringRef elf::getOutputSectionName(const InputSection
|
||||
for (StringRef v :
|
||||
{".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
|
||||
".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
|
||||
- ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
|
||||
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab.",
|
||||
+ ".openbsd.randomdata.", ".openbsd.mutable." })
|
||||
if (isSectionPrefix(v, s->name))
|
||||
return v.drop_back();
|
||||
|
||||
@@ -324,6 +325,7 @@ void elf::addReservedSymbols() {
|
||||
};
|
||||
|
||||
ElfSym::bss = add("__bss_start", 0);
|
||||
+ ElfSym::data = add("__data_start", 0);
|
||||
ElfSym::end1 = add("end", -1);
|
||||
ElfSym::end2 = add("_end", -1);
|
||||
ElfSym::etext1 = add("etext", -1);
|
||||
@@ -883,7 +885,11 @@ static bool isRelroSection(const OutputSection *sec) {
|
||||
// However, if "-z now" is given, the lazy symbol resolution is
|
||||
// disabled, which enables us to put it into RELRO.
|
||||
if (sec == in.gotPlt->getParent())
|
||||
+#ifndef __OpenBSD__
|
||||
return config->zNow;
|
||||
+#else
|
||||
+ return true; /* kbind(2) means we can always put these in RELRO */
|
||||
+#endif
|
||||
|
||||
// .dynamic section contains data for the dynamic linker, and
|
||||
// there's no need to write to it at runtime, so it's better to put
|
||||
@@ -1193,6 +1199,9 @@ template <class ELFT> void Writer<ELFT>::setReservedSy
|
||||
if (ElfSym::bss)
|
||||
ElfSym::bss->section = findSection(".bss");
|
||||
|
||||
+ if (ElfSym::data)
|
||||
+ ElfSym::data->section = findSection(".data");
|
||||
+
|
||||
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
|
||||
// be equal to the _gp symbol's value.
|
||||
if (ElfSym::mipsGp) {
|
||||
@@ -2461,6 +2470,12 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Par
|
||||
addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags())
|
||||
->add(part.ehFrameHdr->getParent());
|
||||
|
||||
+ // PT_OPENBSD_MUTABLE is an OpenBSD-specific feature. That makes
|
||||
+ // the dynamic linker fill the segment with zero data, like bss, but
|
||||
+ // it can be treated differently.
|
||||
+ if (OutputSection *cmd = findSection(".openbsd.mutable", partNo))
|
||||
+ addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd);
|
||||
+
|
||||
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
|
||||
// the dynamic linker fill the segment with random data.
|
||||
if (OutputSection *cmd = findSection(".openbsd.randomdata", partNo))
|
||||
@@ -2484,6 +2499,11 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Par
|
||||
if (config->zWxneeded)
|
||||
addHdr(PT_OPENBSD_WXNEEDED, PF_X);
|
||||
|
||||
+ // PT_OPENBSD_NOBTCFI is an OpenBSD-specific header to mark that the
|
||||
+ // executable is expected to violate branch-target CFI checks.
|
||||
+ if (config->zNoBtCfi)
|
||||
+ addHdr(PT_OPENBSD_NOBTCFI, PF_X);
|
||||
+
|
||||
if (OutputSection *cmd = findSection(".note.gnu.property", partNo))
|
||||
addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd);
|
||||
|
||||
@@ -2576,6 +2596,31 @@ template <class ELFT> void Writer<ELFT>::fixSectionAli
|
||||
};
|
||||
}
|
||||
};
|
||||
+
|
||||
+#ifdef __OpenBSD__
|
||||
+ // On i386, produce binaries that are compatible with our W^X implementation
|
||||
+ if (config->emachine == EM_386) {
|
||||
+ auto NXAlign = [](OutputSection *Cmd) {
|
||||
+ if (Cmd && !Cmd->addrExpr)
|
||||
+ Cmd->addrExpr = [=] {
|
||||
+ return alignTo(script->getDot(), 0x20000000);
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ for (Partition &part : partitions) {
|
||||
+ PhdrEntry *firstRW = nullptr;
|
||||
+ for (PhdrEntry *P : part.phdrs) {
|
||||
+ if (P->p_type == PT_LOAD && (P->p_flags & PF_W)) {
|
||||
+ firstRW = P;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (firstRW)
|
||||
+ NXAlign(firstRW->firstSec);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
for (Partition &part : partitions) {
|
||||
prev = nullptr;
|
14
devel/llvm/13/patches/patch-lld_ELF_Writer_h
Normal file
14
devel/llvm/13/patches/patch-lld_ELF_Writer_h
Normal file
|
@ -0,0 +1,14 @@
|
|||
- XXX no comment
|
||||
|
||||
Index: lld/ELF/Writer.h
|
||||
--- lld/ELF/Writer.h.orig
|
||||
+++ lld/ELF/Writer.h
|
||||
@@ -30,7 +30,7 @@ template <class ELFT> void writeResult();
|
||||
// placed in it.
|
||||
struct PhdrEntry {
|
||||
PhdrEntry(unsigned type, unsigned flags)
|
||||
- : p_align(type == llvm::ELF::PT_LOAD ? config->maxPageSize : 0),
|
||||
+ : p_align(type == llvm::ELF::PT_LOAD ? config->textAlignPageSize : 0),
|
||||
p_type(type), p_flags(flags) {}
|
||||
void add(OutputSection *sec);
|
||||
|
29
devel/llvm/13/patches/patch-lld_docs_ld_lld_1
Normal file
29
devel/llvm/13/patches/patch-lld_docs_ld_lld_1
Normal file
|
@ -0,0 +1,29 @@
|
|||
- sync --execute-only archs described in the manual with current code
|
||||
- add note about nobtcfi
|
||||
|
||||
Index: lld/docs/ld.lld.1
|
||||
--- lld/docs/ld.lld.1.orig
|
||||
+++ lld/docs/ld.lld.1
|
||||
@@ -212,7 +212,9 @@ followed by the name of the missing library.
|
||||
followed by the name of the undefined symbol.
|
||||
.It Fl -execute-only
|
||||
Mark executable sections unreadable.
|
||||
-This option is currently only supported on AArch64.
|
||||
+This option is currently supported on x86-32, x86-64 (default),
|
||||
+AArch64 (default), MIPS64, PowerPC32 (default), PowerPC64 (default),
|
||||
+RISC-V (default), and SPARC64 (default).
|
||||
.It Fl -exclude-libs Ns = Ns Ar value
|
||||
Exclude static libraries from automatic export.
|
||||
.It Fl -export-dynamic , Fl E
|
||||
@@ -830,6 +832,11 @@ This is the default.
|
||||
.It Cm wxneeded
|
||||
Create a
|
||||
.Dv PT_OPENBSD_WXNEEDED
|
||||
+segment.
|
||||
+.Pp
|
||||
+.It Cm nobtcfi
|
||||
+Create a
|
||||
+.Dv PT_OPENBSD_NOBTCFI
|
||||
segment.
|
||||
.El
|
||||
.El
|
14
devel/llvm/13/patches/patch-lld_tools_lld_CMakeLists_txt
Normal file
14
devel/llvm/13/patches/patch-lld_tools_lld_CMakeLists_txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
Don't build MachO2 support in lld. This code reaches into libunwind
|
||||
internals.
|
||||
|
||||
Index: lld/tools/lld/CMakeLists.txt
|
||||
--- lld/tools/lld/CMakeLists.txt.orig
|
||||
+++ lld/tools/lld/CMakeLists.txt
|
||||
@@ -15,7 +15,6 @@ target_link_libraries(lld
|
||||
lldCOFF
|
||||
lldDriver
|
||||
lldELF
|
||||
- lldMachO2
|
||||
lldMinGW
|
||||
lldWasm
|
||||
)
|
19
devel/llvm/13/patches/patch-lld_tools_lld_lld_cpp
Normal file
19
devel/llvm/13/patches/patch-lld_tools_lld_lld_cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
Don't build MachO2 support in lld. This code reaches into libunwind
|
||||
internals.
|
||||
|
||||
Index: lld/tools/lld/lld.cpp
|
||||
--- lld/tools/lld/lld.cpp.orig
|
||||
+++ lld/tools/lld/lld.cpp
|
||||
@@ -148,10 +148,12 @@ static int lldMain(int argc, const char **argv, llvm::
|
||||
return !elf::link(args, exitEarly, stdoutOS, stderrOS);
|
||||
case WinLink:
|
||||
return !coff::link(args, exitEarly, stdoutOS, stderrOS);
|
||||
+#if 0
|
||||
case Darwin:
|
||||
return !macho::link(args, exitEarly, stdoutOS, stderrOS);
|
||||
case DarwinOld:
|
||||
return !mach_o::link(args, exitEarly, stdoutOS, stderrOS);
|
||||
+#endif
|
||||
case Wasm:
|
||||
return !lld::wasm::link(args, exitEarly, stdoutOS, stderrOS);
|
||||
default:
|
15
devel/llvm/13/patches/patch-lldb_bindings_CMakeLists_txt
Normal file
15
devel/llvm/13/patches/patch-lldb_bindings_CMakeLists_txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Fix build with swig 4.1.0
|
||||
cf https://reviews.llvm.org/D134877
|
||||
cf https://bugzilla.redhat.com/show_bug.cgi?id=2128646
|
||||
Index: lldb/bindings/CMakeLists.txt
|
||||
--- lldb/bindings/CMakeLists.txt.orig
|
||||
+++ lldb/bindings/CMakeLists.txt
|
||||
@@ -26,8 +26,6 @@ set(SWIG_COMMON_FLAGS
|
||||
-features autodoc
|
||||
-I${LLDB_SOURCE_DIR}/include
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}
|
||||
- -D__STDC_LIMIT_MACROS
|
||||
- -D__STDC_CONSTANT_MACROS
|
||||
${DARWIN_EXTRAS}
|
||||
)
|
||||
|
15
devel/llvm/13/patches/patch-lldb_bindings_interfaces_swig
Normal file
15
devel/llvm/13/patches/patch-lldb_bindings_interfaces_swig
Normal file
|
@ -0,0 +1,15 @@
|
|||
Fix build with swig 4.1.0
|
||||
cf https://reviews.llvm.org/D134877
|
||||
cf https://bugzilla.redhat.com/show_bug.cgi?id=2128646
|
||||
Index: lldb/bindings/interfaces.swig
|
||||
--- lldb/bindings/interfaces.swig.orig
|
||||
+++ lldb/bindings/interfaces.swig
|
||||
@@ -1,8 +1,5 @@
|
||||
/* Various liblldb typedefs that SWIG needs to know about. */
|
||||
#define __extension__ /* Undefine GCC keyword to make Swig happy when processing glibc's stdint.h. */
|
||||
-/* The ISO C99 standard specifies that in C++ implementations limit macros such
|
||||
- as INT32_MAX should only be defined if __STDC_LIMIT_MACROS is. */
|
||||
-#define __STDC_LIMIT_MACROS
|
||||
%include "stdint.i"
|
||||
|
||||
%include "lldb/lldb-defines.h"
|
|
@ -0,0 +1,15 @@
|
|||
fix build with swig 4.1.0
|
||||
https://github.com/llvm/llvm-project/commit/f0a25fe0b746f56295d5c02116ba28d2f965c175
|
||||
|
||||
Index: lldb/bindings/python/python-typemaps.swig
|
||||
--- lldb/bindings/python/python-typemaps.swig.orig
|
||||
+++ lldb/bindings/python/python-typemaps.swig
|
||||
@@ -439,7 +439,7 @@ bool SetNumberFromPyObject<double>(double &number, PyO
|
||||
|
||||
%typemap(out) lldb::FileSP {
|
||||
$result = nullptr;
|
||||
- lldb::FileSP &sp = $1;
|
||||
+ const lldb::FileSP &sp = $1;
|
||||
if (sp) {
|
||||
PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp));
|
||||
if (!pyfile.IsValid())
|
|
@ -0,0 +1,32 @@
|
|||
Skip retguard instructions in prologue detection.
|
||||
|
||||
Index: lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
|
||||
--- lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp.orig
|
||||
+++ lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
|
||||
@@ -870,6 +870,18 @@ int16_t x86AssemblyInspectionEngine::extract_2_signed(
|
||||
return v;
|
||||
}
|
||||
|
||||
+// movq $0x????????(%rip), $reg [(0x4c || 0x48) 0x8b ?? ?? ?? ?? ??]
|
||||
+// xorq $off(%rsp), $reg [(0x4c || 0x48) 0x33 ?? 0x24]
|
||||
+bool x86AssemblyInspectionEngine::retguard_prologue_p(size_t offset, int insn_len) {
|
||||
+ uint8_t *p = m_cur_insn;
|
||||
+ if (offset == 0 && insn_len == 7)
|
||||
+ return (*p == 0x48 || *p == 0x4c) && (*(p + 1) == 0x8b);
|
||||
+ else if (offset == 7 && insn_len == 4)
|
||||
+ return (*p == 0x48 || *p == 0x4c) && (*(p + 1) == 0x33) && (*(p + 3) == 0x24);
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {
|
||||
uint32_t v = 0;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
@@ -1601,6 +1613,7 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologue
|
||||
if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||
|
||||
sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||
|
||||
mov_reg_to_local_stack_frame_p(regno, scratch) ||
|
||||
+ retguard_prologue_p(offset, insn_len) ||
|
||||
(lea_rsp_pattern_p(scratch) && offset == 0)) {
|
||||
offset += insn_len;
|
||||
continue;
|
|
@ -0,0 +1,13 @@
|
|||
Skip retguard instructions in prologue detection.
|
||||
|
||||
Index: lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
|
||||
--- lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h.orig
|
||||
+++ lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
|
||||
@@ -114,6 +114,7 @@ class x86AssemblyInspectionEngine { (private)
|
||||
bool call_next_insn_pattern_p();
|
||||
bool mov_reg_to_local_stack_frame_p(int ®no, int &rbp_offset);
|
||||
bool ret_pattern_p();
|
||||
+ bool retguard_prologue_p(size_t offset, int insn_len);
|
||||
bool jmp_to_reg_p();
|
||||
bool pc_rel_branch_or_jump_p (const int instruction_length, int &offset);
|
||||
bool non_local_branch_p (const lldb::addr_t current_func_text_offset,
|
|
@ -0,0 +1,14 @@
|
|||
Properly parse library suffixes on OpenBSD
|
||||
|
||||
Index: llvm/cmake/modules/GetLibraryName.cmake
|
||||
--- llvm/cmake/modules/GetLibraryName.cmake.orig
|
||||
+++ llvm/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: llvm/cmake/modules/LLVMProcessSources.cmake
|
||||
--- llvm/cmake/modules/LLVMProcessSources.cmake.orig
|
||||
+++ llvm/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")
|
|
@ -0,0 +1,21 @@
|
|||
- support more than one input file in llvm-ranlib
|
||||
|
||||
Index: llvm/docs/CommandGuide/llvm-ranlib.rst
|
||||
--- llvm/docs/CommandGuide/llvm-ranlib.rst.orig
|
||||
+++ llvm/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``.
|
|
@ -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: llvm/include/llvm/BinaryFormat/ELF.h
|
||||
--- llvm/include/llvm/BinaryFormat/ELF.h.orig
|
||||
+++ llvm/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.
|
|
@ -0,0 +1,29 @@
|
|||
Use int3 trap padding between functions instead of trapsleds with a leading jump.
|
||||
|
||||
Index: llvm/include/llvm/CodeGen/AsmPrinter.h
|
||||
--- llvm/include/llvm/CodeGen/AsmPrinter.h.orig
|
||||
+++ llvm/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: llvm/include/llvm/CodeGen/MachineFrameInfo.h
|
||||
--- llvm/include/llvm/CodeGen/MachineFrameInfo.h.orig
|
||||
+++ llvm/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.
|
|
@ -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: llvm/include/llvm/CodeGen/Passes.h
|
||||
--- llvm/include/llvm/CodeGen/Passes.h.orig
|
||||
+++ llvm/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: llvm/include/llvm/CodeGen/ReturnProtectorLowering.h
|
||||
--- llvm/include/llvm/CodeGen/ReturnProtectorLowering.h.orig
|
||||
+++ llvm/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: llvm/include/llvm/CodeGen/TargetFrameLowering.h
|
||||
--- llvm/include/llvm/CodeGen/TargetFrameLowering.h.orig
|
||||
+++ llvm/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.
|
|
@ -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: llvm/include/llvm/InitializePasses.h
|
||||
--- llvm/include/llvm/InitializePasses.h.orig
|
||||
+++ llvm/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: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
|
||||
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp.orig
|
||||
+++ llvm/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/13/patches/patch-llvm_lib_CodeGen_CMakeLists_txt
Normal file
31
devel/llvm/13/patches/patch-llvm_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: llvm/lib/CodeGen/CMakeLists.txt
|
||||
--- llvm/lib/CodeGen/CMakeLists.txt.orig
|
||||
+++ llvm/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: llvm/lib/CodeGen/PrologEpilogInserter.cpp
|
||||
--- llvm/lib/CodeGen/PrologEpilogInserter.cpp.orig
|
||||
+++ llvm/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.
|
|
@ -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: llvm/lib/CodeGen/ReturnProtectorLowering.cpp
|
||||
--- llvm/lib/CodeGen/ReturnProtectorLowering.cpp.orig
|
||||
+++ llvm/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);
|
||||
+}
|
|
@ -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: llvm/lib/CodeGen/ReturnProtectorPass.cpp
|
||||
--- llvm/lib/CodeGen/ReturnProtectorPass.cpp.orig
|
||||
+++ llvm/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(); }
|
|
@ -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: llvm/lib/CodeGen/TargetPassConfig.cpp
|
||||
--- llvm/lib/CodeGen/TargetPassConfig.cpp.orig
|
||||
+++ llvm/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/13/patches/patch-llvm_lib_MC_MCAsmInfoELF_cpp
Normal file
14
devel/llvm/13/patches/patch-llvm_lib_MC_MCAsmInfoELF_cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
Do not use ident.
|
||||
|
||||
Index: llvm/lib/MC/MCAsmInfoELF.cpp
|
||||
--- llvm/lib/MC/MCAsmInfoELF.cpp.orig
|
||||
+++ llvm/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/13/patches/patch-llvm_lib_MC_MCELFStreamer_cpp
Normal file
19
devel/llvm/13/patches/patch-llvm_lib_MC_MCELFStreamer_cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
getNonexecutableStackSection() may return nullptr.
|
||||
|
||||
Index: llvm/lib/MC/MCELFStreamer.cpp
|
||||
--- llvm/lib/MC/MCELFStreamer.cpp.orig
|
||||
+++ llvm/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) {
|
|
@ -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: llvm/lib/MC/MCParser/AsmParser.cpp
|
||||
--- llvm/lib/MC/MCParser/AsmParser.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64FrameLowering.h
|
||||
--- llvm/lib/Target/AArch64/AArch64FrameLowering.h.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64InstrInfo.td
|
||||
--- llvm/lib/Target/AArch64/AArch64InstrInfo.td.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64ReturnProtectorLowering.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64ReturnProtectorLowering.h
|
||||
--- llvm/lib/Target/AArch64/AArch64ReturnProtectorLowering.h.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64Subtarget.h
|
||||
--- llvm/lib/Target/AArch64/AArch64Subtarget.h.orig
|
||||
+++ llvm/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: llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
|
||||
--- llvm/lib/Target/AArch64/AArch64TargetMachine.cpp.orig
|
||||
+++ llvm/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())) {
|
|
@ -0,0 +1,13 @@
|
|||
Add retguard for arm64.
|
||||
|
||||
Index: llvm/lib/Target/AArch64/CMakeLists.txt
|
||||
--- llvm/lib/Target/AArch64/CMakeLists.txt.orig
|
||||
+++ llvm/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,84 @@
|
|||
Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
|
||||
|
||||
Index: llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
|
||||
--- llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp.orig
|
||||
+++ llvm/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,20 @@ 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;
|
||||
+ LLVM_FALLTHROUGH;
|
||||
+ 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 +3352,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;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
|
||||
- Add retguard for octeon/mips64.
|
||||
|
||||
Index: llvm/lib/Target/Mips/CMakeLists.txt
|
||||
--- llvm/lib/Target/Mips/CMakeLists.txt.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
|
||||
--- llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp.orig
|
||||
+++ llvm/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};
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
- Add retguard for octeon/mips64.
|
||||
|
||||
Index: llvm/lib/Target/Mips/MipsAsmPrinter.cpp
|
||||
--- llvm/lib/Target/Mips/MipsAsmPrinter.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MipsFrameLowering.cpp
|
||||
--- llvm/lib/Target/Mips/MipsFrameLowering.cpp.orig
|
||||
+++ llvm/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;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
Add retguard for octeon/mips64.
|
||||
|
||||
Index: llvm/lib/Target/Mips/MipsFrameLowering.h
|
||||
--- llvm/lib/Target/Mips/MipsFrameLowering.h.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MipsISelLowering.cpp
|
||||
--- llvm/lib/Target/Mips/MipsISelLowering.cpp.orig
|
||||
+++ llvm/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)
|
|
@ -0,0 +1,37 @@
|
|||
- Add retguard for octeon/mips64.
|
||||
|
||||
Index: llvm/lib/Target/Mips/MipsInstrInfo.td
|
||||
--- llvm/lib/Target/Mips/MipsInstrInfo.td.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MipsLoongson2FBTBFix.cpp
|
||||
--- llvm/lib/Target/Mips/MipsLoongson2FBTBFix.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp
|
||||
--- llvm/lib/Target/Mips/MipsReturnProtectorLowering.cpp.orig
|
||||
+++ llvm/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: llvm/lib/Target/Mips/MipsReturnProtectorLowering.h
|
||||
--- llvm/lib/Target/Mips/MipsReturnProtectorLowering.h.orig
|
||||
+++ llvm/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
|
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