Keil™, An ARM® Company

RealView Libraries and Floating Point Support Guide

Technical Support

On-Line Manuals

RealView Libraries and Floating Point Support Guide

Preface
Introduction
The C and C++ Libraries
About the C and C++ libraries
Features of the C and C++ libraries
Namespaces
Writing reentrant and thread‑safe code
Introduction to reentrancy and thread‑safety
Use of static data in the C libraries
The __user_libspace static data area
Managing locks in multithreaded applications
Using the ARM C libraries with a multithreaded app
Thread‑safety in the ARM C libraries
Thread‑safety in the ARM C++ libraries
Building an application with the C library
Using the libraries with an application
Building an application for a semihosted environme
Building an application for a non semihosting envi
Building an application without the C library
Integer and FP helper functions
Bare machine integer C
Bare machine C with floating‑point
Exploiting the C library
The standalone C library functions
Tailoring the C library to a new execution environ
How C and C++ programs use the library functions
__rt_entry
Exiting from the program
__rt_exit()
__rt_lib_init()
__rt_lib_shutdown()
Tailoring static data access
Tailoring locale and CTYPE using assembler macros
Selecting locale at link time
Selecting locale at runtime
Defining a locale block
LC_CTYPE data block
LC_COLLATE data block
LC_MONETARY data block
LC_NUMERIC data block
LC_TIME data block
_get_lconv()
localeconv()
setlocale()
_findlocale()
The lconv structure
Tailoring locale and CTYPE using C macros
Selecting locale at link time
Selecting locale at runtime
Macros and utility functions
_get_lc_ctype()
_get_lc_collate()
_get_lc_monetary()
_get_lc_numeric()
_get_lc_time()
_get_lconv()
localeconv()
setlocale()
_findlocale()
__LC_CTYPE_DEF
__LC_COLLATE_DEF
__LC_TIME_DEF
__LC_NUMERIC_DEF
__LC_MONETARY_DEF
__LC_INDEX_END
The lconv structure
Tailoring error signaling, error handling, and pro
_sys_exit()
errno
__rt_errno_addr()
__raise()
__rt_raise()
__default_signal_handler()
_ttywrch()
__rt_fp_status_addr()
Tailoring storage management
Avoiding the ARM‑supplied heap and heap‑using
Support for malloc
Tailoring the runtime memory model
The memory models
Controlling the runtime memory model
Writing your own memory model
__user_initial_stackheap()
__user_setup_stackheap()
__user_heap_extend()
__user_heap_extent()
__user_stack_cleanup_space()
__rt_heap_extend()
__rt_stack_postlongjmp()
Tailoring the input/output functions
Dependencies on low‑level functions
Target‑dependent input/output support functions
_sys_open()
_sys_close()
_sys_read()
_sys_write()
_sys_ensure()
_sys_flen()
_sys_seek()
_sys_istty()
_sys_tmpnam()
_sys_command_string()
#pragma import(_main_redirection)
Tailoring other C library functions
clock()
_clock_init()
time()
remove()
rename()
system()
getenv()
_getenv_init()
Selecting real‑time division
ISO implementation definition
ISO C library implementation definition
Standard C++ library implementation definition
C library extensions
atoll()
strtoll()
strtoull()
printf()
snprintf()
vsnprintf()
lldiv()
llabs()
wcstombs()
alloca()
strlcpy()
strlcat()
_fisatty()
__heapstats()
__heapvalid()
Library naming conventions
Placing ARM libraries
Helper libraries
Identifying library variants
The C Micro-library
Floating‑point Support

How C and C++ programs use the library functions

2.5.1. How C and C++ programs use the library functions

This section describes:

  • specific library functions that are used to initialize the execution environment and application

  • library exit functions

  • target‑dependent library functions that the application itself might call during its execution.

Initializing the execution environment and executing the application

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 Guide for more information.

  2. Zeroes ZI regions.

  3. Branches to __rt_entry.

If you do not want the library to perform these actions, you can define your own __main that branches to __rt_entry as shown in Example 2.1.

Example 2.1. __main and __rt_entry

    IMPORT __rt_entry
    EXPORT __main
    ENTRY
__main
    B     __rt_entry
    END

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() for more information.

  4. Calls exit() with the value returned by main().

C++ initialization, construction, and destruction

C++ places certain requirements on the construction and destruction of objects with static storage duration. See section 3.6 of the C++ Standard.

The ARM C++ compiler uses the .init_array area to achieve this. This is a const data array of self‑relative pointers to functions. For example, you might have the following C++ translation unit, contained in the file test.cpp:

struct T
{
    T();
    ~T();
} t;

int f()
{
    return 4;
}

int i = f();

This translates into the following pseudocode:

         AREA ||.text||, CODE, READONLY
     int f()
    {
         return 4;
    }

     static void __sti___8_test_cpp
     {
         // construct 't' and register its destruction
         __aeabi_atexit(T::T(&t), &T::~T, &__dso_handle);
         i = f();
     }
         AREA ||.init_array||, DATA, READONLY
         DCD __sti___8_test_cpp ‑ {PC}

         AREA ||.data||, DATA
     t   % 4
     i   % 4

This pseudocode is for illustration only. To see the code that is generated, compile the C++ source code with armcc ‑c ‑‑cpp ‑S.

The linker collects each .init_array from the various translation units together. It is important that the .init_array is accumulated in the same order.

The library routine __cpp_initialize__aeabi_ is called from the C library startup code, __rt_lib_init, before main. __cpp_initialize__aeabi_ walks through the .init_array calling each function in turn. On exit, __rt_lib_shutdown calls __cxa_finalize.

Usually there is at most one function for T::T(), mangled name _ZN1TC1Ev, one function for T::~T(), mangled name _ZN1TD1Ev, one __sti__ function, and four bytes of .init_array for each translation unit. The mangled name for the function f() is _Z1fv. There is no way to determine the initialization order between translation units.

Function‑local static objects with destructors are also handled using __aeabi_atexit.

Certain sections must be placed contiguously within the same region, for their base/limit symbols to be accessible. If they are not, the linker generates an error.

For example, the .init_array area is generated by the C++ compiler. This area must be placed in the same region as __cpp_initialize__aeabi_. To do this, specify the sections in a scatter‑loading description file, for example:

LOAD_ROM 0x0000000
{
    EXEC_ROM 0x0000000
    {
        init_aeabi.o(+RO)
        * (.init_array)
        ...
    }
    RAM 0x0100000
    {
        * (+RW,+ZI)
    }
}
Legacy support

In RVCT v2.1, or later, .init_array replaces C$$pi_ctorvec. However, objects with C$$pi_ctorvec are still supported. Therefore, if you have legacy objects, your scatter file contains:

LOAD_ROM 0x0000000
{
    EXEC_ROM 0x0000000
    {
        init_aeabi.o(+RO)
        init.o(+RO)              ; backwards compatibility
        * (.init_array)
        * (C$$pi_ctorvec)        ; backwards compatibility
        ...
    }
    RAM 0x0100000
    {
        * (+RW,+ZI)
    }
}

In RVCT, the C++ name mangling scheme is different from that in ADS v1.2. This might have an effect when loading a newer C++ image into an older debugger.

Exceptions system initialization

The exceptions system can be initialized either on demand (that is, when first used), or before main is entered. Initialization on demand has the advantage of not allocating heap memory unless the exceptions system is used, but has the disadvantage that it becomes impossible to throw any exception (such as std::bad_alloc) if the heap is exhausted at the time of first use.

The default is to initialize on demand. To initialize the exceptions system before main is entered, include the following function in the link:

extern "C" void __cxa_get_globals(void);
extern "C" void __ARM_exceptions_init(void)
{
    __cxa_get_globals();
}

Although you can place the call to __cxa_get_globals directly in your code, placing it in __ARM_exceptions_init ensures that it is called as early as possible. That is, before any global variables are initialized and before main is entered.

__ARM_exceptions_init is weakly referenced by the library initialization mechanism, and is called if it is present as part of __rt_lib_init.

Note

The exception system is initialized by calls to various library functions, for example, std::set_terminate(). Therefore, you might not have to initialize before the entry to main.

Emergency buffer memory for exceptions

You can choose whether or not to allocate emergency memory that is to be used for throwing a std::bad_alloc exception when the heap is exhausted.

To allocate emergency memory, you must include the symbol __ARM_exceptions_buffer_required in the link. A call is then made to __ARM_exceptions_buffer_init() as part of the exceptions system initialization. The symbol is not included by default.

The following routines manage the exceptions emergency buffer:

extern "C" void *__ARM_exceptions_buffer_init()

Called once during runtime, to allocate the emergency buffer memory. It returns a pointer to the emergency buffer memory, or NULL if no memory is allocated.

extern "C" void *__ARM_exceptions_buffer_allocate(void *buffer, size_t size)

Called when an exception is about to be thrown, but there is not enough heap memory available to allocate the exceptions object. buffer is the value previously returned by __ARM_exceptions_buffer_init(), or NULL if that routine was not called. __ARM_exceptions_buffer_allocate() returns a pointer to size bytes of memory that is aligned on an eight‑byte boundary, or NULL if the allocation is not possible.

extern "C" void *__ARM_exceptions_buffer_free(void *buffer, void *addr)

Called to free memory possibly allocated by __ARM_exceptions_buffer_allocate(). buffer is the value previously returned by __ARM_exceptions_buffer_init(), or NULL if that routine was not called. The routine determines whether the passed address has been allocated from the emergency memory buffer, and if so, frees it appropriately, then returns a non‑NULL value. If the memory at addr was not allocated by __ARM_exceptions_buffer_allocate(), the routine must return NULL.

Default definitions of these routines are present in the image, but you can supply your own versions to override the defaults supplied by the library. The default routines reserve just enough space for a single std::bad_alloc exceptions object. If you do not require an emergency buffer, it is safe to redefine all these routines to return only NULL.

Library functions called from main()

The function main() is the user‑level root of the application. It requires that the execution environment is initialized, and that input/output functions can be called. While in main() the program might perform one of the following actions that calls user‑customizable functions in the C library:

Copyright © 2007 ARM Limited. All rights reserved.ARM DUI 0378A