-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[llvm] Implement address sanitizer on AIX #129926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -118,6 +118,9 @@ static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46; | |
static const uint64_t kNetBSDKasan_ShadowOffset64 = 0xdfff900000000000; | ||
static const uint64_t kPS_ShadowOffset64 = 1ULL << 40; | ||
static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; | ||
static const uint64_t kAIXShadowOffset32 = 0x40000000; | ||
// 64-BIT AIX is not yet ready. | ||
static const uint64_t kAIXShadowOffset64 = 0x0a01000000000000ULL; | ||
static const uint64_t kWebAssemblyShadowOffset = 0; | ||
|
||
// The shadow memory space is dynamically allocated. | ||
|
@@ -128,6 +131,8 @@ static const size_t kMaxStackMallocSize = 1 << 16; // 64K | |
static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; | ||
static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E; | ||
|
||
static const uint32_t kAIXHighBits = 6; | ||
|
||
const char kAsanModuleCtorName[] = "asan.module_ctor"; | ||
const char kAsanModuleDtorName[] = "asan.module_dtor"; | ||
static const uint64_t kAsanCtorAndDtorPriority = 1; | ||
|
@@ -463,11 +468,14 @@ namespace { | |
|
||
/// This struct defines the shadow mapping using the rule: | ||
/// shadow = (mem >> Scale) ADD-or-OR Offset. | ||
/// However, on 64-bit AIX, we use HighBits to reduce the mapped address space: | ||
/// shadow = ((mem << HighBits) >> (HighBits + Scale)) + Offset | ||
/// If InGlobal is true, then | ||
/// extern char __asan_shadow[]; | ||
/// shadow = (mem >> Scale) + &__asan_shadow | ||
struct ShadowMapping { | ||
int Scale; | ||
int HighBits; | ||
uint64_t Offset; | ||
bool OrShadowOffset; | ||
bool InGlobal; | ||
|
@@ -487,6 +495,7 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, | |
bool IsLinux = TargetTriple.isOSLinux(); | ||
bool IsPPC64 = TargetTriple.getArch() == Triple::ppc64 || | ||
TargetTriple.getArch() == Triple::ppc64le; | ||
bool IsAIX = TargetTriple.isOSAIX(); | ||
jakeegan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
bool IsSystemZ = TargetTriple.getArch() == Triple::systemz; | ||
bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; | ||
bool IsMIPSN32ABI = TargetTriple.isABIN32(); | ||
|
@@ -525,6 +534,8 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, | |
Mapping.Offset = kDynamicShadowSentinel; | ||
else if (IsWindows) | ||
Mapping.Offset = kWindowsShadowOffset32; | ||
else if (IsAIX) | ||
Mapping.Offset = kAIXShadowOffset32; | ||
else if (IsWasm) | ||
Mapping.Offset = kWebAssemblyShadowOffset; | ||
else | ||
|
@@ -534,7 +545,9 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, | |
// space is always available. | ||
if (IsFuchsia) | ||
Mapping.Offset = 0; | ||
else if (IsPPC64) | ||
else if (IsAIX) | ||
Mapping.Offset = kAIXShadowOffset64; | ||
else if (IsPPC64 && !IsAIX) | ||
Mapping.Offset = kPPC64_ShadowOffset64; | ||
else if (IsSystemZ) | ||
Mapping.Offset = kSystemZ_ShadowOffset64; | ||
|
@@ -596,13 +609,16 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize, | |
// SystemZ, we could OR the constant in a single instruction, but it's more | ||
// efficient to load it once and use indexed addressing. | ||
Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS && | ||
!IsRISCV64 && !IsLoongArch64 && | ||
!IsRISCV64 && !IsLoongArch64 && !IsAIX && | ||
!(Mapping.Offset & (Mapping.Offset - 1)) && | ||
Mapping.Offset != kDynamicShadowSentinel; | ||
bool IsAndroidWithIfuncSupport = | ||
IsAndroid && !TargetTriple.isAndroidVersionLT(21); | ||
Mapping.InGlobal = ClWithIfunc && IsAndroidWithIfuncSupport && IsArmOrThumb; | ||
|
||
if (IsAIX && LongSize == 64) | ||
Mapping.HighBits = kAIXHighBits; | ||
|
||
return Mapping; | ||
} | ||
|
||
|
@@ -1380,7 +1396,11 @@ static bool isUnsupportedAMDGPUAddrspace(Value *Addr) { | |
|
||
Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) { | ||
// Shadow >> scale | ||
Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); | ||
if (TargetTriple.isOSAIX() && TargetTriple.getArch() == Triple::ppc64) | ||
Shadow = IRB.CreateLShr(IRB.CreateShl(Shadow, Mapping.HighBits), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will ShadowBase has HighBits set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, does this mean that 0x090100000f000000 will have same shadow as 0x000100000f000000? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately I think we have to diverge from the default implementation because the address ranges on 64-bit AIX are large, resulting in a large shadow region, so we use HIGH_BITS to limit it. More details on the mapping: 0x90100000f000000 is mapped to 0x20200001e00000 while 0x100000f000000 is mapped to 0x200001e00000 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still confused with HIGH_BITS purpose.
Mapping should be
Same amount of shadow. Why this does not work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A large part of the address space is reserved by the OS and not available to the compiler/runtime. The mapping scheme Jake is using is because we have to map the shadow memory into the mmap range from |
||
Mapping.Scale + Mapping.HighBits); | ||
else | ||
Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); | ||
if (Mapping.Offset == 0) return Shadow; | ||
// (Shadow >> scale) | offset | ||
Value *ShadowBase; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
; Test shadow memory mapping on AIX | ||
|
||
; RUN: opt -passes=asan -mtriple=powerpc64-ibm-aix -S < %s | FileCheck %s -check-prefix=CHECK-64 | ||
; RUN: opt -passes=asan -mtriple=powerpc-ibm-aix -S < %s | FileCheck %s -check-prefix=CHECK-32 | ||
|
||
; CHECK: @test | ||
; On 64-bit AIX, we expect a left shift of 6 (HIGH_BITS) followed by a right shift of 9 (HIGH_BITS | ||
; + ASAN_SHADOW_SCALE) and an offset of 0x0a01000000000000. | ||
; CHECK-64: shl {{.*}} 6 | ||
; CHECK-64-NEXT: lshr {{.*}} 9 | ||
; CHECK-64-NEXT: add {{.*}} 720857415355990016 | ||
; On 32-bit AIX, we expect just a right shift of 3 and an offset of 0x40000000. | ||
; CHECK-32: lshr {{.*}} 3 | ||
; CHECK-32-NEXT: add {{.*}} 1073741824 | ||
; CHECK: ret | ||
|
||
define i32 @test(i32* %a) sanitize_address { | ||
entry: | ||
%tmp1 = load i32, i32* %a, align 4 | ||
ret i32 %tmp1 | ||
} |
Uh oh!
There was an error while loading. Please reload this page.