LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 28641 - Emit a warning if inline assembly with a clobber list is used inside a naked function.
Summary: Emit a warning if inline assembly with a clobber list is used inside a naked ...
Status: NEW
Alias: None
Product: libraries
Classification: Unclassified
Component: Register Allocator (show other bugs)
Version: trunk
Hardware: PC Windows NT
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-07-21 06:18 PDT by pierre gousseau
Modified: 2018-02-26 14:28 PST (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description pierre gousseau 2016-07-21 06:18:47 PDT
Having inline assembly with a clobber list in a function marked naked seems dangerous as this will alter the stack but only at -O0 in the case below, higher optimisations level are fine.

eg:
$ clang --version
clang version 3.9.0 @r276109
Target: x86_64-unknown-linux-gnu

  #include <stdlib.h>

  __attribute__((__naked__, __noinline__)) int foo(size_t) 
  {
    __asm__ __volatile__ (
      "ret" : : : "rdi"
    );
  }

$ clang -O0 -S test.cpp

# BB#0:                                 # %entry
        movq    %rdi, -16(%rbp)         # 8-byte Spill <- Stack altered
        #APP
        retq
        #NO_APP
Comment 1 Reid Kleckner 2016-07-21 08:17:47 PDT
Alternatively we could avoid generating code around inline asm if it appears in a naked function.
Comment 2 pierre gousseau 2016-07-21 09:24:10 PDT
(In reply to comment #1)
> Alternatively we could avoid generating code around inline asm if it appears
> in a naked function.

Yes, I think it depends whether clobbered list are meant to be supported inside naked functions, or are their behaviour undefined?

This gcc documentation https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#ARM-Function-Attributes seems to suggest that only "basic asm" is allowed in a naked function, clobbered list are considered "extended asm" I think.

Does it mean we could emit an undefined behaviour warning whenever a non "basic asm" statement is found in a naked function?
Comment 3 Evgenii Stepanov 2016-12-22 14:08:14 PST
FTR, we've got a use for simple input arguments in inline asm in naked functions, like this:

define void @f() #0 {
entry:
  call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(void ()* @f.cfi)
  unreachable
}

attributes #0 = { naked }

We use this to emit CFI jumptables, see https://reviews.llvm.org/D28012 for more context. Without the input argument, we'd have to do asm name mangling in IR transform pass, which is ugly and wrong.

Btw, win32 backend is not happy about any assembly in a naked function right now.

target triple = "x86_64-pc-windows-msvc"


define void @f() #0 {
entry:
  call void asm "nop", ""()
  unreachable
}

attributes #0 = { naked }

include/llvm/CodeGen/MachineFunction.h:452: bool llvm::MachineFunction::hasWinCFI() const: Assertion `HasWinCFI.hasValue() && "HasWinCFI not set yet!"' failed.
Comment 4 Konstantin Belochapka 2018-02-15 15:10:47 PST
It looks like the register spill instruction is nothing to do with the inline assembler statement register clobber list. The extra instruction is a spill of a function input argument:

Consider the source:
__attribute__((__naked__, __noinline__)) void foo(SIZE_T x, SIZE_T y, SIZE_T z)
{
    __asm__ __volatile__ (
      "ret" : : :
    );
}

It produces the following assembler: 
foo:                                    # @foo
# %bb.0:                                # %entry
        #APP
        retq
        #NO_APP
        movq    %rsi, -8(%rbp)          # 8-byte Spill
        movq    %rdi, -16(%rbp)         # 8-byte Spill
        movq    %rdx, -24(%rbp)         # 8-byte Spill

As can be seen the spilled registers are the function input arguments.

It happens only if the clang uses Fast registry allocator, which produces spill to the stack frame instruction for every function input argument. Other registry allocators in similar situation, mark those registers as "dead", replace them with "KILL %%reg" instructions and no machine instructions will be produced for them during the instruction selection phase.
So, the question is, what is a best way to fix the issue?
Disable spill instruction generation for "naked" function? Produce a warning message?
Comment 5 Konstantin Belochapka 2018-02-26 14:28:56 PST
potential fix on Phabricator:
https://reviews.llvm.org/D43542