Skip to content

Commit 7b4b43b

Browse files
authored
[MSan] Separated PPC32 va_arg helper from PPC64 (#131827)
With more understanding of PowerPC32 ABI we've rewritten the `VarArgPowerPC32Helper`. New implementation fills shadow for both `reg_save_area` and `overflow_arg_area`. It does not copy shadow for floating-point arguments, as they are stored in a separate space. This implementation does not fully support passing arguments `byVal`. This will be fixed in future PRs. Tests were also updated via `llvm/utils/update_test_checks.py`.
1 parent a0d4490 commit 7b4b43b

File tree

4 files changed

+796
-741
lines changed

4 files changed

+796
-741
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 109 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6399,8 +6399,8 @@ struct VarArgPowerPC64Helper : public VarArgHelperBase {
63996399
Value *VAArgSize = nullptr;
64006400

64016401
VarArgPowerPC64Helper(Function &F, MemorySanitizer &MS,
6402-
MemorySanitizerVisitor &MSV, unsigned VAListTagSize)
6403-
: VarArgHelperBase(F, MS, MSV, VAListTagSize) {}
6402+
MemorySanitizerVisitor &MSV)
6403+
: VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/8) {}
64046404

64056405
void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {
64066406
// For PowerPC, we need to deal with alignment of stack arguments -
@@ -6414,15 +6414,10 @@ struct VarArgPowerPC64Helper : public VarArgHelperBase {
64146414
// Parameter save area starts at 48 bytes from frame pointer for ABIv1,
64156415
// and 32 bytes for ABIv2. This is usually determined by target
64166416
// endianness, but in theory could be overridden by function attribute.
6417-
if (TargetTriple.isPPC64()) {
6418-
if (TargetTriple.isPPC64ELFv2ABI())
6419-
VAArgBase = 32;
6420-
else
6421-
VAArgBase = 48;
6422-
} else {
6423-
// Parameter save area is 8 bytes from frame pointer in PPC32
6424-
VAArgBase = 8;
6425-
}
6417+
if (TargetTriple.isPPC64ELFv2ABI())
6418+
VAArgBase = 32;
6419+
else
6420+
VAArgBase = 48;
64266421
unsigned VAArgOffset = VAArgBase;
64276422
const DataLayout &DL = F.getDataLayout();
64286423
for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {
@@ -6524,11 +6519,6 @@ struct VarArgPowerPC64Helper : public VarArgHelperBase {
65246519
Value *VAListTag = OrigInst->getArgOperand(0);
65256520
Value *RegSaveAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);
65266521

6527-
// In PPC32 va_list_tag is a struct, whereas in PPC64 it's a pointer
6528-
if (!TargetTriple.isPPC64()) {
6529-
RegSaveAreaPtrPtr =
6530-
IRB.CreateAdd(RegSaveAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 8));
6531-
}
65326522
RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);
65336523

65346524
Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);
@@ -6551,42 +6541,27 @@ struct VarArgPowerPC32Helper : public VarArgHelperBase {
65516541
Value *VAArgSize = nullptr;
65526542

65536543
VarArgPowerPC32Helper(Function &F, MemorySanitizer &MS,
6554-
MemorySanitizerVisitor &MSV, unsigned VAListTagSize)
6555-
: VarArgHelperBase(F, MS, MSV, VAListTagSize) {}
6544+
MemorySanitizerVisitor &MSV)
6545+
: VarArgHelperBase(F, MS, MSV, /*VAListTagSize=*/12) {}
65566546

65576547
void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override {
6558-
// For PowerPC, we need to deal with alignment of stack arguments -
6559-
// they are mostly aligned to 8 bytes, but vectors and i128 arrays
6560-
// are aligned to 16 bytes, byvals can be aligned to 8 or 16 bytes,
6561-
// For that reason, we compute current offset from stack pointer (which is
6562-
// always properly aligned), and offset for the first vararg, then subtract
6563-
// them.
65646548
unsigned VAArgBase;
65656549
Triple TargetTriple(F.getParent()->getTargetTriple());
6566-
// Parameter save area starts at 48 bytes from frame pointer for ABIv1,
6567-
// and 32 bytes for ABIv2. This is usually determined by target
6568-
// endianness, but in theory could be overridden by function attribute.
6569-
if (TargetTriple.isPPC64()) {
6570-
if (TargetTriple.isPPC64ELFv2ABI())
6571-
VAArgBase = 32;
6572-
else
6573-
VAArgBase = 48;
6574-
} else {
6575-
// Parameter save area is 8 bytes from frame pointer in PPC32
6576-
VAArgBase = 8;
6577-
}
6550+
// Parameter save area is 8 bytes from frame pointer in PPC32
6551+
VAArgBase = 8;
65786552
unsigned VAArgOffset = VAArgBase;
65796553
const DataLayout &DL = F.getDataLayout();
6554+
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
65806555
for (const auto &[ArgNo, A] : llvm::enumerate(CB.args())) {
65816556
bool IsFixed = ArgNo < CB.getFunctionType()->getNumParams();
65826557
bool IsByVal = CB.paramHasAttr(ArgNo, Attribute::ByVal);
65836558
if (IsByVal) {
65846559
assert(A->getType()->isPointerTy());
65856560
Type *RealTy = CB.getParamByValType(ArgNo);
65866561
uint64_t ArgSize = DL.getTypeAllocSize(RealTy);
6587-
Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(8));
6588-
if (ArgAlign < 8)
6589-
ArgAlign = Align(8);
6562+
Align ArgAlign = CB.getParamAlign(ArgNo).value_or(Align(IntptrSize));
6563+
if (ArgAlign < IntptrSize)
6564+
ArgAlign = Align(IntptrSize);
65906565
VAArgOffset = alignTo(VAArgOffset, ArgAlign);
65916566
if (!IsFixed) {
65926567
Value *Base =
@@ -6601,41 +6576,47 @@ struct VarArgPowerPC32Helper : public VarArgHelperBase {
66016576
kShadowTLSAlignment, ArgSize);
66026577
}
66036578
}
6604-
VAArgOffset += alignTo(ArgSize, Align(8));
6579+
VAArgOffset += alignTo(ArgSize, Align(IntptrSize));
66056580
} else {
66066581
Value *Base;
6607-
uint64_t ArgSize = DL.getTypeAllocSize(A->getType());
6608-
Align ArgAlign = Align(8);
6609-
if (A->getType()->isArrayTy()) {
6610-
// Arrays are aligned to element size, except for long double
6611-
// arrays, which are aligned to 8 bytes.
6612-
Type *ElementTy = A->getType()->getArrayElementType();
6613-
if (!ElementTy->isPPC_FP128Ty())
6614-
ArgAlign = Align(DL.getTypeAllocSize(ElementTy));
6615-
} else if (A->getType()->isVectorTy()) {
6616-
// Vectors are naturally aligned.
6617-
ArgAlign = Align(ArgSize);
6618-
}
6619-
if (ArgAlign < 8)
6620-
ArgAlign = Align(8);
6621-
VAArgOffset = alignTo(VAArgOffset, ArgAlign);
6622-
if (DL.isBigEndian()) {
6623-
// Adjusting the shadow for argument with size < 8 to match the
6624-
// placement of bits in big endian system
6625-
if (ArgSize < 8)
6626-
VAArgOffset += (8 - ArgSize);
6627-
}
6628-
if (!IsFixed) {
6629-
Base =
6630-
getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase, ArgSize);
6631-
if (Base)
6632-
IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment);
6582+
Type *ArgTy = A->getType();
6583+
6584+
// On PPC 32 floating point variable arguments are stored in separate
6585+
// area: fp_save_area = reg_save_area + 4*8. We do not copy shaodow for
6586+
// them as they will be found when checking call arguments.
6587+
if (!ArgTy->isFloatingPointTy()) {
6588+
uint64_t ArgSize = DL.getTypeAllocSize(ArgTy);
6589+
Align ArgAlign = Align(IntptrSize);
6590+
if (ArgTy->isArrayTy()) {
6591+
// Arrays are aligned to element size, except for long double
6592+
// arrays, which are aligned to 8 bytes.
6593+
Type *ElementTy = ArgTy->getArrayElementType();
6594+
if (!ElementTy->isPPC_FP128Ty())
6595+
ArgAlign = Align(DL.getTypeAllocSize(ElementTy));
6596+
} else if (ArgTy->isVectorTy()) {
6597+
// Vectors are naturally aligned.
6598+
ArgAlign = Align(ArgSize);
6599+
}
6600+
if (ArgAlign < IntptrSize)
6601+
ArgAlign = Align(IntptrSize);
6602+
VAArgOffset = alignTo(VAArgOffset, ArgAlign);
6603+
if (DL.isBigEndian()) {
6604+
// Adjusting the shadow for argument with size < IntptrSize to match
6605+
// the placement of bits in big endian system
6606+
if (ArgSize < IntptrSize)
6607+
VAArgOffset += (IntptrSize - ArgSize);
6608+
}
6609+
if (!IsFixed) {
6610+
Base = getShadowPtrForVAArgument(IRB, VAArgOffset - VAArgBase,
6611+
ArgSize);
6612+
if (Base)
6613+
IRB.CreateAlignedStore(MSV.getShadow(A), Base,
6614+
kShadowTLSAlignment);
6615+
}
6616+
VAArgOffset += ArgSize;
6617+
VAArgOffset = alignTo(VAArgOffset, Align(IntptrSize));
66336618
}
6634-
VAArgOffset += ArgSize;
6635-
VAArgOffset = alignTo(VAArgOffset, Align(8));
66366619
}
6637-
if (IsFixed)
6638-
VAArgBase = VAArgOffset;
66396620
}
66406621

66416622
Constant *TotalVAArgSize =
@@ -6675,24 +6656,68 @@ struct VarArgPowerPC32Helper : public VarArgHelperBase {
66756656
NextNodeIRBuilder IRB(OrigInst);
66766657
Value *VAListTag = OrigInst->getArgOperand(0);
66776658
Value *RegSaveAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);
6659+
Value *RegSaveAreaSize = CopySize;
66786660

6679-
// In PPC32 va_list_tag is a struct, whereas in PPC64 it's a pointer
6680-
if (!TargetTriple.isPPC64()) {
6681-
RegSaveAreaPtrPtr =
6682-
IRB.CreateAdd(RegSaveAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 8));
6683-
}
6684-
RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);
6661+
// In PPC32 va_list_tag is a struct
6662+
RegSaveAreaPtrPtr =
6663+
IRB.CreateAdd(RegSaveAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 8));
6664+
6665+
// On PPC 32 reg_save_area can only hold 32 bytes of data
6666+
RegSaveAreaSize = IRB.CreateBinaryIntrinsic(
6667+
Intrinsic::umin, CopySize, ConstantInt::get(MS.IntptrTy, 32));
66856668

6669+
RegSaveAreaPtrPtr = IRB.CreateIntToPtr(RegSaveAreaPtrPtr, MS.PtrTy);
66866670
Value *RegSaveAreaPtr = IRB.CreateLoad(MS.PtrTy, RegSaveAreaPtrPtr);
6687-
Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;
6671+
66886672
const DataLayout &DL = F.getDataLayout();
66896673
unsigned IntptrSize = DL.getTypeStoreSize(MS.IntptrTy);
66906674
const Align Alignment = Align(IntptrSize);
6691-
std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =
6692-
MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),
6693-
Alignment, /*isStore*/ true);
6694-
IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment,
6695-
CopySize);
6675+
6676+
{ // Copy reg save area
6677+
Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr;
6678+
std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) =
6679+
MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(),
6680+
Alignment, /*isStore*/ true);
6681+
IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy,
6682+
Alignment, RegSaveAreaSize);
6683+
6684+
RegSaveAreaShadowPtr =
6685+
IRB.CreatePtrToInt(RegSaveAreaShadowPtr, MS.IntptrTy);
6686+
Value *FPSaveArea = IRB.CreateAdd(RegSaveAreaShadowPtr,
6687+
ConstantInt::get(MS.IntptrTy, 32));
6688+
FPSaveArea = IRB.CreateIntToPtr(FPSaveArea, MS.PtrTy);
6689+
// We fill fp shadow with zeroes as uninitialized fp args should have
6690+
// been found during call base check
6691+
IRB.CreateMemSet(FPSaveArea, ConstantInt::getNullValue(IRB.getInt8Ty()),
6692+
ConstantInt::get(MS.IntptrTy, 32), Alignment);
6693+
}
6694+
6695+
{ // Copy overflow area
6696+
// RegSaveAreaSize is min(CopySize, 32) -> no overflow can occur
6697+
Value *OverflowAreaSize = IRB.CreateSub(CopySize, RegSaveAreaSize);
6698+
6699+
Value *OverflowAreaPtrPtr = IRB.CreatePtrToInt(VAListTag, MS.IntptrTy);
6700+
OverflowAreaPtrPtr =
6701+
IRB.CreateAdd(OverflowAreaPtrPtr, ConstantInt::get(MS.IntptrTy, 4));
6702+
OverflowAreaPtrPtr = IRB.CreateIntToPtr(OverflowAreaPtrPtr, MS.PtrTy);
6703+
6704+
Value *OverflowAreaPtr = IRB.CreateLoad(MS.PtrTy, OverflowAreaPtrPtr);
6705+
6706+
Value *OverflowAreaShadowPtr, *OverflowAreaOriginPtr;
6707+
std::tie(OverflowAreaShadowPtr, OverflowAreaOriginPtr) =
6708+
MSV.getShadowOriginPtr(OverflowAreaPtr, IRB, IRB.getInt8Ty(),
6709+
Alignment, /*isStore*/ true);
6710+
6711+
Value *OverflowVAArgTLSCopyPtr =
6712+
IRB.CreatePtrToInt(VAArgTLSCopy, MS.IntptrTy);
6713+
OverflowVAArgTLSCopyPtr =
6714+
IRB.CreateAdd(OverflowVAArgTLSCopyPtr, RegSaveAreaSize);
6715+
6716+
OverflowVAArgTLSCopyPtr =
6717+
IRB.CreateIntToPtr(OverflowVAArgTLSCopyPtr, MS.PtrTy);
6718+
IRB.CreateMemCpy(OverflowAreaShadowPtr, Alignment,
6719+
OverflowVAArgTLSCopyPtr, Alignment, OverflowAreaSize);
6720+
}
66966721
}
66976722
}
66986723
};
@@ -7220,10 +7245,10 @@ static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan,
72207245
// On PowerPC32 VAListTag is a struct
72217246
// {char, char, i16 padding, char *, char *}
72227247
if (TargetTriple.isPPC32())
7223-
return new VarArgPowerPC32Helper(Func, Msan, Visitor, /*VAListTagSize=*/12);
7248+
return new VarArgPowerPC32Helper(Func, Msan, Visitor);
72247249

72257250
if (TargetTriple.isPPC64())
7226-
return new VarArgPowerPC64Helper(Func, Msan, Visitor, /*VAListTagSize=*/8);
7251+
return new VarArgPowerPC64Helper(Func, Msan, Visitor);
72277252

72287253
if (TargetTriple.isRISCV32())
72297254
return new VarArgRISCVHelper(Func, Msan, Visitor, /*VAListTagSize=*/4);

0 commit comments

Comments
 (0)