Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/Frontend/Debug/Options.h"
#include "llvm/Frontend/Driver/CodeGenOptions.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Hash.h"
#include "llvm/Support/Regex.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
Expand Down Expand Up @@ -514,6 +515,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// binary metadata pass should not be instrumented.
std::vector<std::string> SanitizeMetadataIgnorelistFiles;

/// Hash algorithm to use for KCFI type IDs.
llvm::KCFIHashAlgorithm SanitizeKcfiHash;

/// Name of the stack usage file (i.e., .su file) if user passes
/// -fstack-usage. If empty, it can be implied that -fstack-usage is not
/// passed on the command line.
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Options/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2690,6 +2690,16 @@ def fsanitize_kcfi_arity : Flag<["-"], "fsanitize-kcfi-arity">,
Group<f_clang_Group>,
HelpText<"Embed function arity information into the KCFI patchable function prefix">,
MarshallingInfoFlag<CodeGenOpts<"SanitizeKcfiArity">>;
def fsanitize_kcfi_hash_EQ
: Joined<["-"], "fsanitize-kcfi-hash=">,
HelpText<"Select hash algorithm for KCFI type IDs (xxHash64, FNV-1a)">,
Visibility<[ClangOption, CC1Option]>,
Values<"xxHash64,FNV-1a">,
NormalizedValuesScope<"llvm">,
NormalizedValues<["KCFIHashAlgorithm::xxHash64",
"KCFIHashAlgorithm::FNV1a"]>,
MarshallingInfoEnum<CodeGenOpts<"SanitizeKcfiHash">,
"KCFIHashAlgorithm::xxHash64">;
defm sanitize_stats : BoolOption<"f", "sanitize-stats",
CodeGenOpts<"SanitizeStats">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Enable">,
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Hash.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include "llvm/Transforms/Instrumentation/KCFI.h"
#include "llvm/Transforms/Utils/BuildLibCalls.h"
#include <optional>
#include <set>
Expand Down Expand Up @@ -1272,6 +1273,12 @@ void CodeGenModule::Release() {
CodeGenOpts.PatchableFunctionEntryOffset);
if (CodeGenOpts.SanitizeKcfiArity)
getModule().addModuleFlag(llvm::Module::Override, "kcfi-arity", 1);
// Store the hash algorithm choice for use in LLVM passes
getModule().addModuleFlag(
llvm::Module::Override, "kcfi-hash",
llvm::MDString::get(
getLLVMContext(),
llvm::stringifyKCFIHashAlgorithm(CodeGenOpts.SanitizeKcfiHash)));
}

if (CodeGenOpts.CFProtectionReturn &&
Expand Down Expand Up @@ -2434,8 +2441,8 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T, StringRef Salt) {
if (getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
Out << ".generalized";

return llvm::ConstantInt::get(Int32Ty,
static_cast<uint32_t>(llvm::xxHash64(OutName)));
return llvm::ConstantInt::get(
Int32Ty, llvm::getKCFITypeID(OutName, getCodeGenOpts().SanitizeKcfiHash));
}

void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
Expand Down Expand Up @@ -3189,7 +3196,8 @@ void CodeGenModule::finalizeKCFITypes() {
continue;

std::string Asm = (".weak __kcfi_typeid_" + Name + "\n.set __kcfi_typeid_" +
Name + ", " + Twine(Type->getZExtValue()) + "\n")
Name + ", " + Twine(Type->getZExtValue()) + " # " +
Twine(Type->getSExtValue()) + "\n")
.str();
M.appendModuleInlineAsm(Asm);
}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/cfi-salt.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ typedef unsigned int (* __cfi_salt ufn_salt_t)(void);

/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], [[#%d,LOW_SODIUM_HASH:]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], {{[0-9]+}} # [[#%d,LOW_SODIUM_HASH:]]"
// CHECK: module asm ".weak __kcfi_typeid_[[F4_SALT:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4_SALT]], [[#%d,ASM_SALTY_HASH:]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4_SALT]], {{[0-9]+}} # [[#%d,ASM_SALTY_HASH:]]"

/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_f6"
Expand Down
9 changes: 9 additions & 0 deletions clang/test/CodeGen/kcfi-hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -o - %s | FileCheck --check-prefix=DEFAULT %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-hash=xxHash64 -o - %s | FileCheck --check-prefix=XXHASH %s
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-kcfi-hash=FNV-1a -o - %s | FileCheck --check-prefix=FNV %s

void foo(void) {}

// DEFAULT: ![[#]] = !{i32 4, !"kcfi-hash", !"xxHash64"}
// XXHASH: ![[#]] = !{i32 4, !"kcfi-hash", !"xxHash64"}
// FNV: ![[#]] = !{i32 4, !"kcfi-hash", !"FNV-1a"}
2 changes: 1 addition & 1 deletion clang/test/CodeGen/kcfi.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], [[#%d,HASH:]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], {{[0-9]+}} # [[#%d,HASH:]]"
/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_{{f6|_Z2f6v}}"

Expand Down
38 changes: 38 additions & 0 deletions llvm/include/llvm/Support/Hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===- llvm/Support/Hash.h - Hash functions --------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file provides hash functions.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_HASH_H
#define LLVM_SUPPORT_HASH_H

#include "llvm/ADT/StringRef.h"
#include <cstdint>

namespace llvm {

enum class KCFIHashAlgorithm { xxHash64, FNV1a };

/// Parse a KCFI hash algorithm name.
/// Returns xxHash64 if the name is not recognized.
KCFIHashAlgorithm parseKCFIHashAlgorithm(StringRef Name);

/// Convert a KCFI hash algorithm enum to its string representation.
StringRef stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm);

/// Compute KCFI type ID from mangled type name.
/// The algorithm can be xxHash64 or FNV-1a.
uint32_t
getKCFITypeID(StringRef MangledTypeName,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we leave out the default argument? then we make sure we don't forget to think about the type id anywhere

KCFIHashAlgorithm Algorithm = KCFIHashAlgorithm::xxHash64);

} // end namespace llvm

#endif // LLVM_SUPPORT_HASH_H
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ add_llvm_component_library(LLVMSupport
FormatVariadic.cpp
GlobPattern.cpp
GraphWriter.cpp
Hash.cpp
HexagonAttributeParser.cpp
HexagonAttributes.cpp
InitLLVM.cpp
Expand Down
51 changes: 51 additions & 0 deletions llvm/lib/Support/Hash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//===- Hash.cpp - Hash functions ---------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements hash functions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Hash.h"
#include "llvm/Support/xxhash.h"

using namespace llvm;

KCFIHashAlgorithm llvm::parseKCFIHashAlgorithm(StringRef Name) {
if (Name == "FNV-1a")
return KCFIHashAlgorithm::FNV1a;
// Default to xxHash64 for backward compatibility
return KCFIHashAlgorithm::xxHash64;
}

StringRef llvm::stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm) {
switch (Algorithm) {
case KCFIHashAlgorithm::xxHash64:
return "xxHash64";
case KCFIHashAlgorithm::FNV1a:
return "FNV-1a";
}
llvm_unreachable("Unknown KCFI hash algorithm");
}

uint32_t llvm::getKCFITypeID(StringRef MangledTypeName,
KCFIHashAlgorithm Algorithm) {
switch (Algorithm) {
case KCFIHashAlgorithm::xxHash64:
// Use lower 32 bits of xxHash64
return static_cast<uint32_t>(xxHash64(MangledTypeName));
case KCFIHashAlgorithm::FNV1a:
// FNV-1a hash (32-bit)
uint32_t Hash = 2166136261u; // FNV offset basis
for (unsigned char C : MangledTypeName) {
Hash ^= C;
Hash *= 16777619u; // FNV prime
}
return Hash;
}
llvm_unreachable("Unknown KCFI hash algorithm");
}
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Instrumentation/KCFI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/xxhash.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

Expand Down
13 changes: 10 additions & 3 deletions llvm/lib/Transforms/Utils/ModuleUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Hash.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/xxhash.h"
#include "llvm/Transforms/Instrumentation/KCFI.h"

using namespace llvm;

Expand Down Expand Up @@ -208,10 +209,16 @@ void llvm::setKCFIType(Module &M, Function &F, StringRef MangledType) {
std::string Type = MangledType.str();
if (M.getModuleFlag("cfi-normalize-integers"))
Type += ".normalized";

// Determine which hash algorithm to use
auto *MD = dyn_cast_or_null<MDString>(M.getModuleFlag("kcfi-hash"));
KCFIHashAlgorithm Algorithm =
parseKCFIHashAlgorithm(MD ? MD->getString() : "");

F.setMetadata(LLVMContext::MD_kcfi_type,
MDNode::get(Ctx, MDB.createConstant(ConstantInt::get(
Type::getInt32Ty(Ctx),
static_cast<uint32_t>(xxHash64(Type))))));
getKCFITypeID(Type, Algorithm)))));
// If the module was compiled with -fpatchable-function-entry, ensure
// we use the same patchable-function-prefix.
if (auto *MD = mdconst::extract_or_null<ConstantInt>(
Expand Down
Loading