This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ARM: Using STL vectors

Hi,

I'm writing a C++ program that will run on an STM3210E-EVAL board and I'm having some problems using STL vectors. I'm wondering what I'm doing wrong. (Or if STL vectors are even supported.)

Here's a snippet:

#include <vector>

.
.
.

void func()
{
  std::vector<int> temp;

  temp.push_back(5);
}

When I try to run the debugger on my target, I end up somewhere in assembly land and never reach the beginning of my main() function. (I am not familiar with assembly so, I'm not quite sure where I am or how I got there.)

When I run in simulator mode, everything works fine. (I end up at the beginning of my main() function like I expect.)

It appears that whenever I make any command that increases the size of my vector, I get the same result. If I never insert into my vector or resize it, then the debugger brings me to the beginning of main(), like I'd expect.

The last time I saw something like this was when my heap was 0 and I tried newing something on the heap. If anyone has any ideas, I'd be grateful.

I'm required to write my program in C++ and though I'm not required to use vectors, I really would like to. (I also have a few ideas of how to implement it differently if it turns out that vectors don't work.)

Thanks,

Parents
  • you must read the following document: DUI0349A_rvct_libraries_guide.pdf paragraph 2.5.1, available at http://www.arm.com (it counts for the RealView compiler):

    The entry point of a program is at __main in the C library where library code does the
    following:
    1. Copies non root (RO and RW) execution regions from their load addresses to their
    execution addresses. Also, if any data sections are compressed, they are
    decompressed from the load address to the execution address. See the Linker and
    Utilities Guide for more information.
    2. Zeroes ZI regions.
    3. Branches to __rt_entry.
    .
    .
    .
    .
    The library function __rt_entry() runs the program as follows:
    1. Calls __rt_stackheap_init() to set up the stack and heap.
    2. Calls __rt_lib_init() to initialize referenced library functions, initialize the
    locale and, if necessary, set up argc and argv for main().
    For C++, calls the constructors for any top-level objects by way of
    __cpp_initialize__aeabi_. See C++ initialization, construction, and destruction
    for more information.
    3. Calls main(), the user-level root of the application.
    From main(), your program might call, among other things, library functions. See
    Library functions called from main() on page 2-36 for more information.
    4. Calls exit() with the value returned by main().
    

    so, if you try to use your STL library too soon, you are, I am sorry to sad, dead. very dead...

Reply
  • you must read the following document: DUI0349A_rvct_libraries_guide.pdf paragraph 2.5.1, available at http://www.arm.com (it counts for the RealView compiler):

    The entry point of a program is at __main in the C library where library code does the
    following:
    1. Copies non root (RO and RW) execution regions from their load addresses to their
    execution addresses. Also, if any data sections are compressed, they are
    decompressed from the load address to the execution address. See the Linker and
    Utilities Guide for more information.
    2. Zeroes ZI regions.
    3. Branches to __rt_entry.
    .
    .
    .
    .
    The library function __rt_entry() runs the program as follows:
    1. Calls __rt_stackheap_init() to set up the stack and heap.
    2. Calls __rt_lib_init() to initialize referenced library functions, initialize the
    locale and, if necessary, set up argc and argv for main().
    For C++, calls the constructors for any top-level objects by way of
    __cpp_initialize__aeabi_. See C++ initialization, construction, and destruction
    for more information.
    3. Calls main(), the user-level root of the application.
    From main(), your program might call, among other things, library functions. See
    Library functions called from main() on page 2-36 for more information.
    4. Calls exit() with the value returned by main().
    

    so, if you try to use your STL library too soon, you are, I am sorry to sad, dead. very dead...

Children
  • The constructors for "top-level objects" do not get called until __cpp_initialize__aeabi which is where the vectors will get initialized. This should still be an OK time to do it since the libraries and heap are already initialized.

  • Thank you for all your help.

    Unfortunately, I don't understand what I need to do still. :( (I definitely don't have much experience with this kind of stuff.) I'm using the uVision3 IDE, and I'm not sure where/what I need to change...

  • ... if you try to use your STL library too soon, you are, I am sorry to sad, dead

    I guess I'm not sure how I am using the STL library "too soon". I simplified my program some more (but it still doesn't work.)

    extern "C"{
    #include "stm32f10x_lib.h"
    }
    #include <vector>
    
    ErrorStatus HSEStartUpStatus;
    
    void RCC_Configuration(void);
    
    int main(void)
    {
      /* System Clocks Configuration */
      RCC_Configuration();
    
      std::vector<int> temp;
    
      int size = sizeof(temp);
    
      int i = 5;
    
      temp.push_back(i);
    
      while(1){}
    }
    

    I never felt all that great about that 'extern "C"' that I need in order to get rid of some compiler errors. Could that be the root of my problems?

  • The information you posted so far clearly indicates that there is something "wrong" in the way your program is built - or to be more specific, the link with the STL library. Look at uVision's "Linker" tab - are there any unusual settings there...? You tell us that when STL is referred to in your program, it "end up somewhere in assembly land". Where? Does the address where you end up map correspond with a certain function? Is it an exception handler?

  • Did you check your RAM/ROM address ranges (in the "Target" tab)?

  • A C++ compiler has a naming rule for all external symbols that has a lot of extra bells and whistles. The aim is to get type-safe linking, i.e. if one module think a function takes a double as parameter, and another module think it takes an integer, then the two modules will generate two different function names. When linking, the actual function will have the true name based on what parameters and parameter types and return values the function really takes.

    C does not have such augmentated (mangled) names. So if you include a C header file in a C++ program, all linking will fail. Your program may ask for a $abs$_3v1v4z function, while your C runtime library main contain a _abs function.

    Encapsulating all C declarations in extern "C" (for the runtime library, this is normally already done inside the files, but many tool vendors don't take their time to do it for all of their own files) makes sure that the compiler will not mangle the external names of the symbols.

    In some situations, the compiler may also change calling convention (how parameters and return values are passed and what registers that gets destroyed) depending on if the reference is to a C symbol or a C++ symbol.

    You normally do not get a runtime error from one too much or one too little extern "C" in your code. The extern "C" part is to get a correct linking step - with mismatch your program will (almost always) not link. It is possible to get into troubles if the runtime library has two functions with the same name - one name-mangled and one using standard C naming convention. The intention would then be that a correct C++ program should pick up the mangled C++ version, while a C program should pick up the un-mangled C version. But having extern "C" in one C++ module and not in another can result in both copies of the function being included with strange results.

    In your case, you have a problem with a C++ data type - so there should not be any corresponding C code that may link in by mistake unless you have manually added a vector library written in C.

  • In your case, you have a problem with a C++ data type - so there should not be any corresponding C code that may link in by mistake unless you have manually added a vector library written in C.

    That is why I initially asked the OP if he sees a linker warning. Can such a blunt mistake go unnoticed...?

  • Look at uVision's "Linker" tab - are there any unusual settings there...?

    I haven't changed anything from the default. I've got "Use Memory Layout from Target Dialog" and "Report 'might fail' Conditions as Errors" checked. I've got nothing under Misc control. Nothing looks odd in the linker control string either.

    You tell us that when STL is referred to in your program, it "end up somewhere in assembly land". Where?

    The call stack looks like (they're actually all memory addresses, so I just scrolled up to see which functions seemed to be called):
    0: _sys_open:
    1: freopen:
    2: fopoen:
    3: __rt_lib_init:
    4: __rt_entry:
    5: _ZSt9terminatev:

  • Have you (or somebody else - check in your project) re-implemented "__rt_lib_init()"? It seems that adding a C++ object to your project fails the initialization of the C runtime library. That's not supposed to happen!
    In addition, try this: compare the map file of a functioning program (no STL) to the one having a reference to STL. What do you see?

  • Have you (or somebody else - check in your project) re-implemented "__rt_lib_init()"?

    No, no one has touched/rewritten __rt_lib_init.

    In addition, try this: compare the map file of a functioning program (no STL) to the one having a reference to STL. What do you see?

    The first thing I notice is that the non-working version is much larger (RO = 23020, RW = 17400) compared to the working version (R0 = 1516, RW = 17008).

    The second thing I notice, is that in the non-working version, it removed testvector.o from the image. (Testvector.cpp is the file that contains my main() function.)

    Both things don't look that great in my opinion...

  • Did you check your RAM/ROM address ranges (in the "Target" tab)?

    IROM1 Start is 0x8000000, Size 0x80000
    IRAM1 Start is 0x20000000, Size 0xC000

    It looks reasonable to me...

  • The second thing I notice, is that in the non-working version, it removed testvector.o from the image.

    Correction, it removed more portions of testvector.o.

  • Using STL will bring in a lot of extra code. C++ can give a smaller program growth when you add one more feature to an existing program. But it tends to produce very large "hello world" applications compared to C programs. And huge "hello world" applications compared to assembler applications.

    It does not sound good that your program does not include your main().

  • It does not sound good that your program does not include your main().

    Oh, main() is still there. It just decided to remove some other portions of my code... (Not sure which parts though...)

    Using STL will bring in a lot of extra code.

    I absolutely agree. I've got space for the time being. Hopefully, the reusability of the code is worth the code bloat.