Skip to content

Commit d9e2fb7

Browse files
k-kashapovKamil Kashapovvitalybuka
authored
[msan] Add 32-bit platforms support (#109284)
References #103057 Added `VAArgHelper` functions for platforms: ARM32, i386, RISC-V, PowerPC32, MIPS32. ARM, RISCV and MIPS share similar conventions regarding va args. Therefore `VAArgGenericHelper` was introduced to avoid code duplication. --------- Co-authored-by: Kamil Kashapov <[email protected]> Co-authored-by: Vitaly Buka <[email protected]>
1 parent ec1e0c5 commit d9e2fb7

20 files changed

+1501
-1095
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 192 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ static const MemoryMapParams Linux_X86_64_MemoryMapParams = {
411411
0x100000000000, // OriginBase
412412
};
413413

414+
// mips32 Linux
415+
// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests
416+
// after picking good constants
417+
414418
// mips64 Linux
415419
static const MemoryMapParams Linux_MIPS64_MemoryMapParams = {
416420
0, // AndMask (not used)
@@ -419,6 +423,10 @@ static const MemoryMapParams Linux_MIPS64_MemoryMapParams = {
419423
0x002000000000, // OriginBase
420424
};
421425

426+
// ppc32 Linux
427+
// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests
428+
// after picking good constants
429+
422430
// ppc64 Linux
423431
static const MemoryMapParams Linux_PowerPC64_MemoryMapParams = {
424432
0xE00000000000, // AndMask
@@ -435,6 +443,10 @@ static const MemoryMapParams Linux_S390X_MemoryMapParams = {
435443
0x1C0000000000, // OriginBase
436444
};
437445

446+
// arm32 Linux
447+
// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests
448+
// after picking good constants
449+
438450
// aarch64 Linux
439451
static const MemoryMapParams Linux_AArch64_MemoryMapParams = {
440452
0, // AndMask (not used)
@@ -451,6 +463,10 @@ static const MemoryMapParams Linux_LoongArch64_MemoryMapParams = {
451463
0x100000000000, // OriginBase
452464
};
453465

466+
// riscv32 Linux
467+
// FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests
468+
// after picking good constants
469+
454470
// aarch64 FreeBSD
455471
static const MemoryMapParams FreeBSD_AArch64_MemoryMapParams = {
456472
0x1800000000000, // AndMask
@@ -559,6 +575,7 @@ class MemorySanitizer {
559575
friend struct VarArgAArch64Helper;
560576
friend struct VarArgPowerPCHelper;
561577
friend struct VarArgSystemZHelper;
578+
friend struct VarArgI386Helper;
562579
friend struct VarArgGenericHelper;
563580

564581
void initializeModule(Module &M);
@@ -5606,10 +5623,15 @@ struct VarArgPowerPCHelper : public VarArgHelperBase {
56065623
// Parameter save area starts at 48 bytes from frame pointer for ABIv1,
56075624
// and 32 bytes for ABIv2. This is usually determined by target
56085625
// endianness, but in theory could be overridden by function attribute.
5609-
if (TargetTriple.getArch() == Triple::ppc64)
5610-
VAArgBase = 48;
5611-
else
5612-
VAArgBase = 32;
5626+
if (TargetTriple.isPPC64()) {
5627+
if (TargetTriple.isPPC64ELFv2ABI())
5628+
VAArgBase = 32;
5629+
else
5630+
VAArgBase = 48;
5631+
} else {
5632+
// Parameter save area is 8 bytes from frame pointer in PPC32
5633+
VAArgBase = 8;
5634+
}
56135635
unsigned VAArgOffset = VAArgBase;
56145636
const DataLayout &DL = F.getDataLayout();
56155637
for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {
@@ -5674,7 +5696,7 @@ struct VarArgPowerPCHelper : public VarArgHelperBase {
56745696
}
56755697

56765698
Constant *TotalVAArgSize =
5677-
ConstantInt::get(IRB.getInt64Ty(), VAArgOffset - VAArgBase);
5699+
ConstantInt::get(MS.IntptrTy, VAArgOffset - VAArgBase);
56785700
// Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of
56795701
// a new class member i.e. it is the total size of all VarArgs.
56805702
IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);
@@ -5705,14 +5727,24 @@ struct VarArgPowerPCHelper : public VarArgHelperBase {
57055727

57065728
// Instrument va_start.
57075729
// Copy va_list shadow from the backup copy of the TLS contents.
5730+
Triple TargetTriple(F.getParent()->getTargetTriple());
57085731
for (CallInst *OrigInst : VAStartInstrumentationList) {
57095732
NextNodeIRBuilder IRB(OrigInst);
57105733
Value *VAListTag = OrigInst->getArgOperand(0);
5711-
Value *RegSaveAreaPtrPtr = IRB.CreateIntToPtr(
5712-
IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), MS.PtrTy);
5734+
Value *RegSaveAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);
5735+
5736+
// In PPC32 va_list_tag is a struct, whereas in PPC64 it's a pointer
5737+
if (!TargetTriple.isPPC64()) {
5738+
RegSaveAreaPtrPtr =
5739+
IRB.CreateAdd(RegSaveAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 8));
5740+
}
5741+
RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);
5742+
57135743
Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);
57145744
Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;
5715-
const Align Alignment = Align(8);
5745+
const DataLayout &DL = F.getDataLayout();
5746+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
5747+
const Align Alignment = Align(IntptrSize);
57165748
std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =
57175749
MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),
57185750
Alignment, /*isStore*/ true);
@@ -6003,8 +6035,118 @@ struct VarArgSystemZHelper : public VarArgHelperBase {
60036035
}
60046036
};
60056037

6006-
/// MIPS-specific implementation of VarArgHelper.
6007-
/// NOTE: This is also used for LoongArch64.
6038+
/// i386-specific implementation of VarArgHelper.
6039+
struct VarArgI386Helper : public VarArgHelperBase {
6040+
AllocaInst *VAArgTLSCopy = nullptr;
6041+
Value *VAArgSize = nullptr;
6042+
6043+
VarArgI386Helper(Function &F, MemorySanitizer &MS,
6044+
MemorySanitizerVisitor &MSV)
6045+
: VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/4) {}
6046+
6047+
void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {
6048+
const DataLayout &DL = F.getDataLayout();
6049+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
6050+
unsigned VAArgOffset = 0;
6051+
for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {
6052+
bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();
6053+
bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);
6054+
if (IsByVal) {
6055+
assert(A->getType()->isPointerTy());
6056+
Type *RealTy = CB.getParamByValType(ArgNo);
6057+
uint64_t ArgSize = DL.getTypeAllocSize(RealTy);
6058+
Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(IntptrSize));
6059+
if (ArgAlign < IntptrSize)
6060+
ArgAlign = Align(IntptrSize);
6061+
VAArgOffset = alignTo(VAArgOffset, ArgAlign);
6062+
if (!IsFixed) {
6063+
Value *Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);
6064+
if (Base) {
6065+
Value *AShadowPtr, *AOriginPtr;
6066+
std::tie(AShadowPtr, AOriginPtr) =
6067+
MSV.getShadowOriginPtr(A, IRB, IRB.getInt8Ty(),
6068+
kShadowTLSAlignment, /*isStore*/ false);
6069+
6070+
IRB.CreateMemCpy(Base, kShadowTLSAlignment, AShadowPtr,
6071+
kShadowTLSAlignment, ArgSize);
6072+
}
6073+
VAArgOffset += alignTo(ArgSize, Align(IntptrSize));
6074+
}
6075+
} else {
6076+
Value *Base;
6077+
uint64_t ArgSize = DL.getTypeAllocSize(A->getType());
6078+
Align ArgAlign = Align(IntptrSize);
6079+
VAArgOffset = alignTo(VAArgOffset, ArgAlign);
6080+
if (DL.isBigEndian()) {
6081+
// Adjusting the shadow for argument with size < IntptrSize to match
6082+
// the placement of bits in big endian system
6083+
if (ArgSize < IntptrSize)
6084+
VAArgOffset += (IntptrSize - ArgSize);
6085+
}
6086+
if (!IsFixed) {
6087+
Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);
6088+
if (Base)
6089+
IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);
6090+
VAArgOffset += ArgSize;
6091+
VAArgOffset = alignTo(VAArgOffset, Align(IntptrSize));
6092+
}
6093+
}
6094+
}
6095+
6096+
Constant *TotalVAArgSize = ConstantInt::get(MS.IntptrTy, VAArgOffset);
6097+
// Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of
6098+
// a new class member i.e. it is the total size of all VarArgs.
6099+
IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);
6100+
}
6101+
6102+
void finalizeInstrumentation() override {
6103+
assert(!VAArgSize && !VAArgTLSCopy &&
6104+
"finalizeInstrumentation called twice");
6105+
IRBuilder<> IRB(MSV.FnPrologueEnd);
6106+
VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS);
6107+
Value *CopySize = VAArgSize;
6108+
6109+
if (!VAStartInstrumentationList.empty()) {
6110+
// If there is a va_start in this function, make a backup copy of
6111+
// va_arg_tls somewhere in the function entry block.
6112+
VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize);
6113+
VAArgTLSCopy->setAlignment(kShadowTLSAlignment);
6114+
IRB.CreateMemSet(VAArgTLSCopy, Constant::getNullValue(IRB.getInt8Ty()),
6115+
CopySize, kShadowTLSAlignment, false);
6116+
6117+
Value *SrcSize = IRB.CreateBinaryIntrinsic(
6118+
Intrinsic::umin, CopySize,
6119+
ConstantInt::get(IRB.getInt64Ty(), kParamTLSSize));
6120+
IRB.CreateMemCpy(VAArgTLSCopy, kShadowTLSAlignment, MS.VAArgTLS,
6121+
kShadowTLSAlignment, SrcSize);
6122+
}
6123+
6124+
// Instrument va_start.
6125+
// Copy va_list shadow from the backup copy of the TLS contents.
6126+
for (CallInst *OrigInst : VAStartInstrumentationList) {
6127+
NextNodeIRBuilder IRB(OrigInst);
6128+
Value *VAListTag = OrigInst->getArgOperand(0);
6129+
Type *RegSaveAreaPtrTy = PointerType::getUnqual(*MS.C);
6130+
Value *RegSaveAreaPtrPtr =
6131+
IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),
6132+
PointerType::get(RegSaveAreaPtrTy, 0));
6133+
Value *RegSaveAreaPtr =
6134+
IRB.CreateLoad(RegSaveAreaPtrTy, RegSaveAreaPtrPtr);
6135+
Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;
6136+
const DataLayout &DL = F.getDataLayout();
6137+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
6138+
const Align Alignment = Align(IntptrSize);
6139+
std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =
6140+
MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),
6141+
Alignment, /*isStore*/ true);
6142+
IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,
6143+
CopySize);
6144+
}
6145+
}
6146+
};
6147+
6148+
/// Implementation of VarArgHelper that is used for ARM32, MIPS, RISCV,
6149+
/// LoongArch64.
60086150
struct VarArgGenericHelper : public VarArgHelperBase {
60096151
AllocaInst *VAArgTLSCopy = nullptr;
60106152
Value *VAArgSize = nullptr;
@@ -6016,24 +6158,25 @@ struct VarArgGenericHelper : public VarArgHelperBase {
60166158
void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {
60176159
unsigned VAArgOffset = 0;
60186160
const DataLayout &DL = F.getDataLayout();
6161+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
60196162
for (Value *A :
60206163
llvm::drop_begin(CB.args(), CB.getFunctionType()->getNumParams())) {
60216164
uint64_t ArgSize = DL.getTypeAllocSize(A->getType());
60226165
if (DL.isBigEndian()) {
6023-
// Adjusting the shadow for argument with size < 8 to match the
6166+
// Adjusting the shadow for argument with size < IntptrSize to match the
60246167
// placement of bits in big endian system
6025-
if (ArgSize < 8)
6026-
VAArgOffset += (8 - ArgSize);
6168+
if (ArgSize < IntptrSize)
6169+
VAArgOffset += (IntptrSize - ArgSize);
60276170
}
60286171
Value *Base = getShadowPtrForVAArgument(IRB, VAArgOffset, ArgSize);
60296172
VAArgOffset += ArgSize;
6030-
VAArgOffset = alignTo(VAArgOffset, 8);
6173+
VAArgOffset = alignTo(VAArgOffset, IntptrSize);
60316174
if (!Base)
60326175
continue;
60336176
IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);
60346177
}
60356178

6036-
Constant *TotalVAArgSize = ConstantInt::get(IRB.getInt64Ty(), VAArgOffset);
6179+
Constant *TotalVAArgSize = ConstantInt::get(MS.IntptrTy, VAArgOffset);
60376180
// Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of
60386181
// a new class member i.e. it is the total size of all VarArgs.
60396182
IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS);
@@ -6066,11 +6209,16 @@ struct VarArgGenericHelper : public VarArgHelperBase {
60666209
for (CallInst *OrigInst : VAStartInstrumentationList) {
60676210
NextNodeIRBuilder IRB(OrigInst);
60686211
Value *VAListTag = OrigInst->getArgOperand(0);
6069-
Value *RegSaveAreaPtrPtr = IRB.CreateIntToPtr(
6070-
IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), MS.PtrTy);
6071-
Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);
6212+
Type *RegSaveAreaPtrTy = PointerType::getUnqual(*MS.C);
6213+
Value *RegSaveAreaPtrPtr =
6214+
IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy),
6215+
PointerType::get(RegSaveAreaPtrTy, 0));
6216+
Value *RegSaveAreaPtr =
6217+
IRB.CreateLoad(RegSaveAreaPtrTy, RegSaveAreaPtrPtr);
60726218
Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;
6073-
const Align Alignment = Align(8);
6219+
const DataLayout &DL = F.getDataLayout();
6220+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
6221+
const Align Alignment = Align(IntptrSize);
60746222
std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =
60756223
MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),
60766224
Alignment, /*isStore*/ true);
@@ -6080,8 +6228,10 @@ struct VarArgGenericHelper : public VarArgHelperBase {
60806228
}
60816229
};
60826230

6083-
// Loongarch64 is not a MIPS, but the current vargs calling convention matches
6084-
// the MIPS.
6231+
// ARM32, Loongarch64, MIPS and RISCV share the same calling conventions
6232+
// regarding VAArgs.
6233+
using VarArgARM32Helper = VarArgGenericHelper;
6234+
using VarArgRISCVHelper = VarArgGenericHelper;
60856235
using VarArgMIPSHelper = VarArgGenericHelper;
60866236
using VarArgLoongArch64Helper = VarArgGenericHelper;
60876237

@@ -6106,18 +6256,39 @@ static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan,
61066256
// VarArg handling is only implemented on AMD64. False positives are possible
61076257
// on other platforms.
61086258
Triple TargetTriple(Func.getParent()->getTargetTriple());
6259+
6260+
if (TargetTriple.getArch() == Triple::x86)
6261+
return new VarArgI386Helper(Func, Msan, Visitor);
6262+
61096263
if (TargetTriple.getArch() == Triple::x86_64)
61106264
return new VarArgAMD64Helper(Func, Msan, Visitor);
61116265

6266+
if (TargetTriple.isARM())
6267+
return new VarArgARM32Helper(Func, Msan, Visitor, /*VAListTagSize=*/4);
6268+
61126269
if (TargetTriple.isAArch64())
61136270
return new VarArgAArch64Helper(Func, Msan, Visitor);
61146271

61156272
if (TargetTriple.isSystemZ())
61166273
return new VarArgSystemZHelper(Func, Msan, Visitor);
61176274

6275+
// On PowerPC32 VAListTag is a struct
6276+
// {char, char, i16 padding, char *, char *}
6277+
if (TargetTriple.isPPC32())
6278+
return new VarArgPowerPCHelper(Func, Msan, Visitor, /*VAListTagSize=*/12);
6279+
61186280
if (TargetTriple.isPPC64())
61196281
return new VarArgPowerPCHelper(Func, Msan, Visitor, /*VAListTagSize=*/8);
61206282

6283+
if (TargetTriple.isRISCV32())
6284+
return new VarArgRISCVHelper(Func, Msan, Visitor, /*VAListTagSize=*/4);
6285+
6286+
if (TargetTriple.isRISCV64())
6287+
return new VarArgRISCVHelper(Func, Msan, Visitor, /*VAListTagSize=*/8);
6288+
6289+
if (TargetTriple.isMIPS32())
6290+
return new VarArgMIPSHelper(Func, Msan, Visitor, /*VAListTagSize=*/4);
6291+
61216292
if (TargetTriple.isMIPS64())
61226293
return new VarArgMIPSHelper(Func, Msan, Visitor, /*VAListTagSize=*/8);
61236294

llvm/test/Instrumentation/MemorySanitizer/ARM32/vararg-arm32.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2-
; RUN: opt < %s -S -passes=msan 2>&1 | FileCheck %s
2+
; RUN: opt < %s -S -passes=msan -msan-origin-base=0x40000000 -msan-and-mask=0x80000000 2>&1 | FileCheck %s
33

44
target datalayout = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"
5-
target triple = "mips64--linux"
5+
target triple = "arm--linux"
66

77
define i32 @foo(i32 %guard, ...) {
88
; CHECK-LABEL: define i32 @foo(
@@ -15,20 +15,20 @@ define i32 @foo(i32 %guard, ...) {
1515
; CHECK-NEXT: call void @llvm.donothing()
1616
; CHECK-NEXT: [[VL:%.*]] = alloca ptr, align 8
1717
; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[VL]] to i64
18-
; CHECK-NEXT: [[TMP6:%.*]] = xor i64 [[TMP5]], 549755813888
18+
; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], -2147483649
1919
; CHECK-NEXT: [[TMP7:%.*]] = inttoptr i64 [[TMP6]] to ptr
2020
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP7]], i8 0, i64 8, i1 false)
2121
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr [[VL]])
2222
; CHECK-NEXT: [[TMP8:%.*]] = ptrtoint ptr [[VL]] to i64
23-
; CHECK-NEXT: [[TMP9:%.*]] = xor i64 [[TMP8]], 549755813888
23+
; CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], -2147483649
2424
; CHECK-NEXT: [[TMP10:%.*]] = inttoptr i64 [[TMP9]] to ptr
25-
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP10]], i8 0, i64 8, i1 false)
25+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[TMP10]], i8 0, i64 4, i1 false)
2626
; CHECK-NEXT: call void @llvm.va_start.p0(ptr [[VL]])
2727
; CHECK-NEXT: [[TMP11:%.*]] = ptrtoint ptr [[VL]] to i64
2828
; CHECK-NEXT: [[TMP12:%.*]] = inttoptr i64 [[TMP11]] to ptr
2929
; CHECK-NEXT: [[TMP13:%.*]] = load ptr, ptr [[TMP12]], align 8
3030
; CHECK-NEXT: [[TMP14:%.*]] = ptrtoint ptr [[TMP13]] to i64
31-
; CHECK-NEXT: [[TMP15:%.*]] = xor i64 [[TMP14]], 549755813888
31+
; CHECK-NEXT: [[TMP15:%.*]] = and i64 [[TMP14]], -2147483649
3232
; CHECK-NEXT: [[TMP16:%.*]] = inttoptr i64 [[TMP15]] to ptr
3333
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[TMP16]], ptr align 8 [[TMP3]], i64 [[TMP2]], i1 false)
3434
; CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VL]])

0 commit comments

Comments
 (0)