|
16 | 16 | #include "CGBlocks.h"
|
17 | 17 | #include "CGCXXABI.h"
|
18 | 18 | #include "CGCleanup.h"
|
| 19 | +#include "CGRecordLayout.h" |
19 | 20 | #include "CodeGenFunction.h"
|
20 | 21 | #include "CodeGenModule.h"
|
21 | 22 | #include "TargetInfo.h"
|
@@ -2871,6 +2872,213 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
2871 | 2872 | return store;
|
2872 | 2873 | }
|
2873 | 2874 |
|
| 2875 | +// Helper functions for EmitCMSEClearRecord |
| 2876 | + |
| 2877 | +// Set the bits corresponding to a field having width `BitWidth` and located at |
| 2878 | +// offset `BitOffset` (from the least significant bit) within a storage unit of |
| 2879 | +// `Bits.size()` bytes. Each element of `Bits` corresponds to one target byte. |
| 2880 | +// Use little-endian layout, i.e.`Bits[0]` is the LSB. |
| 2881 | +static void setBitRange(SmallVectorImpl<uint64_t> &Bits, int BitOffset, |
| 2882 | + int BitWidth, int CharWidth) { |
| 2883 | + assert(CharWidth <= 64); |
| 2884 | + assert(static_cast<unsigned>(BitWidth) <= Bits.size() * CharWidth); |
| 2885 | + |
| 2886 | + int Pos = 0; |
| 2887 | + if (BitOffset >= CharWidth) { |
| 2888 | + Pos += BitOffset / CharWidth; |
| 2889 | + BitOffset = BitOffset % CharWidth; |
| 2890 | + } |
| 2891 | + |
| 2892 | + const uint64_t Used = (uint64_t(1) << CharWidth) - 1; |
| 2893 | + if (BitOffset + BitWidth >= CharWidth) { |
| 2894 | + Bits[Pos++] |= (Used << BitOffset) & Used; |
| 2895 | + BitWidth -= CharWidth - BitOffset; |
| 2896 | + BitOffset = 0; |
| 2897 | + } |
| 2898 | + |
| 2899 | + while (BitWidth >= CharWidth) { |
| 2900 | + Bits[Pos++] = Used; |
| 2901 | + BitWidth -= CharWidth; |
| 2902 | + } |
| 2903 | + |
| 2904 | + if (BitWidth > 0) |
| 2905 | + Bits[Pos++] |= (Used >> (CharWidth - BitWidth)) << BitOffset; |
| 2906 | +} |
| 2907 | + |
| 2908 | +// Set the bits corresponding to a field having width `BitWidth` and located at |
| 2909 | +// offset `BitOffset` (from the least significant bit) within a storage unit of |
| 2910 | +// `StorageSize` bytes, located at `StorageOffset` in `Bits`. Each element of |
| 2911 | +// `Bits` corresponds to one target byte. Use target endian layout. |
| 2912 | +static void setBitRange(SmallVectorImpl<uint64_t> &Bits, int StorageOffset, |
| 2913 | + int StorageSize, int BitOffset, int BitWidth, |
| 2914 | + int CharWidth, bool BigEndian) { |
| 2915 | + |
| 2916 | + SmallVector<uint64_t, 8> TmpBits(StorageSize); |
| 2917 | + setBitRange(TmpBits, BitOffset, BitWidth, CharWidth); |
| 2918 | + |
| 2919 | + if (BigEndian) |
| 2920 | + std::reverse(TmpBits.begin(), TmpBits.end()); |
| 2921 | + |
| 2922 | + for (uint64_t V : TmpBits) |
| 2923 | + Bits[StorageOffset++] |= V; |
| 2924 | +} |
| 2925 | + |
| 2926 | +static void setUsedBits(CodeGenModule &, QualType, int, |
| 2927 | + SmallVectorImpl<uint64_t> &); |
| 2928 | + |
| 2929 | +// Set the bits in `Bits`, which correspond to the value representations of |
| 2930 | +// the actual members of the record type `RTy`. Note that this function does |
| 2931 | +// not handle base classes, virtual tables, etc, since they cannot happen in |
| 2932 | +// CMSE function arguments or return. The bit mask corresponds to the target |
| 2933 | +// memory layout, i.e. it's endian dependent. |
| 2934 | +static void setUsedBits(CodeGenModule &CGM, const RecordType *RTy, int Offset, |
| 2935 | + SmallVectorImpl<uint64_t> &Bits) { |
| 2936 | + ASTContext &Context = CGM.getContext(); |
| 2937 | + int CharWidth = Context.getCharWidth(); |
| 2938 | + const RecordDecl *RD = RTy->getDecl()->getDefinition(); |
| 2939 | + const ASTRecordLayout &ASTLayout = Context.getASTRecordLayout(RD); |
| 2940 | + const CGRecordLayout &Layout = CGM.getTypes().getCGRecordLayout(RD); |
| 2941 | + |
| 2942 | + int Idx = 0; |
| 2943 | + for (auto I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++Idx) { |
| 2944 | + const FieldDecl *F = *I; |
| 2945 | + |
| 2946 | + if (F->isUnnamedBitfield() || F->isZeroLengthBitField(Context) || |
| 2947 | + F->getType()->isIncompleteArrayType()) |
| 2948 | + continue; |
| 2949 | + |
| 2950 | + if (F->isBitField()) { |
| 2951 | + const CGBitFieldInfo &BFI = Layout.getBitFieldInfo(F); |
| 2952 | + setBitRange(Bits, Offset + BFI.StorageOffset.getQuantity(), |
| 2953 | + BFI.StorageSize / CharWidth, BFI.Offset, |
| 2954 | + BFI.Size, CharWidth, |
| 2955 | + CGM.getDataLayout().isBigEndian()); |
| 2956 | + continue; |
| 2957 | + } |
| 2958 | + |
| 2959 | + setUsedBits(CGM, F->getType(), |
| 2960 | + Offset + ASTLayout.getFieldOffset(Idx) / CharWidth, Bits); |
| 2961 | + } |
| 2962 | +} |
| 2963 | + |
| 2964 | +// Set the bits in `Bits`, which correspond to the value representations of |
| 2965 | +// the elements of an array type `ATy`. |
| 2966 | +static void setUsedBits(CodeGenModule &CGM, const ConstantArrayType *ATy, |
| 2967 | + int Offset, SmallVectorImpl<uint64_t> &Bits) { |
| 2968 | + const ASTContext &Context = CGM.getContext(); |
| 2969 | + |
| 2970 | + QualType ETy = Context.getBaseElementType(ATy); |
| 2971 | + int Size = Context.getTypeSizeInChars(ETy).getQuantity(); |
| 2972 | + SmallVector<uint64_t, 4> TmpBits(Size); |
| 2973 | + setUsedBits(CGM, ETy, 0, TmpBits); |
| 2974 | + |
| 2975 | + for (int I = 0, N = Context.getConstantArrayElementCount(ATy); I < N; ++I) { |
| 2976 | + auto Src = TmpBits.begin(); |
| 2977 | + auto Dst = Bits.begin() + Offset + I * Size; |
| 2978 | + for (int J = 0; J < Size; ++J) |
| 2979 | + *Dst++ |= *Src++; |
| 2980 | + } |
| 2981 | +} |
| 2982 | + |
| 2983 | +// Set the bits in `Bits`, which correspond to the value representations of |
| 2984 | +// the type `QTy`. |
| 2985 | +static void setUsedBits(CodeGenModule &CGM, QualType QTy, int Offset, |
| 2986 | + SmallVectorImpl<uint64_t> &Bits) { |
| 2987 | + if (const auto *RTy = QTy->getAs<RecordType>()) |
| 2988 | + return setUsedBits(CGM, RTy, Offset, Bits); |
| 2989 | + |
| 2990 | + ASTContext &Context = CGM.getContext(); |
| 2991 | + if (const auto *ATy = Context.getAsConstantArrayType(QTy)) |
| 2992 | + return setUsedBits(CGM, ATy, Offset, Bits); |
| 2993 | + |
| 2994 | + int Size = Context.getTypeSizeInChars(QTy).getQuantity(); |
| 2995 | + if (Size <= 0) |
| 2996 | + return; |
| 2997 | + |
| 2998 | + std::fill_n(Bits.begin() + Offset, Size, |
| 2999 | + (uint64_t(1) << Context.getCharWidth()) - 1); |
| 3000 | +} |
| 3001 | + |
| 3002 | +static uint64_t buildMultiCharMask(const SmallVectorImpl<uint64_t> &Bits, |
| 3003 | + int Pos, int Size, int CharWidth, |
| 3004 | + bool BigEndian) { |
| 3005 | + assert(Size > 0); |
| 3006 | + uint64_t Mask = 0; |
| 3007 | + if (BigEndian) { |
| 3008 | + for (auto P = Bits.begin() + Pos, E = Bits.begin() + Pos + Size; P != E; |
| 3009 | + ++P) |
| 3010 | + Mask = (Mask << CharWidth) | *P; |
| 3011 | + } else { |
| 3012 | + auto P = Bits.begin() + Pos + Size, End = Bits.begin() + Pos; |
| 3013 | + do |
| 3014 | + Mask = (Mask << CharWidth) | *--P; |
| 3015 | + while (P != End); |
| 3016 | + } |
| 3017 | + return Mask; |
| 3018 | +} |
| 3019 | + |
| 3020 | +// Emit code to clear the bits in a record, which aren't a part of any user |
| 3021 | +// declared member, when the record is a function return. |
| 3022 | +llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src, |
| 3023 | + llvm::IntegerType *ITy, |
| 3024 | + QualType QTy) { |
| 3025 | + assert(Src->getType() == ITy); |
| 3026 | + assert(ITy->getScalarSizeInBits() <= 64); |
| 3027 | + |
| 3028 | + const llvm::DataLayout &DataLayout = CGM.getDataLayout(); |
| 3029 | + int Size = DataLayout.getTypeStoreSize(ITy); |
| 3030 | + SmallVector<uint64_t, 4> Bits(Size); |
| 3031 | + setUsedBits(CGM, QTy->getAs<RecordType>(), 0, Bits); |
| 3032 | + |
| 3033 | + int CharWidth = CGM.getContext().getCharWidth(); |
| 3034 | + uint64_t Mask = |
| 3035 | + buildMultiCharMask(Bits, 0, Size, CharWidth, DataLayout.isBigEndian()); |
| 3036 | + |
| 3037 | + return Builder.CreateAnd(Src, Mask, "cmse.clear"); |
| 3038 | +} |
| 3039 | + |
| 3040 | +// Emit code to clear the bits in a record, which aren't a part of any user |
| 3041 | +// declared member, when the record is a function argument. |
| 3042 | +llvm::Value *CodeGenFunction::EmitCMSEClearRecord(llvm::Value *Src, |
| 3043 | + llvm::ArrayType *ATy, |
| 3044 | + QualType QTy) { |
| 3045 | + const llvm::DataLayout &DataLayout = CGM.getDataLayout(); |
| 3046 | + int Size = DataLayout.getTypeStoreSize(ATy); |
| 3047 | + SmallVector<uint64_t, 16> Bits(Size); |
| 3048 | + setUsedBits(CGM, QTy->getAs<RecordType>(), 0, Bits); |
| 3049 | + |
| 3050 | + // Clear each element of the LLVM array. |
| 3051 | + int CharWidth = CGM.getContext().getCharWidth(); |
| 3052 | + int CharsPerElt = |
| 3053 | + ATy->getArrayElementType()->getScalarSizeInBits() / CharWidth; |
| 3054 | + int MaskIndex = 0; |
| 3055 | + llvm::Value *R = llvm::UndefValue::get(ATy); |
| 3056 | + for (int I = 0, N = ATy->getArrayNumElements(); I != N; ++I) { |
| 3057 | + uint64_t Mask = buildMultiCharMask(Bits, MaskIndex, CharsPerElt, CharWidth, |
| 3058 | + DataLayout.isBigEndian()); |
| 3059 | + MaskIndex += CharsPerElt; |
| 3060 | + llvm::Value *T0 = Builder.CreateExtractValue(Src, I); |
| 3061 | + llvm::Value *T1 = Builder.CreateAnd(T0, Mask, "cmse.clear"); |
| 3062 | + R = Builder.CreateInsertValue(R, T1, I); |
| 3063 | + } |
| 3064 | + |
| 3065 | + return R; |
| 3066 | +} |
| 3067 | + |
| 3068 | +// Emit code to clear the padding bits when returning or passing as an argument |
| 3069 | +// a 16-bit floating-point value. |
| 3070 | +llvm::Value *CodeGenFunction::EmitCMSEClearFP16(llvm::Value *Src) { |
| 3071 | + llvm::Type *RetTy = Src->getType(); |
| 3072 | + assert(RetTy->isFloatTy() || |
| 3073 | + RetTy->isIntegerTy() && RetTy->getIntegerBitWidth() == 32); |
| 3074 | + if (RetTy->isFloatTy()) { |
| 3075 | + llvm::Value *T0 = Builder.CreateBitCast(Src, Builder.getIntNTy(32)); |
| 3076 | + llvm::Value *T1 = Builder.CreateAnd(T0, 0xffff, "cmse.clear"); |
| 3077 | + return Builder.CreateBitCast(T1, RetTy); |
| 3078 | + } |
| 3079 | + return Builder.CreateAnd(Src, 0xffff, "cmse.clear"); |
| 3080 | +} |
| 3081 | + |
2874 | 3082 | void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
2875 | 3083 | bool EmitRetDbgLoc,
|
2876 | 3084 | SourceLocation EndLoc) {
|
@@ -3037,6 +3245,21 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
3037 | 3245 |
|
3038 | 3246 | llvm::Instruction *Ret;
|
3039 | 3247 | if (RV) {
|
| 3248 | + if (CurFuncDecl && CurFuncDecl->hasAttr<CmseNSEntryAttr>()) { |
| 3249 | + // For certain return types, clear padding bits, as they may reveal |
| 3250 | + // sensitive information. |
| 3251 | + const Type *RTy = RetTy.getCanonicalType().getTypePtr(); |
| 3252 | + if (RTy->isFloat16Type() || RTy->isHalfType()) { |
| 3253 | + // 16-bit floating-point types are passed in a 32-bit integer or float, |
| 3254 | + // with unspecified upper bits. |
| 3255 | + RV = EmitCMSEClearFP16(RV); |
| 3256 | + } else { |
| 3257 | + // Small struct/union types are passed as integers. |
| 3258 | + auto *ITy = dyn_cast<llvm::IntegerType>(RV->getType()); |
| 3259 | + if (ITy != nullptr && isa<RecordType>(RetTy.getCanonicalType())) |
| 3260 | + RV = EmitCMSEClearRecord(RV, ITy, RetTy); |
| 3261 | + } |
| 3262 | + } |
3040 | 3263 | EmitReturnValueCheck(RV);
|
3041 | 3264 | Ret = Builder.CreateRet(RV);
|
3042 | 3265 | } else {
|
@@ -4332,8 +4555,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
4332 | 4555 | } else {
|
4333 | 4556 | // In the simple case, just pass the coerced loaded value.
|
4334 | 4557 | assert(NumIRArgs == 1);
|
4335 |
| - IRCallArgs[FirstIRArg] = |
4336 |
| - CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this); |
| 4558 | + llvm::Value *Load = |
| 4559 | + CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this); |
| 4560 | + |
| 4561 | + if (CallInfo.isCmseNSCall()) { |
| 4562 | + // For certain parameter types, clear padding bits, as they may reveal |
| 4563 | + // sensitive information. |
| 4564 | + const Type *PTy = I->Ty.getCanonicalType().getTypePtr(); |
| 4565 | + // 16-bit floating-point types are passed in a 32-bit integer or |
| 4566 | + // float, with unspecified upper bits. |
| 4567 | + if (PTy->isFloat16Type() || PTy->isHalfType()) { |
| 4568 | + Load = EmitCMSEClearFP16(Load); |
| 4569 | + } else { |
| 4570 | + // Small struct/union types are passed as integer arrays. |
| 4571 | + auto *ATy = dyn_cast<llvm::ArrayType>(Load->getType()); |
| 4572 | + if (ATy != nullptr && isa<RecordType>(I->Ty.getCanonicalType())) |
| 4573 | + Load = EmitCMSEClearRecord(Load, ATy, I->Ty); |
| 4574 | + } |
| 4575 | + } |
| 4576 | + IRCallArgs[FirstIRArg] = Load; |
4337 | 4577 | }
|
4338 | 4578 |
|
4339 | 4579 | break;
|
|
0 commit comments