sync ports with The Matrix

This commit is contained in:
purplerain 2023-09-08 05:21:37 +00:00
parent ec769495ab
commit f5034afcba
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
3108 changed files with 91999 additions and 80269 deletions

18
devel/llvm/13/Makefile Normal file
View 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
View 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

View file

@ -0,0 +1,20 @@
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length specifiers
and type check like it is used by the regular case.
Index: 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;
}

View file

@ -0,0 +1,32 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Disable strict floating point if not X86.
Index: 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)

View file

@ -0,0 +1,72 @@
- Disable -Waddress-of-packed-member by default.
While these warnings have the potential to be useful, there are too many
false positives right now.
- Disable -Wpointer-sign warnings per default
base gcc does the same.
- Add a new warning for %n format specifier usage in printf(3) family functions
- allow out-of-class defaulting of comparison operators
this is backport of the following upstream commit:
commit 5fbe21a7748f91adbd1b16c95bbfe180642320a3
Index: 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<

View file

@ -0,0 +1,53 @@
- Add ret protector options as no-ops.
- Improve the X86FixupGadgets pass
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
- Alias the command line parameter -p to -pg.
- implement -msave-args in clang/llvm, like the sun did for gcc
Index: 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>;

View 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);

View file

@ -0,0 +1,37 @@
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length specifiers
and type check like it is used by the regular case.
Index: 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;

View 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.

View file

@ -0,0 +1,20 @@
- Implement the 'h' register constraint on mips64. This lets clang build
pieces of software that use the constraint if the compiler claims
to be compatible with GCC 4.2.1.
Note that the constraint was removed in GCC 4.4. The reason was that
'h' could generate code whose result is unpredictable. The underlying
reason is that the HI and LO registers are special, and the optimizer
has to be careful when choosing the order of HI/LO accesses. It looks
that LLVM has the needed logic.
Index: 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();

View 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)

View 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

View file

@ -0,0 +1,31 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: 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.

View file

@ -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;
}

View 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;
};

View file

@ -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.

View file

@ -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)) {

View file

@ -0,0 +1,188 @@
- Switch Powerpc64 Big Endian to ELFv2 on OpenBSD.
- Adapt the -mfix-loongson2f-btb workaround from as(1) to LLVM/clang.
- Disable -fstrict-aliasing per default on OpenBSD.
- Enable -fwrapv by default
- Add ret protector options as no-ops.
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Add retguard for arm64.
- Add retguard for octeon/mips64.
- Add RETGUARD implementation for powerpc and powerpc64.
- Improve the X86FixupGadgets pass
- On OpenBSD disable the malloc/calloc/realloc/free/str*dup builtins, since
they can perform strange transforms and optimizations. Some of those could
gain a slight advantage, but would avoid the variety of important runtime
checks our malloc(3) code does. In essence, the transforms performed are
considered "anti-mitigation".
- Make -mbranch-protection=bti the default on OpenBSD.
- On openbsd amd64, emit IBT endbr64 instructions by default (meaning,
-fcf-protection=branch is the default).
- On openbsd amd64, the compiler has been found to generate some nasty jump
table variations (calculate address into %rax, jmp %rax) which is not
compatible with IBT endbr64. So we will have to disable jump tables by
default.
- Turn on pointer-authentication on arm64 as well by default. This means
we effectively enable -mbranch-protection=standard on arm64 now.
- Make sure -msign-return-address doesn't disable BTI support.
Index: 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.

View file

@ -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;

View file

@ -0,0 +1,156 @@
- Add support for building against libestdc++ from ports-gcc.
- Allow the compiler driver to link the libclang_rt.profile library.
- Use Component in OpenBSD::getCompilerRT to find libraries.
- Enable kernel-address sanitizer for clang openbsd target
Index: 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;
+ }
+}

View file

@ -0,0 +1,30 @@
- Add support for building against libestdc++ from ports-gcc.
- Enable unwind tables on all clang architectures.
- Arm is not ready for unwinding yet. Disable unwind info generation for now.
Index: 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 {

View file

@ -0,0 +1,41 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: 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)) {

View file

@ -0,0 +1,108 @@
- Teach Clang about syslog format attribute
- Enable the kprintf format attribute
- The %b printf extension in the kernel is not fixed to a int type. On sparc64
there are various %llb formats. Adjust the code to handle the length
specifiers and type check like it is used by the regular case.
- Add a new warning for %n format specifier usage in printf(3) family functions
Index: 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,

View 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);

View file

@ -0,0 +1,266 @@
- allow out-of-class defaulting of comparison operators
this is backport of the following upstream commit:
commit 5fbe21a7748f91adbd1b16c95bbfe180642320a3
Index: 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) {

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -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()

View file

@ -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/) {

View 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)

View 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(); }

View file

@ -0,0 +1,59 @@
- Change the emitted .glink stub on powerpc64 to use an instruction sequence
to compose the offset to the PLT instead of having a constant pool in .text.
Make --execute-only work on powerpc64.
Index: 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,

View 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) +

View 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() {

View 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;

View 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;
}

View 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);

View 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;

View 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;

View 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)

View 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">;

View 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;
}

View 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)

View 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;

View 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;

View 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.

View 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;

View 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;
};

View 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;

View 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);

View 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

View 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
)

View 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:

View 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}
)

View 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"

View file

@ -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())

View file

@ -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;

View file

@ -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 &regno, 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,

View file

@ -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)

View file

@ -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")

View file

@ -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``.

View file

@ -0,0 +1,20 @@
- In the linkers, collect objects in section "openbsd.mutable" and place
them into a page-aligned region in the bss, with the right markers for
kernel/ld.so to identify the region and skip making it immutable.
- Implement support for PT_OPENBSD_NOBTCFI in lld(1). This can be set using
the -z nobtcfi option.
Index: 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.

View file

@ -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;

View file

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

View file

@ -0,0 +1,31 @@
Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
Index: 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.
///

View file

@ -0,0 +1,88 @@
- Refactor retguard to make adding additional arches easier.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: 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

View file

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

View file

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

View file

@ -0,0 +1,68 @@
- Use int3 trap padding between functions instead of trapsleds with a leading jump.
- Emit trap alignment between basic blocks that are unreachable via
fallthrough. Avoids unnecessary jmp instructions in the middle
of functions and makes disassembly nicer to read.
Index: 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

View file

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

View file

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

View file

@ -0,0 +1,348 @@
- Refactor retguard to make adding additional arches easier.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: 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);
+}

View file

@ -0,0 +1,91 @@
- Add RETGUARD to clang for amd64. This security mechanism uses per-function
random cookies to protect access to function return instructions, with the
effect that the integrity of the return address is protected, and function
return instructions are harder to use in ROP gadgets.
On function entry the return address is combined with a per-function random
cookie and stored in the stack frame. The integrity of this value is verified
before function return, and if this check fails, the program aborts. In this way
RETGUARD is an improved stack protector, since the cookies are per-function. The
verification routine is constructed such that the binary space immediately
before each ret instruction is padded with int03 instructions, which makes these
return instructions difficult to use in ROP gadgets. In the kernel, this has the
effect of removing approximately 50% of total ROP gadgets, and 15% of unique
ROP gadgets compared to the 6.3 release kernel. Function epilogues are
essentially gadget free, leaving only the polymorphic gadgets that result from
jumping into the instruction stream partway through other instructions. Work to
remove these gadgets will continue through other mechanisms.
- Put the new retguard symbols in their own section,
'.openbsd.randomdata.retguard', to make them easier to work with in the
kernel hibernate code.
- Move the hashed __retguard_* symbols into individual sections and mark
them as COMDATs so that the linker can individually discard them, instead
of just ignoring duplicate symbols but keep the (duplicate) space.
Index: 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(); }

View file

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

View 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";

View 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) {

View file

@ -0,0 +1,22 @@
make clang include a FILE symbol for .(s|S) files
This is mostly needed by syspatch at the moment to be
to be able to re-link in the same order as the original
libraries were linked with by relying on the readelf(1)
and without this .(s|S) assembly files were not getting
a file directive.
Index: 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.

View file

@ -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.

View file

@ -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 {

View file

@ -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;

View file

@ -0,0 +1,17 @@
Disable the Load Stack Guard for OpenBSD on AArch64. We don't use it
on any other platform and it causes a segfault in combination with our
IR Stack Guard.
Index: 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;
}

View file

@ -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

View file

@ -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)>;

View file

@ -0,0 +1,135 @@
- Add retguard for arm64.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
- Fix frame pointer slot on aarch64 for functions that do not save callee
registers with retguard enabled.
Index: 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()));
+}

View file

@ -0,0 +1,61 @@
- Add retguard for arm64.
- Do not store the retguard cookie in frame in leaf functions if possible.
Makes things slightly faster and also improves security in these functions,
since the retguard cookie can't leak via the stack.
Index: 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

View file

@ -0,0 +1,15 @@
Disable the Load Stack Guard for OpenBSD on AArch64. We don't use it
on any other platform and it causes a segfault in combination with our
IR Stack Guard.
Index: 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(); }

View file

@ -0,0 +1,15 @@
Always disable GlobalISel on aarch64, fixes a crash when building on
aarch64 without retguard, with a stack protector and without
optimizations.
Index: 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())) {

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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};

View file

@ -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 &&

View file

@ -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;
}

View file

@ -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,

View file

@ -0,0 +1,48 @@
- Implement the 'h' register constraint on mips64. This lets clang build
pieces of software that use the constraint if the compiler claims
to be compatible with GCC 4.2.1.
Note that the constraint was removed in GCC 4.4. The reason was that
'h' could generate code whose result is unpredictable. The underlying
reason is that the HI and LO registers are special, and the optimizer
has to be careful when choosing the order of HI/LO accesses. It looks
that LLVM has the needed logic.
Index: 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)

View file

@ -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
//===----------------------------------------------------------------------===//

View file

@ -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;
+}

View file

@ -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);
+}

View file

@ -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