LLVM IR and Naked functions in C/C++

Hi,

I’ve recently been investigating problems with using naked functions in Clang where portions of the stack are overwritten in debug builds. This happens on all architectures I’ve tested (x86, x64, ARM) and is evident in the LLVM IR itself. With the svn builds of clang, there’s an additional problem where undefined results are being introduced

First to show what I’m discussing:

test.cpp:

__attribute((noinline, naked)) int NakedTest(int value, int value2)
{
asm(“”);
}

Example using svn r167616 of clang/llvm:

clang -S test.cpp

.section __TEXT,__text,regular,pure_instructions
.globl __Z9NakedTestii
.align 4, 0x90
__Z9NakedTestii: ## @_Z9NakedTestii
.cfi_startproc

BB#0: ## %entry

movl %edi, -8(%rbp)
movl %esi, -12(%rbp)

InlineAsm Start

InlineAsm End

ud2
.cfi_endproc

The first two highlighted lines are overwriting memory unexpected. The ud2 causes a runtime failure on all naked functions with a return type.

The same test.cpp compiled with Xcode 4.5.2’s version of clang:

.section __TEXT,__text,regular,pure_instructions
.globl __Z9NakedTestii
.align 4, 0x90
__Z9NakedTestii: ## @_Z9NakedTestii
.cfi_startproc

BB#0:

movl %edi, -8(%rbp)
movl %esi, -12(%rbp)

InlineAsm Start

InlineAsm End

movl -4(%rbp), %eax
ret
.cfi_endproc

I’ve developed a patch for clang that fixes these issues; however, upon review from Eli Friedman, one of the changes that I had to make was particularly concerning to him and he suggested that I post to this list for discussion – it’s a change required in VMCore/Verifier.cpp.

When we have a naked function, I’m always generating a ret void instruction in LLVM IR. This is even if the function has a signature that specifies a return type, but I need to do this so that the debug code generators don’t insert any extra code to setup the return value. This fails the verifier (which complains that return type of function doesn’t match return type instruction found), however, I believe that for naked functions (where all the body of the function would be written in “asm” sections), that this is actually what is necessary.

So I have a patch that checks for this (attached):

The question is: Am I doing anything that is fundamentally wrong? Will this cause any problems with the LLVM optimisers? Note that naked functions are also implicitly “noinline”

Thanks for your time,

Jeffrey Lim

llvm.naked.patch (1.89 KB)