Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e1490b4
LLVM Patch 16 to 21 on RASM
Gab-San Nov 25, 2025
0f521c1
Small modifications to aspis.sh
Gab-San Nov 25, 2025
bcc18d4
Reinstated lower-switch pass
Gab-San Dec 8, 2025
4f98f81
Patched EDDI to LLVM 21
Gab-San Jan 13, 2026
22d7763
Init RACFED
MartinaStarone Dec 21, 2025
eeaab32
small fix
Gab-San Dec 21, 2025
184b24e
Small Refactor and Work Organization
Gab-San Dec 22, 2025
5670a53
updateCompileSigRandom function update
MartinaStarone Dec 24, 2025
acad4c7
Changes by gamba
MartinaStarone Dec 24, 2025
46a0679
Fixes
MartinaStarone Dec 24, 2025
083ec51
standardized
Gab-San Dec 25, 2025
8eda111
branch try-- to test
MartinaStarone Dec 28, 2025
d715309
Fixed compilation issues
Gab-San Dec 29, 2025
8806792
branch signature verification
MartinaStarone Dec 30, 2025
66f7866
Implementation of Return Value Check
Gab-San Jan 2, 2026
a92d7f3
fixes
MartinaStarone Jan 3, 2026
b440a0f
Fixed restoring branch signature on return
Gab-San Jan 3, 2026
ff6fe07
checkbranches fix-- to test but it works
MartinaStarone Jan 6, 2026
9ebfac6
small-clean
Gab-San Jan 7, 2026
34167ff
fixes and test on phi node
MartinaStarone Jan 7, 2026
a554ea0
Added suffix option to aspis.sh
Gab-San Jan 9, 2026
fe80d9c
Modified test.py
Gab-San Jan 13, 2026
53959e1
Tested racfed on c tests
Gab-San Jan 13, 2026
74a9dac
Tested RACFED+EDDI
Gab-San Jan 13, 2026
7941f08
Update README
Gab-San Jan 14, 2026
f2c9012
Adding Documentation
Gab-San Jan 14, 2026
051950f
Additional documentation
Gab-San Jan 14, 2026
3e48e05
Added multi_if_then_else.c test
Gab-San Jan 15, 2026
55ef536
Fixed warnings in checkJumpSignature
Gab-San Jan 15, 2026
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
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
*.a
*.lib

# IR files
*.ll

# Executables
*.exe
*.out
Expand Down Expand Up @@ -62,4 +65,7 @@ examples/sha/*.csv
examples/sha/sha

examples/cuda/*.txt
examples/cuda/add
examples/cuda/add

# IDE
.idea/
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ The toolchain has been tested with the following versions:
- CMake 3.22.1
- LLVM 16.0.0

> RASM, RACFED and EDDI algorithm are already patched to LLVM 21.
> Patching of the other algorithms is being done.

During the development of ASPIS, done mostly on LLVM 15, we discovered a bug in the [`splitBasicBlock()`](https://llvm.org/doxygen/classllvm_1_1BasicBlock.html#a2bc5caaabd6841e4ab97237ebcaeb86d) procedure. The bug has been fixed in LLVM 16, so we recommend using it rather than applying the patch to the previous versions.

## Building
Expand Down Expand Up @@ -80,6 +83,9 @@ ASPIS does not compile the annotated function or does not duplicate the annotate
## Built-in compilation pipeline
`aspis.sh` is a simple command-line interface that allows users to run the entire compilation pipeline specifying a few command-line arguments. The arguments that are not recognised are passed directly to the front-end, hence all the `clang` arguments are admissible.

> RASM, RACFED and EDDI algorithm are already patched to LLVM 21.
> Patching of the other algorithms is being done.

### Options
- `-h`, `--help`: Display available options.
- `-o <file>`: Write the compilation output to `<file>`.
Expand All @@ -95,6 +101,7 @@ ASPIS does not compile the annotated function or does not duplicate the annotate
- `--cfcss`: **(Default)** Enable CFCSS.
- `--rasm`: Enable RASM.
- `--inter-rasm`: Enable inter-RASM with the default signature `-0xDEAD`.
- `--racfed`: Enable RACFED.

### Example

Expand Down Expand Up @@ -184,6 +191,11 @@ opt --enable-new-pm=0 -S -load </path/to/ASPIS/>build/passes/libEDDI.so -duplica
clang out.ll -o out.elf
```

> With newer versions of LLVM:
> `--enable-new-pm` is no longer valid.
> `-load` has been replaced by `-load-pass-plugin=</path/to/ASPIS/>build/passes/lib*.so -passes="passname"`


## References
If you are using this tool in scientific works, please cite the following article:
- Davide Baroffio, Federico Reghenzani, and William Fornaciari. 2024. Enhanced Compiler Technology for Software-based Hardware Fault Detection. ACM Trans. Des. Autom. Electron. Syst. 29, 5, Article 91 (September 2024), 23 pages. https://doi.org/10.1145/3660524
Expand Down
86 changes: 54 additions & 32 deletions aspis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ input_files=""
clang_options=
eddi_options="-S"
cfc_options="-S"
llvm_bin=$(dirname $(which clang &> /dev/null) &> /dev/null)
llvm_bin=$(dirname "$(which clang)")
suffix=""
build_dir="."
dup=0 # 0 = eddi, 1 = seddi, 2 = fdsc
cfc=0 # 0 = cfcss, 1 = rasm, 2 = inter-rasm
Expand Down Expand Up @@ -65,15 +66,15 @@ title_msg () {

perform_platform_checks() {
if [ ! -f $1 ]; then
error_msg "\nCommand clang not found. Expected path: ${1}. Please check --llvm_bin parameter."
error_msg "\nCommand clang not found. Expected path: ${1}. Please check --llvm-bin parameter."
fi

if [ ! -f $2 ]; then
error_msg "\nCommand opt not found. Expected path: ${2}. Please check --llvm_bin parameter."
error_msg "\nCommand opt not found. Expected path: ${2}. Please check --llvm-bin parameter."
fi

if [ ! -f $3 ]; then
error_msg "\nCommand llvm-link not found. Expected path: ${3}. Please check --llvm_bin parameter."
error_msg "\nCommand llvm-link not found. Expected path: ${3}. Please check --llvm-bin parameter."
fi

}
Expand Down Expand Up @@ -112,12 +113,14 @@ parse_commands() {
-o <file> Write the compilation output to <file>.
--build-dir <path> Specify the directory where to place all the build
files.
--llvm-bin <path> Set the path to the llvm binaries (clang, opt,
--llvm-bin <path> Set the path to the llvm binaries (clang, opt,
llvm-link) to <path>.
--exclude <file> Set the files to exclude from the compilation. The
--suffix <value> Set the suffix of the binary to use (clang, opt,
llvm-link) to <value>.
--exclude <file> Set the files to exclude from the compilation. The
content of <file> is the list of files to
exclude, one for each line (wildcard * allowed).
--asmfiles <file> Defines the set of assembly files required for the
--asmfiles <file> Defines the set of assembly files required for the
compilation. The content of <file> is the list of
assembly files to pass to the linker at compilation
termination, one for each line (wildcard * allowed).
Expand All @@ -128,12 +131,13 @@ parse_commands() {
--eddi (Default) Enable EDDI.
--seddi Enable Selective-EDDI.
--fdsc Enable Full Duplication with Selective Checking.
--no-dup Completely disable data duplication
--no-dup Completely disable data duplication.

--cfcss (Default) Enable CFCSS.
--rasm Enable RASM.
--inter-rasm Enable inter-RASM with the default signature -0xDEAD.
--no-cfc Completely disable control-flow checking
--racfed Enable RACFED.
--no-cfc Completely disable control-flow checking.

Hardening options:
--alternate-memmap When set, alternates the definition of original and
Expand All @@ -155,16 +159,25 @@ EOF
if [[ ${#opt} -eq 2 ]]; then
parse_state=1;
else
output_file=`echo "$opt" | cut -b 2`;
output_file=${opt##"-o"};
fi;
;;
--llvm-bin*)
echo ${#opt}
if [[ ${#opt} -eq 10 ]]; then
parse_state=3;
else
llvm_bin=`echo "$opt" | cut -b 10`;
llvm_bin=${opt##"--llvm-bin="};
fi;
;;
--suffix*)
if [[ ${#opt} -eq 8 ]]; then
parse_state=7;
else
suffix='-';
suffix+=${opt##"--suffix="};
fi;
;;
--exclude*)
if [[ ${#opt} -eq 9 ]]; then
parse_state=4;
Expand Down Expand Up @@ -207,6 +220,9 @@ EOF
--inter-rasm)
cfc=2
;;
--racfed)
cfc=3
;;
--no-cfc)
cfc=-1
;;
Expand Down Expand Up @@ -267,6 +283,10 @@ EOF
build_dir="$opt";
parse_state=0;
;;
7)
suffix="-$opt";
parse_state=0;
;;
esac
done

Expand All @@ -291,9 +311,9 @@ EOF
}
fi

CLANG="${llvm_bin}/clang"
OPT="${llvm_bin}/opt"
LLVM_LINK="${llvm_bin}/llvm-link"
CLANG="${llvm_bin}/clang${suffix}"
OPT="${llvm_bin}/opt${suffix}"
LLVM_LINK="${llvm_bin}/llvm-link${suffix}"

if [[ -n "$config_file" ]]; then
CLANG="${CLANG} --config ${config_file}"
Expand All @@ -319,27 +339,27 @@ run_aspis() {
done

## LINK & PREPROCESS
exe $LLVM_LINK $build_dir/*.ll -o $build_dir/out.ll -opaque-pointers
exe $LLVM_LINK $build_dir/*.ll -o $build_dir/out.ll

success_msg "Emitted and linked IR."

if [[ $debug_enabled == false ]]; then
exe $OPT --enable-new-pm=1 --passes="strip" $build_dir/out.ll -o $build_dir/out.ll
exe $OPT --passes="strip" $build_dir/out.ll -o $build_dir/out.ll
echo " Debug mode disabled, stripped debug symbols."
fi

exe $OPT --enable-new-pm=1 --passes="lowerswitch" $build_dir/out.ll -o $build_dir/out.ll
exe $OPT --passes="lower-switch" $build_dir/out.ll -o $build_dir/out.ll

## FuncRetToRef
if [[ dup != -1 ]]; then
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="func-ret-to-ref" $build_dir/out.ll -o $build_dir/out.ll
if [[ dup -ne -1 ]]; then
exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="func-ret-to-ref" $build_dir/out.ll -o $build_dir/out.ll
fi;

title_msg "ASPIS transformations"
## DATA PROTECTION
case $dup in
0)
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options
exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options
;;
1)
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libSEDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options
Expand All @@ -352,19 +372,21 @@ run_aspis() {
esac
success_msg "Applied data protection passes."

exe $OPT --enable-new-pm=1 --passes="simplifycfg" $build_dir/out.ll -o $build_dir/out.ll

exe $OPT --passes="simplifycfg" $build_dir/out.ll -o $build_dir/out.ll

## CONTROL-FLOW CHECKING
case $cfc in
0)
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libCFCSS.so --passes="cfcss-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
exe $OPT -load-pass-plugin=$DIR/build/passes/libCFCSS.so --passes="cfcss-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
;;
1)
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libRASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
exe $OPT -load-pass-plugin=$DIR/build/passes/libRASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
;;
2)
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
exe $OPT -load-pass-plugin=$DIR/build/passes/libINTER_RASM.so --passes="rasm-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
;;
3)
exe $OPT -load-pass-plugin=$DIR/build/passes/libRACFED.so --passes="racfed-verify" $build_dir/out.ll -o $build_dir/out.ll $cfc_options
;;
*)
echo -e "\t--no-cfc specified!"
Expand Down Expand Up @@ -393,8 +415,8 @@ run_aspis() {
success_msg "Linked excluded files to the compilation."

## DuplicateGlobals
if [[ dup != -1 ]]; then
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="duplicate-globals" $build_dir/out.ll -o $build_dir/out.ll -S $eddi_options
if [[ dup -ne -1 ]]; then
exe $OPT -load-pass-plugin=$DIR/build/passes/libEDDI.so --passes="duplicate-globals" $build_dir/out.ll -o $build_dir/out.ll -S $eddi_options
success_msg "Duplicated globals."
fi;

Expand All @@ -411,7 +433,7 @@ run_aspis() {
exe $OPT $build_dir/out.ll -o $build_dir/out.ll -S $opt_flags
if [[ "$enable_profiling" == "true" ]]; then
title_msg "ASPIS Profiling"
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-insert-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S
exe $OPT -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-insert-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S
success_msg "Code instrumented."

exe $CLANG $clang_options $build_dir/out.ll $asm_files -o $build_dir/$output_file
Expand All @@ -421,7 +443,7 @@ run_aspis() {
success_msg "Profiled code executed."

echo -e "Analyzing..."
exe $OPT --enable-new-pm=1 -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S
exe $OPT -load-pass-plugin=$DIR/build/passes/libPROFILER.so --passes="aspis-check-profile" $build_dir/out.ll -o $build_dir/out.ll -S
exit
fi;

Expand All @@ -437,6 +459,6 @@ run_aspis() {
success_msg "Done!"
}

parse_commands $@
parse_commands "$@"
perform_platform_checks $CLANG $OPT $LLVM_LINK
run_aspis
run_aspis
89 changes: 87 additions & 2 deletions passes/ASPIS.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ using namespace llvm;
// DATA PROTECTION
class FuncRetToRef : public PassInfoMixin<FuncRetToRef> {
private:
Function* updateFnSignature(Function &Fn, Module &Md);
void updateFnSignature(Function &Fn, Module &Md);
void updateRetInstructions(Function &Fn);
void updateFunctionCalls(Function &Fn, Function &NewFn);

Expand Down Expand Up @@ -156,4 +156,89 @@ class RASM : public PassInfoMixin<RASM> {

};

#endif
/**
* @brief Pass implementing RACFED algorithm.
*/
class RACFED : public PassInfoMixin<RACFED> {
private:
std::map<Value *, StringRef> FuncAnnotations;

/**
* Compile time signature map.
*
* Compile time signatures are unique identifiers for the single basic block.
*/
std::unordered_map<BasicBlock *, uint32_t> compileTimeSig;

/**
* SubRanPrevVals map.
*
* These values are added to compile time signature to identify unique
* branch jumps.
*/
std::unordered_map<BasicBlock *, uint32_t> subRanPrevVals;

/**
* Instra instruction sum map.
*
* This map contains the sum of all the random values put after instructions.
*/
std::unordered_map<BasicBlock *, uint64_t> sumIntraInstruction;


#if (LOG_COMPILED_FUNCS == 1)
std::set<Function *> CompiledFuncs;
#endif

/**
* Initializes compile time signature and subRanPrevVal, for
* all of the basic blocks, with unique values.
*/
void initializeBlocksSignatures(Function &Fn);

/**
* Adds updates to the runtime signature with random values
* after each instruction.
*/
void insertIntraInstructionUpdates(Function &Fn,
GlobalVariable *RuntimeSigGV, Type *IntType);

/**
* Adds a check on runtime signature at the entrance of non entry blocks.
*
* If the runtime signature, after some proper modifications, does not match
* the compile time signature a jump to an error handling block is inserted.
*/
void checkJumpSignature(BasicBlock &BB,
GlobalVariable *RuntimeSigGV, Type *IntType,
BasicBlock &ErrBB);

// TODO: Add documentation
Value *getCondition(Instruction &I);

/**
* Adds an update of the runtime signature before a branch instruction.
*
* This function works in conjunction with checkJumpSignature(...).
*/
void updateBeforeJump(Module &Md, BasicBlock &BB, GlobalVariable *RuntimeSigGV,
Type *IntType);

/**
* Adds a check on runtime signature before a return instruction.
*
* If the runtime signature, after some proper modifications, does not match
* the compile time signature a jump to an error handling block is inserted.
*/
Instruction *checkOnReturn(BasicBlock &BB,
GlobalVariable *RuntimeSigGV,
Type *IntType, BasicBlock &ErrBB,
Value *BckupRunSig);

public:
PreservedAnalyses run(Module &Md, ModuleAnalysisManager &);

static bool isRequired() { return true; }
};

#endif
6 changes: 6 additions & 0 deletions passes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ add_library(INTER_RASM SHARED
)
target_compile_definitions(INTER_RASM PRIVATE INTRA_FUNCTION_CFC=1)

# RACFED
add_library(RACFED SHARED
RACFED.cpp
Utils/Utils.cpp
)

add_library(PROFILER SHARED
Profiling/ASPISCheckProfiler.cpp
Utils/Utils.cpp
Expand Down
Loading