Call Convention

Reference 1

calling convention in LLVM

lib/Target/Mips/

./CheriStackInvalidatePass.cpp ./CheriAddressingModeFolder.cpp ./MipsInstrCheri.td ./CheriRangeChecker.cpp ./Cheri128FailHard.cpp ./MipsInstrFormatsCheri.td ./CheriLoopPointerDecanonicalize.cpp ./cheri-compressed-cap ./cheri-compressed-cap/decompress_c128_cap.c ./cheri-compressed-cap/LICENSE ./cheri-compressed-cap/README.md ./cheri-compressed-cap/.editorconfig ./cheri-compressed-cap/.gitignore ./cheri-compressed-cap/cheri_compressed_cap.c ./cheri-compressed-cap/.gitrepo ./cheri-compressed-cap/cheri_compressed_cap.h ./cheri-compressed-cap/test ./cheri-compressed-cap/test/fuzz-decompress.cpp ./cheri-compressed-cap/test/decode_inputs.cpp ./cheri-compressed-cap/test/test_util.h ./cheri-compressed-cap/test/setbounds_test.cpp ./cheri-compressed-cap/test/random_inputs_test.cpp ./cheri-compressed-cap/test/simple_test.cpp ./cheri-compressed-cap/test/FuzzedDataProvider.h ./cheri-compressed-cap/test/catch.hpp ./cheri-compressed-cap/test/setbounds_inputs.cpp ./cheri-compressed-cap/.clang-format ./cheri-compressed-cap/CMakeLists.txt

in MipsCallingConv.td

CC_Mips 
 -> CC_Mips_VarArg
    -> CC_MipsCheriPureCap_VarArg
    -> CC_Mips_ByVal
    -> CC_Mips_N_VarArg
 -> CC_Mips_FixedArg
    -> CC_CHERI_CCall
        -> CC_MipsN
    -> CC_Mips_ByVal
    -> CC_Mips_FastCC
    -> CC_MIpsN

CC_CHERI_CCall

CC_CHERI_CCall convention -> CC_MipsN -> CC_MipsCheriCapOnStack:

// lib/Target/Mips/MipsCallingConv.td

def CC_CHERI_CCall : CallingConv<[
  CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCAssignToReg<[C1, C2, C3, C4, C5, C6, C7, C8, C9, C10]>>,
  CCIfType<[i64], CCAssignToReg<[V0_64]>>,
  CCDelegateTo<CC_MipsN>
]>;

See definition in build/lib/Target/Mips/MipsGenCallingConv.inc

CC_MipsN

// lib/Target/Mips/MipsCallingConv.td

def CC_MipsN : CallingConv<[
  ...
  // All integers (except soft-float integers) are promoted to 64-bit.
  CCIfType<[i8, i16, i32], CCIfOrigArgWasNotFloat<CCPromoteToType<i64>>>,

  // The only i32's we have left are soft-float arguments.
  CCIfSubtarget<"useSoftFloat()", CCIfType<[i32],
                CCDelegateTo<CC_MipsN_SoftFloat>>>,
  ...
  // All stack parameter slots become 64-bit doublewords and are 8-byte aligned.
  CCIfType<[f32], CCAssignToStack<4, 8>>,
  CCIfType<[i64, f64], CCAssignToStack<8, 8>>,
  CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCAssignToReg<[C3, C4, C5, C6, C7, C8, C9, C10]>>,
  CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCDelegateTo<CC_MipsCheriCapOnStack>>
]>;

CC_MipsCheriCapOnStack

// lib/Target/Mips/MipsCallingConv.td

def CC_MipsCheriCapOnStack : CallingConv<[
  CCIfSubtarget<"isCheri128()", CCAssignToStack<16, 16>>,
  CCIfSubtargetNot<"isCheri128()", CCAssignToStack<32, 32>>
]>;

CC_MipsCheriPureCap_VarArg

Purecap: variadic argument on stack:

// In purecap mode, all variadic arguments are passed on the stack.
def CC_MipsCheriPureCap_VarArg : CallingConv<[
  // Promote i8/i16 arguments to i32.
  CCIfType<[i8, i16, i32], CCPromoteToType<i64>>,
  // All stack parameter slots become 64-bit doublewords and are 8-byte aligned.
  CCIfType<[f32], CCAssignToStack<4, 8>>,
  CCIfType<[i64, f64], CCAssignToStack<8, 8>>,
  CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCDelegateTo<CC_MipsCheriCapOnStack>>
]>;

CC_Mips_FixedArg -> CC_CHERI_CCall

CC_Mips_VarArg -> CC_MipsCheriPureCap_VarArg

def CC_Mips_FixedArg : CallingConv<[
  ...
  CCIf<"State.getCallingConv() == CallingConv::CHERI_CCall",
       CCDelegateTo<CC_CHERI_CCall>>,
  ...
]>;

def CC_Mips_VarArg : CallingConv<[
  // If this is the CHERI purecap ABI then we need to pass everything on the
  // stack for variadic functions.
  CCIfSubtarget<"isABI_CheriPureCap()", CCDelegateTo<CC_MipsCheriPureCap_VarArg>>,
  CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>,
  ...
]>;
def CSR_N64_Cheri :
    CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64,
                                   GP_64, (sequence "S%u_64", 7, 0),
                                   (sequence "C%u", 23, 17))>;
def CSR_Cheri_Purecap :
    CalleeSavedRegs<(add (sequence "D%u_64", 31, 24), RA_64, FP_64,
                                   GP_64, (sequence "S%u_64", 7, 0),
                                   (sequence "C%u", 25, 17))>;

pull requests

Only mangle the capability qualifier for pointers in the hybrid ABI #390

  • capability qualifier in name mangling.
  • Having all pointers mangled was useful to catch incorrect linker paths before CHERI support in LLD was added; because C++ programs would fail to link due to missing symbols. But no longer useful since now errors will be catched by LLD when linking purecap and non-purecap libraries. TODO: LLD link support for CHERI.
  • Capability mangling is now only used in hybrid mode. Mangling is now U12_capability: void test(void *__capability) now mangles as _Z4testU12__capabilityPv instead of _Z4testU3capPv; llvm-cxxfilt demangles it to test(void *__capability) instead of test(void *cap).

[CHERI-MIPS] Return structs that are pairs of capabilities in C3/C4 #391

Remove C++ struct calling convention hack and fix bug masked by it #393

  • clang/lib/GodeGen/TargetInfo.cpp: MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize)
  • clang/lib/GodeGen/TargetInfo.cpp: MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offsets, bool &HasV0s)
  • clang/test/CodeGenCXX/cheri/cheri-qdebug-crash.cpp

  1. reference ↩
Created Apr 24, 2020 // Last Updated May 18, 2021

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?