3

I've found an interesting behavior that I cannot explain. I wrote this very simple program that segfaults without apparent reason. Please, can someone explain what is happening here?

  • The program is run in Ubuntu (I don't know if that matters).
  • No includes, no libraries, no link to stdlib. No dependencies whatsoever.

I've tested that the segfault goes away when any of the following happens:

  • stdlib is linked (and renamed _start to main, removed extern "C", etc.)
  • GCC is used
  • Optimizations are enabled

The following is the one and only code file for the program, lets call it main.cpp.

Build it with: clang main.cpp -nostdlib.

struct A
{
    A () = default;
    A (const A &) = default;
    // A (A &) = default;

    char * a = nullptr;
    unsigned long long b;
};

struct ConvertibleToA
{
    ConvertibleToA() = default; // default constructor
    operator A() { return m_a; } // conversion to type A
    A m_a;
};

extern "C"
void _start()
{
    ConvertibleToA my_convertible{};
    A my_a = my_convertible;
}
tadman
  • 208,517
  • 23
  • 234
  • 262
DeltA
  • 564
  • 4
  • 12
  • 1
    I'd try to find the startup code source that you are deliberately not linking and figure out what the functions it is performing are & if they are needed for your program. Segment register setup comes to my mind, but I am not acquainted with startup code for a program running under Linux. – Avi Berger Nov 06 '22 at 03:42
  • 1
    Another problem you're going to have, if you continue this route, is that global and static constructors and destructors won't run. – Nate Eldredge Nov 06 '22 at 04:05
  • 1
    For the ABI, _start is not a function with normal C calling conventions. You need to use (inline) assembly. See https://stackoverflow.com/questions/58806696/gcc-optimizer-generating-error-in-nostdlib-code – n. m. could be an AI Nov 06 '22 at 04:34

1 Answers1

5

Check your stack alignment. For the SysV ABI, rsp is guaranteed to be 16-bytes aligned at program entry. However, a normal function expect rsp to be 16-bytes+8 aligned, because of the address pushed by call.

Clang uses SSE aligned instructions which will crash, GCC doesn't.

ElderBug
  • 5,926
  • 16
  • 25
  • That was it! Finally made it work. The first thing my C++-coded `_start` function does is push `rbp` (perhaps compiler doesn't know that's the entry point?). That broke 16-bytes alignment. The only reason the program worked with optimizations is that the compiler removed everything, because nothing was volatile nor had visible effects (no syscalls). Fixed it by aligning `rsp` (by and-ing it) just before the function calls. Thanks a lot. I would have had a hard time figuring that out. – DeltA Nov 06 '22 at 06:53