EmbDev.net

Forum: ARM programming with GCC/GNU tools Using C++ Exceptions on Winarm 20080331 STM32 Target


von Dan Q. (danq)


Rate this post
useful
not useful
HI All,

I have recently installed WinARM 20080331 and created a test build for 
the STM32F103ZE target device.  I am able to compile, link, and execute 
all 'C' code and some 'C++' code correctly.  The problem appears when I 
attempt to use the C++ exception handling mechanism.

I have read the 'newlib' details on providing reentrant functions, but 
it is still not 100% clear on exactly how to write these functions so 
exception handling will work the way I need.

I would like to be able to use exception handling on a "bare-metal" 
system which has no 'stdout/stdin' type of IO and will have concurrent 
tasks executing.  I need to be certain that exception handling is 
re-entrant under all conditions.

Has anyone here managed to achieve this?  If so, I'd apprecite it if you 
post how you did it.

Suggestions, tips, hints, code, etc. greatly appreciated.

Cheers!

Dan

Note: The following functions are referenced when exceptions are used:

undefined reference to `_exit'
undefined reference to `_sbrk_r'
undefined reference to `_getpid_r'
undefined reference to `_kill_r'
undefined reference to `_fstat_r'
undefined reference to `_isatty_r'
undefined reference to `_close_r'
undefined reference to `_lseek_r'
undefined reference to `_write_r'
undefined reference to `_read_r'

I have provided dummy functions to get the program to link, but I need 
to know exactly what is a minimal implementation that will satisfy the 
exception handling model.  I will never have to worry about uncaught 
exceptions, so I really need a minimal solution that is also reentrant.

von Dan Q. (danq)


Rate this post
useful
not useful
Update:

I have found a way to implement a minimal set of support functions that 
compile and execute.  Execption handling, however, will terminate and 
print the following message:

"terminate called recursively"

Then it will call 'exit()'.


Here is my test function:

void test (void)
{
  try
    {
      throw 1 ;
    }

  catch (...)
    {
    }
}

I have compiled this code on gcc for ix86 Pc target and it executes 
correctly, but on winarm, it generates the terminate message above.

As far as I know, the code is correct.  Anyone have an idea why the 
compiler thinks terminate is called recursively?

Here is the code for the library functions:

#include <stm32f10x_lib.h>
#include <sys/stat.h>

//---------------------------------------------------------------------- 
----//

char * _sbrk_r (void * reent , unsigned incr)
{
  static char     heap_mem [4096] ;

  static unsigned heap_free = 0 ;

  unsigned        heap_new  = heap_free ;

  heap_free += incr ;

  if (heap_free & 0x07)
    {
       heap_free += 8 - (heap_free & 0x07) ;
    }

  return heap_mem + heap_new ;
}

//---------------------------------------------------------------------- 
----//

int _read_r (void * reent , int file , char *ptr , int len)
{
  return 0 ;
}

//---------------------------------------------------------------------- 
----//

int _write_r (void * reent , int file , char *ptr , int len)
{
  // Exception Handling : #1 \\

  unsigned n = len ;

  while (n--)
    {
      USART_SendData (USART2 , (u16) *ptr++) ;

      while (USART_GetFlagStatus (USART2 , USART_FLAG_TXE) == RESET)
        ;
    }

  return len ;
}

//---------------------------------------------------------------------- 
----//

void _exit (int status)
{
  // Exception Handling : #2 \\

   for (;;) ;
}

//---------------------------------------------------------------------- 
----//

int _kill_r (void * reent , int pid , int sig)
{
  return -1 ;
}

//---------------------------------------------------------------------- 
----//

int _getpid_r (void * reent)
{
  return 1 ;
}

//---------------------------------------------------------------------- 
----//

int _fstat_r (void * reent , int file , struct stat *st)
{
  st->st_mode = S_IFCHR ;

  return 0 ;
}

//---------------------------------------------------------------------- 
----//

int _isatty_r (void * reent , int file)
{
  return 1 ;
}

//---------------------------------------------------------------------- 
----//

int _close_r (void * reent , int file)
{
  return -1 ;
}

//---------------------------------------------------------------------- 
----//

int _lseek_r (void * reent , int file , int ptr , int dir)
{
  return 0 ;
}

//---------------------------------------------------------------------- 
----//

int _stat_r (void *reent , const char * file , struct stat * pstat)
{
  pstat->st_mode = S_IFCHR ;

  return 0 ;
}

von Clifford S. (clifford)


Rate this post
useful
not useful
The "reentrancy" issue is primarily about providing separate copes of 
static data for each thread. In practce, for most implementations, this 
only applies to the errno global variable. Which when implemented for 
reentrancy is not truely a global variable but a macro that references 
the appropriate thread local storage.

In all implementations I have worked on, I have simply avoided using 
errno.

Note that some functions, such as strtok, ctime and asctime, are 
intrinsically non-reentant, and should be used with care ot use 
reentrant alternatives.

You could test your exception handling by forcing exceptions and 
stepping the code, using break points in the stubs to ensure that they 
do what you expect.

You should note that supporting C++ exceptions carries a significant 
memory overhead, and generally the -fno-exceptions compiler option is 
used to avoid this.  So if you want exceptions, make sure that the build 
does not use that option, but at the same time be aware of the cost.

von Dan Q. (danq)


Rate this post
useful
not useful
Thanks for the feedback Clifford.

I never use errno.  The reference to these functions is stricly indirect 
through usage of the exception handling mechanism.

But your point(s) is(are) well taken.

I did step through the functions and they are being called correctly 
(ie: arguments are ok), but the error persists.

I did some research and found out that other (non winarm, non cortex) 
gcx compilers were reporting the same problem.  It appears there is a 
problem with 'binutils' and how libstdc++ is built.  A poster indicated 
there is a fix by using a newer version of the binutils:

binutils 2.17.50 -> Generates the bug

Using ld 2.18, or even 2.17.90 creates workable libstdc++.

Perhaps Martin can look at this?

Cheers!

Dan

PS: Here is the link to the other posters thread re the same problem:

http://old.nabble.com/GCC-4.2.2-arm-linux-gnueabi:-c%2B%2B-exceptions-handling--td19686943.html

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.