TI ARM Clang Compiler 1.0.0+STS Release Notes
Table of Contents
Introduction
Version 1.0.0+STS of the TI ARM Clang Compiler Tools, also known as the tiarmclang compiler, is derived from the open source LLVM/Clang source code base. Releases of the tiarmclang compiler tools are derived from the LLVM Compiler Infrastructure source base that can be found in GitHub (github.com).
The tiarmclang compiler can be used to compile and link C/C++ and assembly source files to build static executable application files that can be loaded and run on an Arm Cortex processor (m0, m3, m4, r4, and r5). Please see the Device Support section below for further information about which compiler options to use when building an application for a particular Arm Cortex processor configuration.
Documentation
The “tiarmclang Getting Started Guide” and the “armcl to tiarmclang Migration Guide” are now available in the installation area under the “docs” sub-directory. These guides reside inside the tiarmclang user’s guide. The tiarmclang user’s guide can be viewed from the “docs” sub-directory by opening the tiarmclang_user_guide.html file with Chrome or Internet Exlorer. At the top-level of the user’s guide, there are links to both the “tiarmclang Getting Started Guide” and the “armcl to tiarmclang Migration Guide”.
Questions, comments, or suggestions related to the content of the “tiarmclang Getting Started Guide” or the “armcl to tiarmclang Migration Guide” can be sent to tiarmclang_support@list.ti.com.
Since the tiarmclang compiler is derived from the LLVM project’s Clang compiler source base, much of the generic Clang online documentation is also applicable to the tiarmclang compiler. The latest version of the generic Clang documentation can be found here:
What’s New
Branch Coverage Added to Source-Based Code Coverage Support
In addition to function coverage, instatiation coverage, line coverage, and region coverage, the tiarmclang compiler implementation of Source-Based Code Coverage also includes branch coverage that allows users to measure “True/False” execution coverage of leaf-level Boolean expressions used in conditional statements. For more details about the tiarmclang coompiler’s implementation of code coverage, see the “Source-Based Code Coverage with tiarmclang” section of the “tiarmclang Getting Started Guide.”
Updated C++ Name Demangler (tiarmdem) and Name (tiarmnm) Utilities
The previous TI-specific versions of the tiarmdem and tiarmnm utilities have been replaced by new versions that have been derived from the LLVM open source base. While the new versions of these utilities are functionally equivalent to the previous versions, the command-line interface for the new versions is different from the previous versions.
C++ Name Demangler Utility (tiarmdem)
The C++ name demangler (tiarmdem) is a debugging aid that translates C++ mangled names to their original name found in the relevant C++ source code. The tiarmdem utility reads in input, looking for mangled names. All unmangled text is copied to output unaltered. All mangled names are demangled before being copied to output.
The syntax for invoking the C++ name demangler is:
tiarmdem [options] <mangled names ...>
- options - affect how the name demangler behaves. To display a list of available options, use the help option (-h), “tiarmdem -h”.
- mangled names … - if no names are specified on the command-line, names are read interactively from the standard input stream.
The C++ name demangler writes output to stdout. You can pipe the output to a file if desired.
Differences vs. Previous Version of C++ Name Demangler
Processing Text Input
Unlike the previous version of the C++ name demangler, the new version of tiarmdem will not process a text file specified as an argument to tiarmdem. Assuming that test.s is a compiler generated assembly file, you cannot specify test.s as an argument to tiarmdem. Instead, you can pipe the text file as input to the tiarmdem utility as follows:
tiarmdem < test.s
or
cat test.s | tiarmdem
Saving Output to a File
The previous version of the C++ name demangler supported an “--output-file” option that allowed you to write the output of the tiarmdem utility to a file. The new version of tiarmdem does not support a --output option. Instead, the output can be redirected to a file like so:
cat test.s | tiarmdem > tiarmdemout
No ABI Option Needed
The previous version of the C++ name demangler required that an --abi=eabi option be specified in order to demangle C++ names that are generated by the tiarmclang compiler. The new version of tiarmdem assumes EABI and no ABI option is needed to process tiarmclang compiler generated C++ mangled names.
Name Utility (tiarmnm)
The name utility, tiarmnm, prints the list of symbol names defined and referenced in an object file, executable file, or object library. It also prints the symbol value and an indication of the symbol’s kind.
The syntax for invoking the name utility is:
tiarmnm [options] <input files>
- options - affect how the name utility behaves. To display a list of available options, use the help option (-h), “tiarmdem -h”.
- input files - an input file can be an object file, an executable file, or an object library
The output of the name utility is written to stdout. You can also elect to pipe the output to a file or as input to the C++ name demangler.
Symbol Kind Annotations
In the output from the tiarmnm utility, symbol names are annotated with an indication of their kind. The new version of the tiarmnm utility uses the following list of annotation characters to represent the different symbol kinds:
- a, A - absolute symbol
- b, B - uninitialized data (bss) object
- C - common symbol
- d, D - writable data object
- n - local symbol from a non-alloc section
- N - debug symbol or global symbol from a non-alloc section
- r, R - read-only data object
- t, T - code (text) object
- u - GNU unique symbol
- U - named object is undefined in this file
- v - undefined weak object symbol
- V - defined weak object symbol
- ? - something unrecognizable
Differences vs. Previous Version of Name Utility
Thumb Function Symbols
In the previous version of the name utility, the value of a thumb function symbol would include a 1 in the least significant bit (the thumb mode bit), but the new version of tiarmnm will not report a 1 in the least significant bit position for thumb function symbol values.
Debug Symbol Names
The previous version of the name utility would include debug symbol names in the output. However, to include debug symbols in the output of the new versoin of tiarmnm, you must specify the tiarmnm’s --debug-syms option on the command-line.
Command-Line Options
Functionally Equivalent Option Mappings
Several of the options available in the previous version of the name utility now have functionally equivalent options with different syntax in the new version of the tiarmnm utility. Below is a list of option mappings where the old option symtax is specified first and the second option syntax pertains to the new version of the tiarmnm utility:
KEY: old option syntax -> new option syntax - description
- --all -> --debug-syms - print all symbols
- --prep_fname -> --print-file-name - prepend flie name to each symbol
- --undefined -> --undefined-only - only print undefined symbols
- --sort:value -> --numeric-sort - sort symbols numerically rather than alphabetically
- --sort:reverse -> --reverse-sort - sort symbols in reverse order
- --global -> --externs-only - print only global symbols
- --sort:none -> --no-sort - don’t sort any symbols
Options No Longer Supported
The previous version of the name utility supported several command-line options that are no longer supported in the new version of the tiarmnm utility. These include:
- --format:long - produce detailed listing of symbol information
- --output - write output to a specified file
- --quiet - suppress banner and progress information
Symbol Kind Annotations
The previous version of the name utility will annotate some symbols with kind information differently than the new version of the tiarmnm utility. One of the known differences is that the previous version of the name utility uses ‘d’ to annotate debug symbols, whereas the new version of tiarmnm uses ‘N’. There may be other differences. Please consult the above list of symbol kind annotations for the tiarmnm utility for more information.
Saving Output to a File
As indicated above, the previous version of the name utility supports a command-line option to write the output to a specified file, but the new version of the tiarmnm utility does not support such a command-line option. Instead, you can elect to pipe the output of tiarmnm to a file:
tiarmnm test.o > tiarmnmout
or to the C++ name demangler utility, for example:
tiarmnm test.o | tiarmdem > tiarmdemout
An Example
Consider the following source file (test.cpp):
int g_my_num;
namespace NS { int ns_my_num = 2; }
int f() { return g_my_num + NS::ns_my_num; }
int main() { return f(); }
If the above test.cpp is compiled:
tiarmclang -mcpu=cortex-m4 -c test.cpp
We can then use the tiarmnm utility to write out the symbol names in test.o:
%> tiarmnm test.o
00000000 T _Z1fv
00000000 D _ZN2NS9ns_my_numE
00000000 B g_my_num
00000000 T main
and we could pass the output of tiarmnm to tiarmdem to demangle the mangled names that are present in the tiarmnm output:
%> tiarmnm test.o | tiarmdem
00000000 T f()
00000000 D NS::ns_my_num
00000000 B g_my_num
00000000 T main
Automatic Selection of Printf Support Implementation
The compiler tools will at link-time choose the smallest version of the underlying printf support function, __TI_printfi, used to support processing of format strings and format specifiers for the C RTS family of printf-like functions (printf, sprintf, fprintf, etc.).
There are three different versions of the __TI_printfi function available in the C RTS library, each providing a different level of support for processing format strings as the need dictates in a given application. The linker will choose one of these functions based on what format specifiers are used in the format strings. The three functions can then be characterized in terms of the format specifiers that they support:
- minimal - the smallest version of __TI_printfi will be chosen if there are no calls to any variation of printf in the program where the format strings contain any of the following format specifiers: l, u, p, x, field width with precision, h, i, a, A, g, G, e, E, f, F, and L.
- nofloat - the nofloat version of __TI_printfi is larger than the minimal version, but still quite a bit smaller than the full version of __TI_printfi. The nofloat version will be chosen If there are no calls to any variation of printf in the program where the format strings contain any of the floating-point related format specifiers: a, A, g, G, e, E, f, F, and L.
- full - the full version of __TI_printfi will be chosen if any calls to any variation of printf in the program where the format strings contain any of the floating-point format specifier: a, A, g, G, e, E, f, F, or L. Additionally, In cases where the linker is unable to determine that a smaller version of __TI_printfi can be safely used, the full version of __TI_printfi will be included in the link by default.
If your application uses printf-type functions in the C RTS library, but it does not use format specifiers that require more involved code to support, then you may realize a code size savings if the linker is able to determine that it is safe to use a smaller version of __TI_printfi.
Automatic Selection of memcpy/memset Implementation
The compiler tools will at link-time choose versions of the C RTS memcpy and memset functions according to the optimization goals of a given linked application as determined by the Tag_ABI_optimization_goals build attribute that is embedded in the object files that are input to the linker.
There are two different versions of each of the memcpy and memset functions available in the C RTS library. One version is designed for efficient performance in terms of run-time, and a second version is much smaller than the first, but relatively slow compared to the first especially if large blocks of data are to be handled by the memcpy or memset functions.
If any of the object files input to the linker reflect that code size is to be preferred over performance in an application (i.e. when the -Oz or -Os option is used in the compilation of any input object file or library), then the small version of memcpy and/or memset will be included in the link. In all other cases, the larger and faster version of memcpy and/or memset will be included in the link.
Stack Smashing Detection
The tiarmclang 1.0.0+STS compiler tools provide stack protection functionality in the form of the -fstack-protector and -fstack-protector-all options:
- -fstack-protector - instructs the compiler to emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. This includes functions that call alloca, and functions with buffers larger than or equal to 8 bytes. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits. Only variables that are actually allocated on the stack are considered, optimized away variables or variables allocated in registers don’t count.
- -fstack-protector-all - instructs the compiler to behave as if -fstack-protector were specified, except that the compiler will emit stack buffer overflow checking code for all functions instead of limiting protection as -fstack-protector does.
How to enable Stack Smashing Detection
To enable stack smashing detection in your application, you need to provide definitions of:
- __stack_chk_fail() - the function that is called from an instrumented function when a check against the stack guard value, __stack_chk_guard fails. A simple definition of this function might look like this:
void __stack_chk_fail(void) {
printf("__stack_chk_guard has been corrupted\n");
exit(0);
}
- __stack_chk_guard - a globally visible symbol whose value can be copied into a location at the boundary of a function’s allocated stack on entry into the function, and loaded just prior to function exit to perform a check to see that the local copy of the __stack_chk_guard value was not corrupted. A simple definition of this symbol might look like this:
unsigned long __stack_chk_guard = 0xbadeebad;
You can then compile a file containing both of these definitions to produce an object file that can be linked into an application that is instrumented for stack smashing detection.
The -fstack-protector or -fstack-protector-all option can then be specified on the compiler command-line to instrument your application code with the stack smashing detection mechanisms.
Here is a simple example to summarize and demonstrate …
The first source file presents definitions of __stack_chk_fail() and __stack_chk_guard (stack_check.c):
#include <stdlib.h> #include <stdio.h> void __stack_chk_fail(void); unsigned long __stack_chk_guard = 0xbadeebad; void __stack_chk_fail(void) { printf("ERROR: __stack_chk_guard has been corrupted\n"); exit(0); }
The second source file presents a use case where a function (foo) writes past the end of a local buffer (stack_smash.c):
#include <string.h> void foo(void); int main() { foo(); return 0; } void foo(void) { char buffer[3]; strcpy(buffer, "Oi! I am smashing your stack"); }
The stack_check.c source file can then be compiled to generate stack_check.o:
%> tiarmclang -mcpu=cortex-m4 -c stack_check.c
and the stack_smash.c source file is compiled and linked with stack smashing detection enabled via the use of the -fstack-protector-all option:
%> tiarmclang -mcpu=cortex-m4 -fstack-protector-all stack_smash.c stack_check.o -o hello.out -Xlinker -llnk.cmd
When loaded and run, the error message is emitted and the program exits when the stack check fails before returning from foo():
%> load470 -q stack_smash.out
ERROR: __stack_chk_guard has been corrupted
Install Directory Organization
The organization of the runtime libraries and C/C++ include files in the directory where the tiarmclang compiler tools are installed has been updated compared to previous release versions (prior to 1.0.0-alpha.3) of the toolchain.
What follows is an overview of the install directory organization:
<install directory>
README.html
<toolchain manifest documents>
/bin
<toolchain executables: tiarmasm, tiarmclang, tiarmlnk>
<archive utilities: tiarmar, tiarmlibinfo>
<file/symbol manipulation/information utilities:
tiarmdem, tiarmdis, tiarmhex, tiarmnm, tiarmobjcopy, tiarmobjdump,
tiarmofd, tiarmreadelf, tiarmsize, tiarmstrip, tiarmxref>
<code coverage utilities: tiarmcov, tiarmprofdata>
/include
/c
<C standard runtime include files>
/c++/v1
<C++ standard runtime include files>
/lib
<C runtime libraries>
<C++ runtime libraries>
Support for noinit and persistent Attributes
The tiarmclang compiler supports the noinit and persistent attributes.
The noinit Attribute
Normally, global or local static variables are zero-initialized if not otherwise explicitly initialized. Some applications, however, make use of non-volatile memory that would make not initializing certain variables useful.
When the noinit attribute is applied to a global or static variable, the variable will keep its current value when a processor or platform is reset or loses power. It is not modified by default initialization on resumption of the program. Such a variable must not have an explicit initialization.
Consider a few examples:
// Error, use __attribute__((persistent)) instead
__attribute__((noinit)) int x = 5;
// Error, not global/static
void foo() { __attribute__((noinit)) int x; }
// Ok
__attribute__((noinit)) int x;
void foo() { __attribute__((noinit)) static int x; }
The noinit attribute may be used in conjunction with the location attribute to map variables to a specific memory location, like a memory-mapped register, but without generating unwanted writes.
The persistent Attribute
Normally, global or local static variables have their values reset when a program is restarted, either through loss-of-power or through a reset. Some applications, however, make use of non-volatile memory that would make not re-initializing certain variables useful.
When the persistent attribute is applied to a global or static variable, the variable is initialized to a known value on program start, but will keep its current value when a platform resets or loses power.
Consider a few examples:
// Error, use __attribute__((noinit)) instead
__attribute__((persistent)) int x;
// Error, not global/static
void foo() { __attribute__((persistent)) int x; }
// Ok
__attribute__((persistent)) int x = 5;
void foo() { __attribute__((persistent)) static int x = 5; }
If you are using non-volatile RAM, you can define a persistent variable with an initial value of zero loaded into RAM. The program can increment that variable over time as a counter, and that count will not disappear if the device loses power and restarts, because the memory is non-volatile and the boot routines do not initialize it back to zero.
For example:
__attribute__((persistent, location(0xC200))) int x = 0;
void main() {
run_init();
while (1) {
run_actions(x);
wait_cycles(1000000);
x++;
}
}
Merged Symbol Metadata Information is Kept in Linked Output
The tiarmclang compiler tools utilize an encoding of symbol metadata to pass extra information, which cannot be encoded in a basic ELF symbol table entry, from the compiler to the linker. This includes information about the symbol that needs to be incorporated into the link such as:
- designating that a symbol must be retained in the link even if it isn’t referenced elsewhere in an application,
- designating a specific location where the storage for the symbol’s definition is to be allocated in target memory, and
- designating that a symbol’s value should not be re-initialized on system reset
In previous versions of the tiarmclang compiler tools, symbol metadata information encoded in the .symtab_meta sections of object files that are specified as input to a link were consumed and applied during the link, but not kept in the linked output file. Beginning with release version 1.0.0-alpha.2 of the tiarmclang compiler tools, the linker will merge symbol metadata information from incoming symbol metadata (.symtab_meta) sections and include the merged .symtab_meta section in the linked output file.
Updated ARM EABI Helper Functions in C Runtime Library
In previous releases of the tiarmclang compiler tools (prior to 1.0.0-alpha.2), the ARM EABI helper functions used by the C compiler to perform floating-point arithmetic were implemented in C. The implementation of these helper functions has since been replaced with smaller, more efficient implementations that are written in assembler language.
Applications that contain references to these helper functions are likely to realize a code size savings when built with the latest tiarmclang compiler release compared to builds with earlier versions of the tiarmclang compiler.
All Runtime Libraries are Built with Optimization (-Oz)
Some early analysis of tiarmclang code size gaps vs. armcl revealed that some of the runtime libraries provided with the tiarmclang compiler tools package were not being compiled with optimization turned on.
The applicable libraries include:
- libcxx - libc++.a
- libcxxabi - libc++abi.a
- compiler-rt - libclang_rt.builtins.a
Beginning with drop #2 of the tiarmclang 1.0.0-alpha.1 compiler tools, compiling the source files for these libraries with the tiarmclang -Oz option may reduce the code size (vs. previous tiarmclang releases) of an application that is linked with one or more of these libraries.
Legacy TI-Syntax ARM Assembler Can Be Invoked from tiarmclang
Beginning with release version 1.0.0-alpha.1, the tiarmclang compiler can be instructed to process input files with its TI-syntax ARM assembler. The assembly language source files, written using legacy TI-syntax ARM assembly code, can be indicated to the tiarmclang compiler using the "-x language" option, where language is "ti-asm". This option applies to all subsequent input files, so be sure to reset the input file type if there are non-TI-syntax ARM assembly source files on the command line following the TI-syntax ARM assembly source files.
For example, in the following command:
%> tiarmclang c-source1.c -x ti-asm ti-asm-source1.asm -x none c-source2.c
the "-x ti-asm" option indicates that the ti-asm-source1.asm file is to be processed by the TI-syntax ARM assembler, and the subsequent "-x none" option resets the input file type to a default state so that the tiarmclang compiler knows to process the c-source2.c input file as a C file.
While many important options that need to be passed to the TI-syntax ARM assembler, such as silicon version and FPU version, can be inferred from the compiler’s normal command line options, other options that you might need may be missing or need to be overridden. To support this, two new options, "-Wti-a" and "-Xti-assembler" are supported. These behave similarly to tiarmclang’s other "-W" and "-X" options. Please see -Xlinker flag and -Wl flag for examples of the "-X" and "-W" options that apply to the linker.
Some helpful options available for use are:
- --define/--undefine - pre-define (or undefine) an identifier to a value, similar to tiarmclang’s -D and -U compiler options.
- --include_file - effectively process an ".include file" directive before reading the assembly source file itself.
- --include_path - similar to the tiarmclang’s -I compiler option, adding a specified directory to the search path used to find the subject of a ".include file" directive.
- --no_warnings - suppresses all warnings that are emitted by the TI-syntax ARM assembler.
Remember that when passing one of the above options to the TI-syntax ARM assembler from the tiarmclang command line, to precede the option with the tiarmclang’s "-Xti-assembler" or "-Wti-a" option. In this example,
%> tiarmclang ... -x ti-asm tia.asm -Xti-assembler \-\-define=MY_PREDEF_SYM=10 ...
the "--define=MY_PREDEF_SYM=10" option is passed to the TI-syntax ARM assembler when processing the TI-syntax ARM assembly source file, "tia.asm".
armcl ->tiarmclang Migration Aid Diagnostics
When migrating an ARM C/C++ application project from using the armcl compiler to using the tiarmlang compiler you may have instances of TI-specific pragmas, pre-defined macro symbols, or intrinsics that are supported by the armcl compiler, but not the tiarmclang compiler. To make your C/C++ source code more portable, we advise that you find these instances of TI-specific pragmas, pre-defined macro symbols, and instrinsics and convert them into their ACLE (ARM C Language Extensions) counterparts.
Please refer to the ARM C Language Extensions specification for details about ACLE.
To help with this process, the tiarmclang compiler will emit a diagnostic when it encounters the use of a legacy TI pre-defined macro symbol, pragma, or intrinsic and provide information about how that use can be safely transformed into a functionally equivalent ACLE alternative, if one exists. In cases where there is no functionally equivalent ACLE alternative to replace an instance of a legacy TI pre-defined macro symbol, pragma, or intrinsic, the tiarmclang compiler will emit a diagnostic to inform you about the presence of that legacy TI mechanism.
Let’s consider a couple of examples …
The legacy TI pragma FUNC_CANNOT_INLINE has a valid ACLE alternative, so if the tiarmclang compiler encounters the following line of code:
#pragma FUNC_CANNOT_INLINE
The tiarmclang compiler will emit the following diagnostic:
warning: pragma FUNC_CANNOT_INLINE is a legacy TI pragma and not supported in
clang compilers. use '__attribute__((noinline))' instead
However, the legacy TI pre-defined macro symbol __TI_ARM_V4__ does not have a viable ACLE alternative, so the following code:
#if defined(__TI_ARM_V4__)
...
#endif
will cause the tiarmclang compiler to emit the following diagnostic:
warning: '__TI_ARM_V4__' is a legacy TI macro and not supported in clang compilers
The migration aid diagnostics for use of legacy TI macro symbols, pragmas, and intrinsics are enabled by default in the 1.0.0-alpha.1 version of the tiarmclang compiler. If you wish to suppress any of the three migration aid diagnostic types, you can specify:
- -Wno-ti-pragmas : to suppress migration aid diagnostics for legacy TI pragmas
- -Wno-ti-macros : to suppress migration aid diagnostics for legacy TI pre-defined macro symbols
- -Wno-ti-intrinsics : to suppress migration aid diagnostics for legacy TI intrinsics
Support for Unsigned 32- and Signed 64-Bit POSIX time_t
Beginning with release 1.0.0-alpha.1, the tiarmclang compiler defines time_t by default as a POSIX-compatible signed 64-bit value using the POSIX epoch of January 1, 1970. This is different from the TI proprietary ARM compiler (armcl), which defines time_t as an unsigned 32-bit value using a legacy TI-defined epoch of January 1, 1900. You do not need to take any special steps or define any macros to use the new implementation, just be sure to include time.h and use the standard C functions as you normally would. The standard C time functions will automatically map to 64-bit implementations.
AEABI portability mode
If you must link object files built with the tiarmclang compiler tools with object files built by other compiler vendors, you must use AEABI portability mode. The ARM standard (Section 5.20 of the "C Library ABI for the ARM® Architecture") specifies that you must define the _AEABI_PORTABILITY_LEVEL preprocessor macro as follows before #includ’ing any standard header files, particularly <time.h>:
#define _AEABI_PORTABILITY_LEVEL 1
This definition enables full portability. For time.h, defining and setting this macro will force the compiler to use an unsigned 32-bit representation for time_t with POSIX epoch. All calls to the standard C time functions will refer to their 32-bit variants. In addition, the compiler will also ensure that the _AEABI_PORTABLE macro is defined, as required by the standard.
- Note: If your program attempts to use or manipulate any time_t with value larger than INT_MAX (which corresponds to a date in 2038), the time functions may not work properly.
You may also interlink third party object code with the tiarmclang linker and runtime library, including calling the standard C time functions, requiring no special steps. You are responsible for ensuring that AEABI portability is used consistently throughout your application.
Other ways to leverage the unsigned 32-bit representation of time_t
You may also activate the unsigned 32-bit representation of time_t without activating AEABI portability mode. Instead of setting the _AEABI_PORTABILITY_LEVEL macro, simply set the macro __TI_TIME_USES_64=0.
As long as variables of type time_t aren’t used globally, you may freely link object files built using __TI_TIME_USES_64=0 with those that do not since the actual time functions in the RTS are not changed.
- Note: The epoch used for time_t functions is an implementation-defined property. For this reason, you should be cautious when attempting to link using time functions defined within an RTS library built using the TI proprietary ARM compiler since that compiler does not define values for time_t using the POSIX epoch. You are responsible for ensuring that time_t is used consistently through their application.
Concerns when migrating from ARMCL to TI ARM CLANG
- Typesize assumptions
- If you have code that assumes an unsigned 32-bit type for time_t, you should either remove this assumption or build your code in a way that forces time_t to be unsigned 32-bit. This can be done by setting -D__TI_TIME_USES_64=0 on the command line for your build.
- TI-epoch assumptions
- If you have code that decodes the value of time_t outside of using the standard C time functions and assumes a TI-defined epoch, you should know to adjust your code to represent the timestamp based on the POSIX epoch.
- The standard C time functions rely on an implementation of HOSTtime() to extract the system time for both unsigned 32-bit and signed 64-bit representations. If you substitute your own HOSTtime() routine to extract the system time, this routine should be adjusted to return time based on a POSIX epoch rather than the TI epoch.
- For both issues, you may reference the TI provided HOSTtime() routine in the runtime support library for an example of how to adjust for the POSIX epoch.
Support for atexit() in Static Executable Use Cases (tiarmclang 1.0.0-alpha.1)
In previous versions of the tiarmclang compiler, use of the C runtime function atexit() was not supported. Beginning with the tiarmclang 1.0.0-alpha.1 compiler tools’ C runtime library, proper support for using the atexit() function to register functions to be executed upon exit is now present.
The implemented support for atexit() adheres to the Itanium C++ ABI - Construction and Destruction APIs for static executable use cases. It does not support dynamic linking and dynamic shared object use cases.
General Discussion of Implemented Functionality
First, some basic characteristics:
- The atexit() function takes a single function pointer argument.
- Functions that are registered via atexit() should not have any arguments.
- The atexit() function can be called explicitly within the source code, but it will also be called implicitly to register a destructor for a global data object that requires a destructor.
- At each call to atexit() the provided function pointer will be recorded on a last-in-first-out stack of function pointers.
- If registration is successful, atexit() will return a value of 0.
- When the relevant program exits, the registered atexit() functions will be called in the reverse order in which they were registered.
If atexit() is called to register a function during exit, perhaps even in the process of calling the already registered functions, then the newly registered function will be placed on the top of the function pointer stack. This situation may occur if atexit() is called as part of a destructor function.
In the TI proprietary ARM compiler tools (armcl), the maximum number of functions that could be registered via atexit() is 32. In the tiarmclang compiler tools, there is not a set limit for how many functions can be registered.
The atexit() implementation provided in the tiarmclang compiler tools does incur some overhead in terms of data space allocation to maintain the stack. Upon the first instance where a function is registered via atexit(), the C runtime library will allocate a data structure of 136 bytes to support up to 8 registered functions. If a program requires more than 8 registered functions, then an additional 136 bytes of memory will be allocated for every 8 functions registered via atexit().
Consider an example that demonstrates how to register a function to be called when the program exits:
#include <stdio.h>
#include <stdlib.h>
void foo() {
printf("foo\n");
}
int main() {
atexit(foo);
return 0;
}
When run, the above program will write “foo” to stdout.
Standard atexit implementations require two function definitions: atexit() itself, and __cxa_atexit(). The atexit() function can be called explicitly as shown in the above example, but __cxa_atexit() can not. By default, the tiarmclang compiler will register global destructors via the __cxa_atexit() function. However, the tiarmclang compiler will use atexit() instead if the tiarmclang -fno-use-cxa-atexit option is specified on the command line.
Testing and Validation
The Plumhall C++ and Perennial C++ test suites have recently been added to the collection of commercial and in-house-developed test suites that are used to test the correctness and robustness of the tiarmclang compiler. New testing has also been added to the suite of TI proprietary custom tests (a.k.a. PHIL) to verify functionality and robustness of newly added features.
Our normal regression testing of the tiarmclang compiler tools includes:
- An automated process to keep our compiler source base up to date with changes that have been made to the upstream LLVM/Clang repository,
- LLVM and Clang lit tests from the upstream LLVM/Clang repository as well as lit tests that we have added to validate updates to the compiler source code, and
- We continue to expand the test plan to test a wider variety of option combinations:
- Each combination of compiler options will be tested with the following test suites:
- ACE C SuperTest
- ACE C++ SuperTest
- Plum Hall C
- Plum Hall C++
- Perennial C90
- Perennial C++
- PHIL - TI proprietary test suite for custom, targeted feature and regression testing
- Each combination of compiler options will be tested with the following test suites:
Known Issues
tiarmclang -save-temps Option Loses Source Correspondence Information (CODEGEN-7470)
When a C/C++ source file is being compiled with the -mskip-fault-mitigation option (available only on Cortex-m0 and Cortex-m0plus), and the file contains a function with a non-zero stack frame that uses all of the available argument registers, the tiarmclang compiler will emit a warning diagnostic indicating that skip fault mitigation is not supported on that function in that file at a specified location. The current implementation of the skip fault mitigation feature in the tiarmclang compiler requires the use of a free argument register or a zero-length stack frame in order to apply mitigation measures to a given function.
However, when the compilation of the C/C++ source file uses the -save-temps option in combination with the -mskip-fault-mitigation option, the emitted diagnostic will not contain the source file and line number information indicating the location of the function that caused the diagnostic to be emitted. This can be problematic when building a multi-file project making it difficult to identify the source of the diagnostic.
If this situation should arise, it is possible to find the source of the diagnostic by temporarily removing the -save-temps option from the build options, then rebuilding the project to emit a diagnostic that does contain the source file and line number information so that the source of the diagnostic can be identified and worked around. The -save-temps option can then be reinstated in the project build options.
tiarmclang Optimizes Away Empty Loops (CODEGEN-6288)
There have been reports from TI internal users of the tiarmclang compiler that the tiarmclang optimizer is more aggressive about removing empty loops than the armcl compiler. This includes functions that contain nothing but an infinite do-nothing loop as well as a simple empty loop where the only effect is to modify the loop counter on each iteration. This issue is recorded and is being tracked as JIRA item CODEGEN-6288.
A solution to this issue in the compiler has not been forthcoming as there is debate about whether or not the compiler should be allowed to remove empty loops that it determines to have no effect. In fact, the C++ language standard advises that the compiler is within expected behavior in this regard.
Section 1.10 of the C++ language standard reads:
The implementation may assume that any thread will eventually do one of
the following:
- terminate
- make a call to a library I/O function
- access or modify a volatile object, or
- perform a synchronization operation or an atomic operation
[Note: This is intended to allow compiler transformations such as removal
of empty loops, even when termination cannot be proven. - end note ]
and taking advantage of these guarantees is part of providing a
high-quality optimizer for C/C++ programs.
While this issue remains to be resolved in the tiarmclang compiler, there are viable workarounds …
For a function that contains only an infinite, do-nothing loop:
void parking_func() {
while(1) {
;
}
}
You can insert an asm(" "); statement into the function as follows:
void parking_func() {
asm(" ");
while(1) {
;
}
}
to ensure that the compiler will not inline or completely remove the function.
Likewise, for the following empty for loop:
#include <stdint.h>
int main() {
uint32_t i = 0x1000;
for (i = 0x1000; i > 0; i--);
return 0;
}
You can add a volatile type qualifier to the loop counter like so:
#include <stdint.h>
int main() {
volatile uint32_t i = 0x1000;
for (i = 0x1000; i > 0; i--);
return 0;
}
to ensure that the compiler will not remove the loop.
The crux of the workaround for this issue is to get the compiler to believe that there is a side effect associated with the loop.
Fixed Issues
Defect ID | Summary | Resolution |
---|---|---|
CODEGEN-4562 | tiarmclang libc needs to provide a proper definition of atexit() | updated libc implementation of atexit() to support static executable use cases |
CODEGEN-6350 | source/producer of DWARF compile unit debug information is not always properly identified | updated DW_AT_producer attribute’s value to include “TI ARM Clang Linker” when DWARF compile unit debug information entry is being generated by the tiarmclang linker |
CODEGEN-6595 | linker generates internal error when trying to generate a trampoline on behalf of a linker generated CMSE veneer section | gnerating a trampoline for a linker generated CMSE veneer section is not allowed; updated diagnostic to inform user to place CMSE veneer section within range of secure code that is being referenced by the CMSE veneer |
CODEGEN-6870 | running tiarmclang executable on some RHEL7 environments cannot find GLIBCXX shared library | build UNIX versions of tiarmclang with statically linked libstdc++ library |
CODEGEN-6894 | orphaned symbol metadata being generated | symbol meta-information will not be included in an object file unless the symbol it is associated with is also included in the object file’s symbol table |
CODEGEN-7035 | LDRD/STRD optimization in the compiler is causing a runtime failure | disabled specific optimization pending further investigation |
CODEGEN-7089 | a NULL pointer argument passed into the __udivmoddi4() runtime support function will trigger a bus error | guard writes to memory pointed to by argument to avoid potential writes via a NULL pointer |
CODEGEN-7123 | the off_t type required for POSIX support is not consistently defined in runtime support header files | the off_t type is now consistently defined to be long in both file.h and sys/types.h |
CODEGEN-7216 | tiarmclang linker erroneously includes TMS470_C_DIR in its library search path by default | updated tiarmclang to avoid adding TMS470_C_DIR to library search path used by linker |
CODEGEN-7217 | similar to CODEGEN-7089 described above, this defect involves two additional cases where a NULL pointer argument passed into the __udivmoddi4() runtime support function will trigger a bus error | guard writes to memory pointed to by argument to avoid potential writes via a NULL pointer |
CODEGEN-7358 | tiarmclang linker fails to find a compatible libc library to link with object file compiled with -mcpu=cortex-r5 | repaired object file compatibility check for Tag_DIV_use build attribute |
CODEGEN-7446 | tiarmclang compiler generates unexpected token in .sym_meta_info directive | repaired code in compiler that writes value operand of .sym_meta_info directive |
CODEGEN-7586 | tiarmobjcopy does not handle printf-related symbol metadata information properly | tiarmobjcopy code has been updated to repair an error when reading and writing symbol metadata information entries from/to the symbol metadata section |
CODEGEN-7690 | tiarmstrip may corrupt the content of the symbol metadata section | repaired code in tiarmstrip to properly account for changes to the symbol table that affect the content of the symbol metadata section |
Host Support / Dependencies
The following host-specific versions of the 1.0.0+STS tiarmclang compiler are available:
- Linux: Ubuntu, RHEL 7
- Windows: 7, 8, 10
- Mac: OSX
Device Support
The tiarmclang compiler supports development of applications that are to be loaded and run on one of the following Arm Cortex processor variants:
ARM Processor Variant | Options |
---|---|
Cortex-M0 | “-mcpu=cortex-m0” |
Cortex-M0+ | “-mcpu=cortex-m0plus” |
Cortex-M3 | “-mcpu=cortex-m3” |
Cortex-M4 without FPV4SPD16 | “-mcpu=cortex-m4 -mfloat-abi=soft” |
Cortex-M4 with FPv4SPD16 | “-mcpu=cortex-m0 -mfloat-abi=hard -mfpu=fpv4-sp-d16” |
Cortex-R4 (Thumb) without VFPv3D16 | “-mcpu=cortex-r4 -mthumb -mfloat-abi=soft” |
Cortex-R4 (Thumb) with VFPv3D16 | “-mcpu=cortex-r4 -mthumb -mfloat-abi=hard -mfpu=vfpv3-d16” |
Cortex-R4 without VFPv3D16 | “-mcpu=cortex-r4 -mfloat-abi=soft” |
Cortex-R4 with VFPv3D16 | “-mcpu=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16” |
Cortex-R5 (Thumb) without VFPv3D16 | “-mcpu=cortex-r5 -mthumb -mfloat-abi=soft” |
Cortex-R5 (Thumb) with VFPv3D16 | “-mcpu=cortex-r5 -mthumb -mfloat-abi=hard -mfpu=vfpv3-d16” |
Cortex-R5 without VFPv3D16 | “-mcpu=cortex-r5 -mfloat-abi=soft” |
Cortex-R5 with VFPv3D16 | “-mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16” |
The tiarmclang compiler will default to the Cortex-M4 (“-mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16”) processor if you do not explicitly specify an -mcpu or -march option on the compiler command-line.
Technical Support
The tiarmclang 1.0.0+STS compiler is a short term support release. Until a subsequent long-term support (LTS) release is made, support for the tiarmclang compiler is currently being handled directly by the development team. To submit a question or report an issue with the 1.0.0+STS version of the tiarmclang compiler, please send e-mail to tiarmclang_support@list.ti.com.
Someone from the tiarmclang compiler development team will respond to acknowledge the receipt of the question or issue report and, if warranted, create a TI Internal Jira entry to track the issue.