Skip to content

clang >= 18 .cfi frame check rejects assembly generated by clang (Mach-O) #148170

Open
@sternenseemann

Description

@sternenseemann

Background

When upgrading clang in Nixpkgs, older versions of GHC started hitting the cfi frame check for darwin introduced in clang 18. This happens while compiling the file rts/StgCRun.c which has a bunch of inline assembly which notably contains labels, but no explicit .cfi_startproc/endproc.

While this only affected GHC versions before 9.6, the StgCRun.c wasn't changed in any meaningful way to alleviate the issue (the reproducer uses the one from 9.12.2). I eventually figured out that GHC used to (before 9.6) roundtrip C compilation via assembly, i.e. it would run clang -S followed by clang -c using the generated assembly file as an input. This was changed for 9.6 (mainly to benefit wasm compilation).

The (potential) bug

I concluded that, for Mach-O, clang -c will, without complaints, translate one and the same C file to object code directly that it would reject (due to the cfi frame check) if it is translated to assembly first (by the same version of clang). This is shown by the reproducer below.

I'm not sure if this should be considered a bug or not. StgCRun.c is definitely not bog standard C due to its use of inline Assembly containing labels. It may be that clang can figure that the translation is safe in the context of the C file, but not in the case of the assembly file presented to it without context.

Unless other software is also affected by this, it is not worth fixing this for the sake of some GHC versions that should go out of use soon (hopefully). I'm mostly reporting this in case LLVM considers this inconsistency a bug that should be fixed.

Reproducer

The issue can relatively easily be reproduced using the following commands on a Darwin machine. I didn't test clang 18 and 20, but they should also exhibit the same issue. I'm happy to test any specific clang version, e.g. main, if required, just let me know.

$ curl https://downloads.haskell.org/ghc/9.12.2/ghc-9.12.2-src.tar.gz | tar -zxv
$ cd ghc-*/rts/
$ clang --version
clang version 19.1.7
Target: arm64-apple-darwin
Thread model: posix
InstalledDir: /nix/store/702wr5c2h7z8r6nhl7sjrw5d0af9xbdv-clang-19.1.7/bin
$ ./configure
(I think this should succeed if Developer Tools or similar installed, let me know if it gives you any trouble.)
$ clang -S -o StgCRun.asm StgCRun.c -I include -I .
$ clang -c -o StgCRun.o StgCRun.asm -I include -I .
StgCRun.asm:46:1: error: non-private labels cannot appear between .cfi_startproc / .cfi_endproc pairs
StgReturn:
^
StgCRun.asm:7:2: error: previous .cfi_startproc was here
 .cfi_startproc
 ^
$ rm -f StgCRun.asm StgCRun.o
$ clang -c -o StgCRun.o StgCRun.c -I include -I .
$ ls *.o
StgCRun.o

See also

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions