C++ arm cross-compiled executable segfaults

I’m trying to cross-compile my C++ project from x86_64 to arm using zig. The resulting binary segfaults which can be reproduced with qemu.

I reduced the example. I use WSL2 Ubuntu 22.04 and zig 0.14.0-dev.1457+7e3180487 (a recent one).

Steps to reproduce

  1. Create file main.cpp
    #include <iostream>
    
    int main() {
        std::cout << "All your codebase" << std::endl;
        return 0;
    }
    
  2. Build
    zig build-exe main.cpp -target arm-linux-gnueabi -mcpu cortex_a72 -OReleaseSafe -lc++
    
  3. Run
    qemy-arm -L /usr/arm-linux-gnueabi main
    
  4. Get signal 11 (Segmentation fault).

Things to note

  1. I’m building for Cortex-A72 in a 32-bit mode. This CPU supports 32 and 64-bit modes. Looks like I can’t emulate this CPU in a 32-bit mode with qemu, so it’s a generic qemu-arm. Not sure whether it’s important.
  2. Building in Debug makes it work. All Release* modes segfault.
  3. Changing the std::cout line to std::puts("All your codebase"); makes it work.
  4. Adding puts before cout like so
    std::puts("All your codebase");
    std::cout << "are belong to us" << std::endl;
    
    also segfaults and doesn’t print any of those strings.
  5. Building for arm-linux-musleabi works in all build modes.

It’s my first time using qemu. Do I use it correctly? Maybe it’s a libc++ issue? If so, why does Debug work?

I am not sure if this is the problem, but try running qemu-arm -cpu cortex-a72 -L ...

Unfortunately, qemu-arm doesn’t support cortex-a72

qemu-arm: unable to find CPU model 'cortex-a72'

From cortex-a* CPUs it supports just cortex-a15, cortex-a7, cortex-a8, cortex-a9.

OTOH, qemu-aarch64 supports cortex-a72, but it fails to run the executable.

$ qemu-aarch64 -cpu cortex-a72 -L /usr/aarch64-linux-gnu main
qemu-aarch64: main: Invalid ELF image for this architecture

I suppose it expects a 64-bit executable.

The thing is, the described behavior is reproducible on an actual Cortex-A72 hardware. Without std::cout everything works, with std::cout only Debug works, musleabi works in all cases.