Asan code size overhead

Hi Kcc,

I’m trying enabling the Asan in my firmware, but I find the asan instrumentation code size impact is too big for me. I just implement necessary firmware version runtime library functions (e.g. __asan_report_load8) with blank body firstly to pass the asan enabled build, but I find the new binary code size is already ~2.5 times as original one with asan disabled in GCC. I know Linux kernel already enabled the asan (a.k.a Kasan), and is there any magic of asan for Linux to control its code size impact? Please advise how to mitigate the asan code size overhead.

Steven Shi

Intel\SSG\STO\UEFI Firmware

Tel: +86 021-61166522

iNet: 821-6522

Hi Kcc,

I’m trying enabling the Asan in my firmware, but I find the asan
instrumentation code size impact is too big for me. I just implement
necessary firmware version runtime library functions (e.g.
__asan_report_load8) with blank body firstly to pass the asan enabled
build, but I find the new binary code size is already ~2.5 times as
original one with asan disabled in GCC. I know Linux kernel already enabled
the asan (a.k.a Kasan), and is there any magic of asan for Linux to control
its code size impact?

I don't think there is much magic.

Please advise how to mitigate the asan code size overhead.

First, need to figure out what parts of instrumentation increase the code
size the most.
Start from switching from inline instrumentation to instrumentation with
calls:
With Clang that is "-mllvm -asan-instrumentation-with-call-threshold=0",
gcc should have something similar.
W/o this flag the instrumentation will look like this:
.cfi_def_cfa_offset 16
movq %rdi, %rax
shrq $3, %rax
movb 2147450880(%rax), %al
testb %al, %al
jne .LBB0_1
.LBB0_3:
movl (%rdi), %eax
popq %rcx
retq
.LBB0_1:
movl %edi, %ecx
andl $7, %ecx
addl $3, %ecx
cmpb %al, %cl
jl .LBB0_3
# BB#2:
callq __asan_report_load4

With this flag it will look like this:
movq %rdi, %rbx
callq __asan_load4
movl (%rbx), %eax

Obviously, there is a cost in performance.

Clang (and recent gcc) also have a convenience
flag -fsanitize=kernel-address:
movq %rdi, %rbx
callq __asan_load4_noabort
movl (%rbx), %eax

If that does not solve your code size problem, let's look at it more.

--kcc

Hi Kcc,

Thank your advices.

Start from switching from inline instrumentation to instrumentation with calls:

With Clang that is “-mllvm -asan-instrumentation-with-call-threshold=0”, gcc should have something similar.

I see the call-threshold option force to use the calls and have same effect as -fsanitize=kernel-address in below code. Thanks.

http://llvm.org/svn/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp

line 1956:

bool UseCalls =

CompileKernel ||

(ClInstrumentationWithCallsThreshold >= 0 &&

ToInstrument.size() > (unsigned)ClInstrumentationWithCallsThreshold);

Obviously, there is a cost in performance.

The call cost to my firmware should be very low. (1) Not like CPU-intensive application, my firmware is an IO-intensive software, the boot performance bottleneck is usually because of slow IO response. If Asan instrumentation mainly bring overhead to CPU, it is not a big problem to my firmware. (2) Not like memory-intensive application, my firmware usually have sufficient system memory to use. If Asan mainly bring overhead to system memory consumption for shadow memory metadata, it is not a big problem for me too.

But my firmware usually care the code size, even in debug version. If my Asan-enabled firmware image size is too big, I cannot easily apply and run it on real HW.

Clang (and recent gcc) also have a convenience flag -fsanitize=kernel-address:

movq %rdi, %rbx

callq __asan_load4_noabort

movl (%rbx), %eax

I like the -fsanitize=kernel-address option, and I believe it better fit my firmware scenario rather than -fsanitize=address. I but after take a look at the current LLVM Asan implementation, I have some concerns that kernel-address might disable the global and stack instrumentations by default as below code. Does LLVM Asan really support -fsanitize=kernel-address to check glabal and stack buffer issues?

http://llvm.org/svn/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp

line 1723:

// TODO(glider): temporarily disabled globals instrumentation for KASan.

if (ClGlobals && !CompileKernel) {

Function *CtorFunc = M.getFunction(kAsanModuleCtorName);

assert(CtorFunc);

IRBuilder<> IRB(CtorFunc->getEntryBlock().getTerminator());

Changed |= InstrumentGlobals(IRB, M);

}

Line2287:

bool DoStackMalloc = ClUseAfterReturn && !ASan.CompileKernel &&

LocalStackSize <= kMaxStackMallocSize;

Thanks

Steven