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,

  • I haven't tested, so I can't really help with your problem.

    But think twice about dynamic memory in an embedded application. The stl implementation may be leak-free, but not free from possible memory fragmentation.

    And unless you preallocate everything, you can't test your code and know that it will also work out in the wild. With dynamic memory, the sequence and the quantity of allocations will matter, creatly increasing the number of permutations in how your program may fail.

  • Yes, I'm aware that dynamic memory allocation while the system is running is bad. I plan on preallocate everything in the beginning. I would just like a solution that will be easily readable when I'm done.

    Thank you for your tip though.

  • * are you getting any linker warnings?
    * did you verify the layout of your flash through your map file? is everything that is involved in startup where is should be (reset vector, jump to __main, etc.)...?
    * are your clocks configured correctly?
    * maybe it is your watchdog (unlikely...)?
    * stack size?
    * interrupt that occurs immediately after startup but is not handled...?
    * ...

  • * are you getting any linker warnings?
    No.

    * did you verify the layout of your flash through your map file? is everything that is involved in startup where is should be (reset vector, jump to __main, etc.)...?
    Uh... I'm not quite sure what I should be verifying... I have the default startup code if that's what you're asking about. (Except for a change in stack size and heap size.)

    * are your clocks configured correctly?
    Oh, they're not configured at all... Let me go set some values and see if that helps. How would I know if they are "correctly" configured?

    If they're not configured at all, would it still allow some programs to run and others not to? (Or is it undefined behavior?)

    * maybe it is your watchdog (unlikely...)?
    How would I verify if it was or not?

    * stack size?
    Stack Size = 0x200, Heap Size = 0x200.

    * interrupt that occurs immediately after startup but is not handled...?
    I haven't enabled any interrupts yet in my program. Is there still a chance that it's caused by an interrupt?

  • Alright, I added the clock configuration:

    void RCC_Configuration(void)
    {
      /* RCC system reset(for debug purpose) */
      RCC_DeInit();
    
      /* Enable HSE */
      RCC_HSEConfig(RCC_HSE_ON);
    
      /* Wait till HSE is ready */
      HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
      if (HSEStartUpStatus == SUCCESS)
      {
        /* Enable Prefetch Buffer */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
        /* Flash 2 wait state */
        FLASH_SetLatency(FLASH_Latency_2);
    
        /* HCLK = SYSCLK */
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
    
        /* PCLK2 = HCLK/2 */
        RCC_PCLK2Config(RCC_HCLK_Div2);
    
        /* PCLK1 = HCLK/2 */
        RCC_PCLK1Config(RCC_HCLK_Div2);
    
        /* PLLCLK = 8MHz * 9 = 72 MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    
        /* Enable PLL */
        RCC_PLLCmd(ENABLE);
    
        /* Wait till PLL is ready */
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
        {}
    
        /* Select PLL as system clock source */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
        /* Wait till PLL is used as system clock source */
        while (RCC_GetSYSCLKSource() != 0x08)
        {}
      }
    
      /* Enable peripheral clocks ------------------------------------------*/
      /* GPIOA, GPIOB and SPI1 clock enable */
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    }
    
    

    And I still have the same problem.

  • You do realize the by pushing an item into the back of the vector that the vector code is calling new?

    There will be no simple way of using vectors and pre-allocating all space at startup without re-writeing the vector code.

  • You do realize the by pushing an item into the back of the vector that the vector code is calling new?
    Yes, I do realize that. I plan to do all my pushing at the start of my program. (Is this bad as well?) Is it any better if I used the following?

    vector<int> temp(50);
    

  • pushing at the start of your program will call new and

    vector<int> temp(50);
    

    will call new, maybe even before main is called!

  • Robert,

    I guess I'm not understanding you correctly/completely... Are you saying that calling 'new' will break things even if I defined my heap size to be 0x200?

    int * i = new int;
    
    *i = 5;
    

    works in my program...

  • No, not at all.

    Just that vectors call new even though it may not look like they do in the code.

    Also failures in new before main is even called are hard to "catch" (i.e. with an exception) because you are not even running a block of code yet.

  • 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...

  • 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?