Unusual segfault when using C++ Std Lib on embedded Linux

Here's some sample test code I'm trying to run on an embedded Linux system:

#include <iostream>

int main(int argc, char *argv[])
{
    char c = 'A';
    int i = 7;

    std::cout << "Hello World from C++" << std::endl;
    std::cout << "c=" << c << std::endl;
    std::cout << "i=" << i << std::endl;
}

The embedded system is a Microblaze, which is a 32-bit RISC softcore processor running on a Xilinx FPGA. Please don't be put off by that, as a lot of your standard Linux knowledge will still apply. The processor is configured as LSB with an MMU, and the Linux build I'm using (PetaLinux, supplied by Xilinx) is expecting the same. I'm using the supplied GNU compiler; Microblaze appears to be officially supported in GCC.

The problem I'm having is that when the stdlib needs to interact with the integer, it segfaults. Here's the output:

Hello World from C++
c=A
Segmentation fault

Note that the char is handled fine. The C equivalent of this code also works fine:

#include <stdio.h>

int main(int argc, char *argv[])
{
    char c = 'A';
    int i = 7;

    printf("Hello World from Cn");
    printf("c=%cn", c);
    printf("i=%in", i);

    return 0;
}

...

Hello World from C
c=A
i=7

This leads me to suspect an issue with the shared library libstdc++.so.6.0.20 . That library is supplied by Xilinx though, so it should be correct. The file output of that library is:

libstdc++.so.6.0.20: ELF 32-bit LSB shared object, Xilinx MicroBlaze 32-bit RISC, version 1 (SYSV), dynamically linked, not stripped

The file output of my binary is:

cpptest: ELF 32-bit LSB executable, Xilinx MicroBlaze 32-bit RISC, version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.6.32, stripped

I've also tried statically linking my binary using the -static flag, but the result was the same.

Here are the most relevant compiler and linker settings I'm using, but I've tried changing these with no avail.

CC=microblazeel-xilinx-linux-gnu-gcc
CXX=microblazeel-xilinx-linux-gnu-g++

CFLAGS= -O2 -fmessage-length=0 -fno-common -fno-builtin -Wall -feliminate-unused-debug-types
CPPFLAGS?=
CXXFLAGS= -O2 -fmessage-length=0 -fno-common -fno-builtin -Wall -feliminate-unused-debug-types
LDFLAGS=-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed

To compile:
@$(CCACHE) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(CFLAGS) $< -o "$@"

To link:
@$(CXX) $(RELOBJECTS) $(LDFLAGS) $(EXT_LIBS) -o $(RELBINARY)

Note that microblazeel refers to the little endian version of the microblaze compiler.

I would very much like to debug this or at least look at a coredump, but no coredump seems to be produced when the segfault happens, and there's no gdb executable in the Microblaze Linux build. Maybe I'm missing something?

Thanks for taking your time to read this. Any thoughts?


From what I could see after a bit of research, vivado is the HW development IDE [because they offer a trial period--so it's the HW devel, which they always want to charge for].

If you're using the standard SDK board from Xilinx, everything should be preconfigured. Otherwise, a HW designer produces a HW design that has Microblaze in it.

From that, you may have to use petalinux to generate a new boot, kernel, etc. image that is compatible.

You may need to rebuild libstdc++ from source, but I'd do that as a last resort. For example, don't bother with it, until you've got gdb working and have test results.


Here are some petalinux PDF files:
http://www.xilinx.com/support/documentation/sw_manuals/petalinux2013_10/ug977-petalinux-getting-started.pdf
http://www.xilinx.com/support/documentation/sw_manuals/petalinux2013_10/ug981-petalinux-application-development-debug.pdf


The development guide shows how to invoke gdb (eg):
On the target system:
gdbserver host:1534 /bin/myapp
On the development system:
petalinux-utils --gdb myapp followed by target remote 192.168.0.10:1534


I've done some editing on your Makefile with annotations. I've commented out some of the non-essential options. Note that I'm using the += operator to build up CFLAGS/CXXFLAGS gradually

The basic idea here is to do a build with minimum deviations from "standard". Add only proven essential options. Build and test. Add back the options one-by-one [rebuild and test each time] until you find the option that is causing the problem.

I do, however, have a strong suspicion about -fno-common being a source of problems. Also, to a lesser extent, I'm a bit suspicious of -Wl,--as-needed

Should these options work? Sure, but xilinx/microblaze ain't no x86 ...

I've added two command line make variables:
DEBUG -- generate for debug with gdb
VERBOSE -- show everything about the build process

For example, try make <whatever> DEBUG=1 VERBOSE=1

CC = microblazeel-xilinx-linux-gnu-gcc
CXX = microblazeel-xilinx-linux-gnu-g++

CPPFLAGS ?=

CMFLAGS += -Wall -Werror
CMFLAGS += -fmessage-length=0

# compile for gdb session
# NOTES:
# (1) -gdwarf-2 may or may not be the the right option for microblaze
# (2) based on doc for -feliminate-unused-debug* petalinux/microblaze may want
#     stabs format
ifdef DEBUG
  CMFLAGS += -gdwarf-2
  CMFLAGS += -O0

# compile for normal build
#else
  CMFLAGS += -O2
  CMFLAGS += -feliminate-unused-debug-types
endif

# NOTE: I used to use "@" on commands, but now I leave it off -- debug or not
# sure it's "ugly" but you can get used to it pretty quickly--YMMV
ifndef VERBOSE
  Q :=
else
  ###Q := @
  Q :=
endif

# let compiler/linker tell you _everything_:
# (1) configure options when tool was built
# (2) library search paths
# (3) linker scripts being used
ifdef VERBOSE
  CMFLAGS += -v
  LDFLAGS += -Wl,--verbose=2
endif

CMFLAGS += -fno-builtin

# NOTE: I'd _really_ leave this off as it may confuse c++ std as "<<" calls
# _M_insert (which is in the library, which is almost certainly _not_ using
# -fno-common)
###CMFLAGS += -fno-common

# NOTE: I'm also suspicious of this a little bit because the c++ lib may have
# some "weak" symbols that the c library doesn't
###LDFLAGS += -Wl,--as-needed

# NOTE: this seems harmless enough, but you can comment it out to see if it
# helps
LDFLAGS += -Wl,--hash-style=gnu

# NOTE: an optimization only
ifndef DEBUG
  LDFLAGS += -Wl,-O1
endif

CFLAGS += $(CMFLAGS)
CXXFLAGS += $(CMFLAGS)

# NOTES:
# (1) leave this off for now -- doesn't save _that_ much and adds complexity
#     to the build
# (2) IMO, I _never_ use it and I erase/uninstall it on any system I
#     administrate (or just ensure the build doesn't use it by removing it
#     from $PATH)--YMMV
###XCCACHE = $(CCACHE)

# to compile
$(Q)$(XCCACHE) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(CFLAGS) $< -o "$@"

# to link
$(Q)$(CXX) $(RELOBJECTS) $(LDFLAGS) $(EXT_LIBS) -o $(RELBINARY)
链接地址: http://www.djcxy.com/p/86968.html

上一篇: 连字符应该逃脱吗?

下一篇: 在嵌入式Linux上使用C ++ Std Lib时出现异常段错误