mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-13 05:40:59 +00:00
[asan] Use dynamic shadow on 32-bit Android, try 2.
Summary: This change reverts r318575 and changes FindDynamicShadowStart() to keep the memory range it found mapped PROT_NONE to make sure it is not reused. We also skip MemoryRangeIsAvailable() check, because it is (a) unnecessary, and (b) would fail anyway. Reviewers: pcc, vitalybuka, kcc Subscribers: srhines, kubamracek, mgorny, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D40203 llvm-svn: 318666
This commit is contained in:
parent
9541975071
commit
8e7018d92f
@ -21,6 +21,7 @@ set(ASAN_SOURCES
|
||||
asan_memory_profile.cc
|
||||
asan_poisoning.cc
|
||||
asan_posix.cc
|
||||
asan_premap_shadow.cc
|
||||
asan_report.cc
|
||||
asan_rtl.cc
|
||||
asan_shadow_setup.cc
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef ASAN_INIT_VERSION_H
|
||||
#define ASAN_INIT_VERSION_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_platform.h"
|
||||
|
||||
extern "C" {
|
||||
// Every time the ASan ABI changes we also change the version number in the
|
||||
// __asan_init function name. Objects built with incompatible ASan ABI
|
||||
@ -32,7 +34,12 @@ extern "C" {
|
||||
// v6=>v7: added 'odr_indicator' to __asan_global
|
||||
// v7=>v8: added '__asan_(un)register_image_globals' functions for dead
|
||||
// stripping support on Mach-O platforms
|
||||
#if SANITIZER_WORDSIZE == 32 && SANITIZER_ANDROID
|
||||
// v8=>v9: 32-bit Android switched to dynamic shadow
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v9
|
||||
#else
|
||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ASAN_INIT_VERSION_H
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "asan_interceptors.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_premap_shadow.h"
|
||||
#include "asan_thread.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_freebsd.h"
|
||||
@ -81,9 +82,51 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||
return &_DYNAMIC; // defined in link.h
|
||||
}
|
||||
|
||||
static void UnmapFromTo(uptr from, uptr to) {
|
||||
CHECK(to >= from);
|
||||
if (to == from) return;
|
||||
uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
|
||||
if (UNLIKELY(internal_iserror(res))) {
|
||||
Report(
|
||||
"ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
|
||||
"%p\n",
|
||||
to - from, to - from, from);
|
||||
CHECK("unable to unmap" && 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
uptr FindPremappedShadowStart() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
|
||||
uptr premap_shadow_size = PremapShadowSize();
|
||||
uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
|
||||
// We may have mapped too much. Release extra memory.
|
||||
UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
|
||||
return shadow_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
uptr FindDynamicShadowStart() {
|
||||
UNREACHABLE("FindDynamicShadowStart is not available");
|
||||
return 0;
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
if (!PremapShadowFailed())
|
||||
return FindPremappedShadowStart();
|
||||
#endif
|
||||
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr alignment = granularity * 8;
|
||||
uptr left_padding = granularity;
|
||||
uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
|
||||
uptr map_size = shadow_size + left_padding + alignment;
|
||||
|
||||
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||
CHECK_NE(map_start, ~(uptr)0);
|
||||
|
||||
uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
|
||||
UnmapFromTo(map_start, shadow_start - left_padding);
|
||||
UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
|
||||
|
||||
return shadow_start;
|
||||
}
|
||||
|
||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||
|
@ -161,7 +161,7 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
# define SHADOW_OFFSET (0)
|
||||
#elif SANITIZER_WORDSIZE == 32
|
||||
# if SANITIZER_ANDROID
|
||||
# define SHADOW_OFFSET (0)
|
||||
# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
|
||||
# elif defined(__mips__)
|
||||
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
|
||||
# elif SANITIZER_FREEBSD
|
||||
@ -205,6 +205,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if SANITIZER_ANDROID && defined(__arm__)
|
||||
# define ASAN_PREMAP_SHADOW 1
|
||||
#else
|
||||
# define ASAN_PREMAP_SHADOW 0
|
||||
#endif
|
||||
|
||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
||||
|
||||
|
79
compiler-rt/lib/asan/asan_premap_shadow.cc
Normal file
79
compiler-rt/lib/asan/asan_premap_shadow.cc
Normal file
@ -0,0 +1,79 @@
|
||||
//===-- asan_premap_shadow.cc ---------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Reserve shadow memory with an ifunc resolver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_mapping.h"
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
|
||||
#include "asan_premap_shadow.h"
|
||||
#include "sanitizer_common/sanitizer_posix.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
// The code in this file needs to run in an unrelocated binary. It may not
|
||||
// access any external symbol, including its own non-hidden globals.
|
||||
|
||||
// Conservative upper limit.
|
||||
uptr PremapShadowSize() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
return RoundUpTo(GetMaxVirtualAddress() >> SHADOW_SCALE, granularity);
|
||||
}
|
||||
|
||||
// Returns an address aligned to 8 pages, such that one page on the left and
|
||||
// PremapShadowSize() bytes on the right of it are mapped r/o.
|
||||
uptr PremapShadow() {
|
||||
uptr granularity = GetMmapGranularity();
|
||||
uptr alignment = granularity * 8;
|
||||
uptr left_padding = granularity;
|
||||
uptr shadow_size = PremapShadowSize();
|
||||
uptr map_size = shadow_size + left_padding + alignment;
|
||||
|
||||
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||
CHECK_NE(map_start, ~(uptr)0);
|
||||
|
||||
uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
|
||||
uptr shadow_end = shadow_start + shadow_size;
|
||||
internal_munmap(reinterpret_cast<void *>(map_start),
|
||||
shadow_start - left_padding - map_start);
|
||||
internal_munmap(reinterpret_cast<void *>(shadow_end),
|
||||
map_start + map_size - shadow_end);
|
||||
return shadow_start;
|
||||
}
|
||||
|
||||
bool PremapShadowFailed() {
|
||||
uptr shadow = reinterpret_cast<uptr>(&__asan_shadow);
|
||||
uptr resolver = reinterpret_cast<uptr>(&__asan_premap_shadow);
|
||||
// shadow == resolver is how Android KitKat and older handles ifunc.
|
||||
// shadow == 0 just in case.
|
||||
if (shadow == 0 || shadow == resolver)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} // namespace __asan
|
||||
|
||||
extern "C" {
|
||||
decltype(__asan_shadow)* __asan_premap_shadow() {
|
||||
// The resolver may be called multiple times. Map the shadow just once.
|
||||
static uptr premapped_shadow = 0;
|
||||
if (!premapped_shadow) premapped_shadow = __asan::PremapShadow();
|
||||
return reinterpret_cast<decltype(__asan_shadow)*>(premapped_shadow);
|
||||
}
|
||||
|
||||
// __asan_shadow is a "function" that has the same address as the first byte of
|
||||
// the shadow mapping.
|
||||
INTERFACE_ATTRIBUTE __attribute__((ifunc("__asan_premap_shadow"))) void
|
||||
__asan_shadow();
|
||||
}
|
||||
|
||||
#endif // ASAN_PREMAP_SHADOW
|
30
compiler-rt/lib/asan/asan_premap_shadow.h
Normal file
30
compiler-rt/lib/asan/asan_premap_shadow.h
Normal file
@ -0,0 +1,30 @@
|
||||
//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// Premap shadow range with an ifunc resolver.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef ASAN_PREMAP_SHADOW_H
|
||||
#define ASAN_PREMAP_SHADOW_H
|
||||
|
||||
#if ASAN_PREMAP_SHADOW
|
||||
namespace __asan {
|
||||
// Conservative upper limit.
|
||||
uptr PremapShadowSize();
|
||||
bool PremapShadowFailed();
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" INTERFACE_ATTRIBUTE void __asan_shadow();
|
||||
extern "C" decltype(__asan_shadow)* __asan_premap_shadow();
|
||||
|
||||
#endif // ASAN_PREMAP_SHADOW_H
|
@ -99,17 +99,21 @@ void InitializeShadowMemory() {
|
||||
// when necessary. When dynamic address is used, the macro |kLowShadowBeg|
|
||||
// expands to |__asan_shadow_memory_dynamic_address| which is
|
||||
// |kDefaultShadowSentinel|.
|
||||
bool full_shadow_is_available = false;
|
||||
if (shadow_start == kDefaultShadowSentinel) {
|
||||
__asan_shadow_memory_dynamic_address = 0;
|
||||
CHECK_EQ(0, kLowShadowBeg);
|
||||
shadow_start = FindDynamicShadowStart();
|
||||
if (SANITIZER_LINUX) full_shadow_is_available = true;
|
||||
}
|
||||
// Update the shadow memory address (potentially) used by instrumentation.
|
||||
__asan_shadow_memory_dynamic_address = shadow_start;
|
||||
|
||||
if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
|
||||
bool full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
if (!full_shadow_is_available)
|
||||
full_shadow_is_available =
|
||||
MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
|
||||
|
||||
#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
|
||||
!ASAN_FIXED_MAPPING
|
||||
|
@ -73,6 +73,7 @@ INLINE uptr GetPageSizeCached() {
|
||||
return PageSizeCached;
|
||||
}
|
||||
uptr GetMmapGranularity();
|
||||
uptr GetMaxVirtualAddress();
|
||||
uptr GetMaxUserVirtualAddress();
|
||||
// Threads
|
||||
tid_t GetTid();
|
||||
|
@ -191,6 +191,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||
return ShadowBounds.memory_limit - 1;
|
||||
}
|
||||
|
||||
uptr GetMaxVirtualAddress() {
|
||||
return GetMaxUserVirtualAddress();
|
||||
}
|
||||
|
||||
static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
|
||||
bool raw_report, bool die_for_nomem) {
|
||||
size = RoundUpTo(size, PAGE_SIZE);
|
||||
|
@ -954,7 +954,7 @@ static uptr GetKernelAreaSize() {
|
||||
}
|
||||
#endif // SANITIZER_WORDSIZE == 32
|
||||
|
||||
uptr GetMaxUserVirtualAddress() {
|
||||
uptr GetMaxVirtualAddress() {
|
||||
#if SANITIZER_NETBSD && defined(__x86_64__)
|
||||
return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
|
||||
#elif SANITIZER_WORDSIZE == 64
|
||||
@ -978,15 +978,21 @@ uptr GetMaxUserVirtualAddress() {
|
||||
# if defined(__s390__)
|
||||
return (1ULL << 31) - 1; // 0x7fffffff;
|
||||
# else
|
||||
uptr res = (1ULL << 32) - 1; // 0xffffffff;
|
||||
if (!common_flags()->full_address_space)
|
||||
res -= GetKernelAreaSize();
|
||||
CHECK_LT(reinterpret_cast<uptr>(&res), res);
|
||||
return res;
|
||||
return (1ULL << 32) - 1; // 0xffffffff;
|
||||
# endif
|
||||
#endif // SANITIZER_WORDSIZE
|
||||
}
|
||||
|
||||
uptr GetMaxUserVirtualAddress() {
|
||||
uptr addr = GetMaxVirtualAddress();
|
||||
#if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
|
||||
if (!common_flags()->full_address_space)
|
||||
addr -= GetKernelAreaSize();
|
||||
CHECK_LT(reinterpret_cast<uptr>(&addr), addr);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
uptr GetPageSize() {
|
||||
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
|
||||
#if SANITIZER_ANDROID
|
||||
|
@ -864,6 +864,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||
#endif // SANITIZER_WORDSIZE
|
||||
}
|
||||
|
||||
uptr GetMaxVirtualAddress() {
|
||||
return GetMaxUserVirtualAddress();
|
||||
}
|
||||
|
||||
uptr FindAvailableMemoryRange(uptr shadow_size,
|
||||
uptr alignment,
|
||||
uptr left_padding,
|
||||
|
@ -70,6 +70,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||
return (uptr)si.lpMaximumApplicationAddress;
|
||||
}
|
||||
|
||||
uptr GetMaxVirtualAddress() {
|
||||
return GetMaxUserVirtualAddress();
|
||||
}
|
||||
|
||||
bool FileExists(const char *filename) {
|
||||
return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
@ -137,8 +137,8 @@ static const char *const kAsanUnregisterElfGlobalsName =
|
||||
static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
|
||||
static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
|
||||
static const char *const kAsanInitName = "__asan_init";
|
||||
static const char *const kAsanVersionCheckName =
|
||||
"__asan_version_mismatch_check_v8";
|
||||
static const char *const kAsanVersionCheckNamePrefix =
|
||||
"__asan_version_mismatch_check_v";
|
||||
static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
|
||||
static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
|
||||
static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
|
||||
@ -208,6 +208,18 @@ static cl::opt<bool> ClForceDynamicShadow(
|
||||
cl::desc("Load shadow address into a local variable for each function"),
|
||||
cl::Hidden, cl::init(false));
|
||||
|
||||
static cl::opt<bool>
|
||||
ClWithIfunc("asan-with-ifunc",
|
||||
cl::desc("Access dynamic shadow through an ifunc global on "
|
||||
"platforms that support this"),
|
||||
cl::Hidden, cl::init(true));
|
||||
|
||||
static cl::opt<bool> ClWithIfuncSuppressRemat(
|
||||
"asan-with-ifunc-suppress-remat",
|
||||
cl::desc("Suppress rematerialization of dynamic shadow address by passing "
|
||||
"it through inline asm in prologue."),
|
||||
cl::Hidden, cl::init(true));
|
||||
|
||||
// This flag limits the number of instructions to be instrumented
|
||||
// in any given BB. Normally, this should be set to unlimited (INT_MAX),
|
||||
// but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary
|
||||
@ -448,10 +460,14 @@ private:
|
||||
|
||||
/// This struct defines the shadow mapping using the rule:
|
||||
/// shadow = (mem >> Scale) ADD-or-OR Offset.
|
||||
/// If InGlobal is true, then
|
||||
/// extern char __asan_shadow[];
|
||||
/// shadow = (mem >> Scale) + &__asan_shadow
|
||||
struct ShadowMapping {
|
||||
int Scale;
|
||||
uint64_t Offset;
|
||||
bool OrShadowOffset;
|
||||
bool InGlobal;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -473,6 +489,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||
TargetTriple.getArch() == Triple::mipsel;
|
||||
bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 ||
|
||||
TargetTriple.getArch() == Triple::mips64el;
|
||||
bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb();
|
||||
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
||||
bool IsWindows = TargetTriple.isOSWindows();
|
||||
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
||||
@ -485,10 +502,8 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||
}
|
||||
|
||||
if (LongSize == 32) {
|
||||
// Android is always PIE, which means that the beginning of the address
|
||||
// space is always available.
|
||||
if (IsAndroid)
|
||||
Mapping.Offset = 0;
|
||||
Mapping.Offset = kDynamicShadowSentinel;
|
||||
else if (IsMIPS32)
|
||||
Mapping.Offset = kMIPS32_ShadowOffset32;
|
||||
else if (IsFreeBSD)
|
||||
@ -552,6 +567,9 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||
Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU &&
|
||||
!(Mapping.Offset & (Mapping.Offset - 1)) &&
|
||||
Mapping.Offset != kDynamicShadowSentinel;
|
||||
bool IsAndroidWithIfuncSupport =
|
||||
IsAndroid && !TargetTriple.isAndroidVersionLT(21);
|
||||
Mapping.InGlobal = ClWithIfunc && IsAndroidWithIfuncSupport && IsArmOrThumb;
|
||||
|
||||
return Mapping;
|
||||
}
|
||||
@ -674,6 +692,7 @@ private:
|
||||
DominatorTree *DT;
|
||||
Function *AsanHandleNoReturnFunc;
|
||||
Function *AsanPtrCmpFunction, *AsanPtrSubFunction;
|
||||
Constant *AsanShadowGlobal;
|
||||
|
||||
// These arrays is indexed by AccessIsWrite, Experiment and log2(AccessSize).
|
||||
Function *AsanErrorCallback[2][2][kNumberOfAccessSizes];
|
||||
@ -746,6 +765,7 @@ private:
|
||||
size_t MinRedzoneSizeForGlobal() const {
|
||||
return RedzoneSizeForScale(Mapping.Scale);
|
||||
}
|
||||
int GetAsanVersion(const Module &M) const;
|
||||
|
||||
GlobalsMetadata GlobalsMD;
|
||||
bool CompileKernel;
|
||||
@ -978,8 +998,9 @@ struct FunctionStackPoisoner : public InstVisitor<FunctionStackPoisoner> {
|
||||
void visitCallSite(CallSite CS) {
|
||||
Instruction *I = CS.getInstruction();
|
||||
if (CallInst *CI = dyn_cast<CallInst>(I)) {
|
||||
HasNonEmptyInlineAsm |=
|
||||
CI->isInlineAsm() && !CI->isIdenticalTo(EmptyInlineAsm.get());
|
||||
HasNonEmptyInlineAsm |= CI->isInlineAsm() &&
|
||||
!CI->isIdenticalTo(EmptyInlineAsm.get()) &&
|
||||
I != ASan.LocalDynamicShadow;
|
||||
HasReturnsTwiceCall |= CI->canReturnTwice();
|
||||
}
|
||||
}
|
||||
@ -2160,6 +2181,16 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
int AddressSanitizerModule::GetAsanVersion(const Module &M) const {
|
||||
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
||||
bool isAndroid = Triple(M.getTargetTriple()).isAndroid();
|
||||
int Version = 8;
|
||||
// 32-bit Android is one version ahead because of the switch to dynamic
|
||||
// shadow.
|
||||
Version += (LongSize == 32 && isAndroid);
|
||||
return Version;
|
||||
}
|
||||
|
||||
bool AddressSanitizerModule::runOnModule(Module &M) {
|
||||
C = &(M.getContext());
|
||||
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
||||
@ -2173,9 +2204,11 @@ bool AddressSanitizerModule::runOnModule(Module &M) {
|
||||
|
||||
// Create a module constructor. A destructor is created lazily because not all
|
||||
// platforms, and not all modules need it.
|
||||
std::string VersionCheckName =
|
||||
kAsanVersionCheckNamePrefix + std::to_string(GetAsanVersion(M));
|
||||
std::tie(AsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
|
||||
M, kAsanModuleCtorName, kAsanInitName, /*InitArgTypes=*/{},
|
||||
/*InitArgs=*/{}, kAsanVersionCheckName);
|
||||
/*InitArgs=*/{}, VersionCheckName);
|
||||
|
||||
bool CtorComdat = true;
|
||||
bool Changed = false;
|
||||
@ -2274,6 +2307,9 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
|
||||
EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false),
|
||||
StringRef(""), StringRef(""),
|
||||
/*hasSideEffects=*/true);
|
||||
if (Mapping.InGlobal)
|
||||
AsanShadowGlobal = M.getOrInsertGlobal("__asan_shadow",
|
||||
ArrayType::get(IRB.getInt8Ty(), 0));
|
||||
}
|
||||
|
||||
// virtual
|
||||
@ -2319,9 +2355,25 @@ void AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) {
|
||||
return;
|
||||
|
||||
IRBuilder<> IRB(&F.front().front());
|
||||
Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
|
||||
kAsanShadowMemoryDynamicAddress, IntptrTy);
|
||||
LocalDynamicShadow = IRB.CreateLoad(GlobalDynamicAddress);
|
||||
if (Mapping.InGlobal) {
|
||||
if (ClWithIfuncSuppressRemat) {
|
||||
// An empty inline asm with input reg == output reg.
|
||||
// An opaque pointer-to-int cast, basically.
|
||||
InlineAsm *Asm = InlineAsm::get(
|
||||
FunctionType::get(IntptrTy, {AsanShadowGlobal->getType()}, false),
|
||||
StringRef(""), StringRef("=r,0"),
|
||||
/*hasSideEffects=*/false);
|
||||
LocalDynamicShadow =
|
||||
IRB.CreateCall(Asm, {AsanShadowGlobal}, ".asan.shadow");
|
||||
} else {
|
||||
LocalDynamicShadow =
|
||||
IRB.CreatePointerCast(AsanShadowGlobal, IntptrTy, ".asan.shadow");
|
||||
}
|
||||
} else {
|
||||
Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
|
||||
kAsanShadowMemoryDynamicAddress, IntptrTy);
|
||||
LocalDynamicShadow = IRB.CreateLoad(GlobalDynamicAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressSanitizer::markEscapedLocalAllocas(Function &F) {
|
||||
|
47
llvm/test/Instrumentation/AddressSanitizer/with-ifunc.ll
Normal file
47
llvm/test/Instrumentation/AddressSanitizer/with-ifunc.ll
Normal file
@ -0,0 +1,47 @@
|
||||
; Test -asan-with-ifunc flag.
|
||||
;
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=0 < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOIFUNC
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 -asan-with-ifunc-suppress-remat=0 < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 -asan-with-ifunc-suppress-remat=1 < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC-NOREMAT
|
||||
|
||||
; Pre-Lollipop Android does not support ifunc.
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 -asan-with-ifunc-suppress-remat=0 -mtriple=armv7-linux-android20 < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOIFUNC
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 -asan-with-ifunc-suppress-remat=0 -mtriple=armv7-linux-android < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOIFUNC
|
||||
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 -asan-with-ifunc-suppress-remat=0 -mtriple=armv7-linux-android21 < %s | \
|
||||
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "armv7--linux-android22"
|
||||
|
||||
; CHECK-IFUNC: @__asan_shadow = external global [0 x i8]
|
||||
; CHECK-NOIFUNC: @__asan_shadow_memory_dynamic_address = external global i32
|
||||
|
||||
define i32 @test_load(i32* %a) sanitize_address {
|
||||
; First instrumentation in the function must be to load the dynamic shadow
|
||||
; address into a local variable.
|
||||
; CHECK-LABEL: @test_load
|
||||
; CHECK: entry:
|
||||
|
||||
; CHECK-IFUNC-NEXT: %[[A:[^ ]*]] = ptrtoint i32* %a to i32
|
||||
; CHECK-IFUNC-NEXT: %[[B:[^ ]*]] = lshr i32 %[[A]], 3
|
||||
; CHECK-IFUNC-NEXT: %[[C:[^ ]*]] = add i32 %[[B]], ptrtoint ([0 x i8]* @__asan_shadow to i32)
|
||||
|
||||
; CHECK-IFUNC-NOREMAT-NEXT: %[[S:[^ ]*]] = call i32 asm "", "=r,0"([0 x i8]* @__asan_shadow)
|
||||
; CHECK-IFUNC-NOREMAT-NEXT: %[[A:[^ ]*]] = ptrtoint i32* %a to i32
|
||||
; CHECK-IFUNC-NOREMAT-NEXT: %[[B:[^ ]*]] = lshr i32 %[[A]], 3
|
||||
; CHECK-IFUNC-NOREMAT-NEXT: %[[C:[^ ]*]] = add i32 %[[B]], %[[S]]
|
||||
|
||||
; CHECK-NOIFUNC-NEXT: %[[SHADOW:[^ ]*]] = load i32, i32* @__asan_shadow_memory_dynamic_address
|
||||
; CHECK-NOIFUNC-NEXT: %[[A:[^ ]*]] = ptrtoint i32* %a to i32
|
||||
; CHECK-NOIFUNC-NEXT: %[[B:[^ ]*]] = lshr i32 %[[A]], 3
|
||||
; CHECK-NOIFUNC-NEXT: %[[C:[^ ]*]] = add i32 %[[B]], %[[SHADOW]]
|
||||
|
||||
entry:
|
||||
%x = load i32, i32* %a, align 4
|
||||
ret i32 %x
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user