Code Generation Tools FAQ

From Texas Instruments Wiki
Jump to: navigation, search

Contents

Q: What are the best compiler build options?

Q: What can I do about the linker taking so long?

See Linker Runs Too Long .

Q: I want to ensure priority ordering of sections across chips with different internal memory sizes with 1 command file

You may have a situation as follows:

Device 1 has 64kb of fast internal memory and Device 2 has 128kb. You then have 4 key code sections:

  • .text:_a : 20kb
  • .text:_b : 30kb
  • .text:_c : 20kb
  • .text:_d : 10kb

Assume the fast internal memory is named IRAM and the slower external memory is named SDRAM.

Assume that .text:_a is most important to be placed in IRAM (eg most MIPS intensive), followed by .text:_b etc. You want to have 1 .cmd file which works across the 2 devices. On device 1, you want .text:_a and .text:_b to be placed in IRAM but can accept it if c and d are allocated in SDRAM. On device 2 you want all .text subsections to be allocated in IRAM.

This can be achieved by doing:

GROUP: {
.text:_a
.text:_b
.text:_c
.text:_d
} >> IRAM | SDRAM

This tells the linker:

  • group the sections as per order I listed them in. The GROUP directive is the only directive in the linker to force ordering. Simply listing sections does not guarantee that the linker will allocate them in the order you desire. In fact the linker typically allocates the largest sections first in an effort to minimize potential memory map holes.
  • Automatically Split the output sections between the non-contiguous Memory ranges IRAM and SDRAM. The >> directive indicates that the contents of the GROUP can be split between IRAM and SDRAM. For example, when the linker encounters .text:_c a 20kb section it realizes it cannot fit this section in IRAM on Device 1. Hence it skips it, and tries to find a smaller section that can such as .text:_d. On Device 2, there's adequate room for subsections a thru d hence they all get placed sequentially as per GROUP rules. On Device 1, .text_c will be placed in SDRAM by the linker since it can fit there.

Note that if you simply do:

.text:_a >> IRAM | SDRAM
.text:_b >> IRAM | SDRAM
.text:_c >> IRAM | SDRAM
.text:_d >> IRAM | SDRAM

then this handles the section splitting but does not guarantee the ordering. Hence some of the most MIPS-intensive functions may get allocated to SDRAM.

And, if you simply do:

GROUP: {
.text:_a
.text:_b
.text:_c
.text:_d
} > IRAM

then you can't have 1 command file for the 2 devices. You would need a different one for Device 1 since all of these sections wont fit in the 64k IRAM.

Q: Why do I need –w link flag?

The linker has a flag –w which is defined to "Warn if an unspecified output section is created". Hence, if you do e.g. in assembly

.sect ".mysect"

or in C

#pragma CODE_SECTION(myFunc, ".mysect")

then such a section is not one of the standard sections (e.g. .text, .bss etc) that the linker expects.

If you do not explicitly place such a section in your .cmd file, the linker will arbitrarily place it for you. This can cause nasty runtime problems. For example, cases have been observed where such user-defined sections have been placed in FLASH sections (but naturally they were not actually FLASH'd). As a result, the code breaks.

The solution is simple : always use the –w linker flag. It will show a warning when such sections have not been placed.

An alternative solution is to always use subsections e.g.

#pragma CODE_SECTION(myFunc, ".text:mysect")

however, this is not practical if you are consuming libraries written by other parties, which may have explicit user-defined sections.

Best is to always link with –w.

All project templates supplied with CCS use the linker -w flag.

Q: Please explain the trampolines section of the linker map file

Trampolines are automatically generated by the linker when a CALL instruction cannot reach it destination. More details are in the Assembly Language Tools User's Guide for your target. When they are generated, you may see entries in the linker map file similar to:

FAR CALL TRAMPOLINES
callee    addr      tramp     addr      call addr  call info
−−−−−−−−  −−−−−−−−  −−−−−−−−  −−−−−−−−  −−−−−−−−−  −−−−−−−−−−−−−−−−
_func4    80000260  .T$0001   00008480  00006fe8   demo.obj (.text)
_func5    80000200  .T$0002   000084a0  00006ff0   demo.obj (.text)

The column contents are as follows:

  • callee – function called
  • addr – address of callee
  • tramp – automatically generated name for the trampoline
  • addr – where the trampoline resides in memory
  • call addr – list of addresses from which a call using the trampoline originates
  • call info – the object file and input section that contain the originating call. If the object file is from a library, the name of the library is shown as well.

Q: When using inline assembly instructions on the TI C compiler, why does the code break at run-time?

The TI C compiler supports an asm() statement which allows developers to insert assembly code into C functions. The contents of an asm() statement are simply passed through to the assembly output. If the asm() code modifies registers required by the surrounding C code, data corruption will occur and the program will fail at run-time. Extreme caution is urged. Always check the assembly output to make sure your asm() statements are correct and maintain the integrity of the program.

Q: What standards does the TI compiler adhere to?

See TI Compilers and Industry Standards .

Q: We wish to comply with an Industry Standard XX to justify safety or industry specific requirements for the tools we use. Is there a validation report or certificate available for the compiler? (XX= IEC61508; TÜV; MISRA-C, etc)

See Compiler Qualification Kit .

Q: Share C headers between C and assembly code

The .cdecls directive allows programmers in mixed assembly and C/C++ environments to share C headers containing declarations and prototypes between the C and assembly code.

Single Line:

.cdecls [options,] "filename"[, "filename2"[,...]]

Multiple Lines:

.cdecls [options]
%{
/*---------------------------------------------------------------------------------*/
/* C/C++ code - Typically a list of #includes and a few defines */
/*---------------------------------------------------------------------------------*/

%}

More information can be found in the Assembly Language Tools User's Guide for your device family.

Note: The .cdecls directive is not supported in C6000 linear assembly or C5500 mnemonic assembly.

Q: How to resolve error “remark #562-D: "typeid" is reserved for future use as a keyword , error #20: identifier "typeid" is undefined”

The built-in function typeid is a C++ language feature related to RTTI (runtime type identification). RTTI is supported in TI compilers, but it is not enabled by default. Enable RTTI by building with the option -rtti.

Q: When compiling my project I get the following error message, “undefined symbol: _strasgi. Error: symbol referencing errors- ‘user.out’ not built”. How can I fix it?

This entry only applies to the C6000 compiler.

You must be linking an object module built with compiler version 6.0.X (or higher) with a runtime support (RTS) library from compiler version 5.1.X (or lower).

The function __strasgi is called by the compiler to perform structure assignment, and other similar memory copy operations. This is termed an “internal” RTS function because it is not called directly by the user. Floating point operations on fixed point devices are similarly performed with internal RTS functions. Starting with compiler release 6.0.1, the internal RTS function __strasg is replaced with __strasgi. Note the “i” at the end of the new function name; it stands for interruptible. The new __strasgi can be interrupted. The older __strasg cannot be interrupted.

It is most likely is brought into the build environment from some object library obtained elsewhere. Which means it was built elsewhere as well and when the build of vendor.obj occurred, a compiler version 6.0.X (or higher) was used. Such a build may place a call to __strasgi in the code. If that is the case, then that code has to be linked with a RTS library that has a definition of the __strasgi function. Libraries from compiler version 5.1.X (or older) do not have this function defined.

Two solutions exist. One: Upgrade from compiler version 5.1.X to 6.0.X (or later). Two: Change to using an older vendor library that was built with compiler version 5.1.X (or earlier).

Q: How to reduce code size with –ms option?

This discussion applies only to the C6000 compiler.

When using the -on option, you are telling the compiler to optimize your code. The higher the value of n, the more effort the compiler invests in optimizing your code. However, you might still need to tell the compiler what your optimization priorities are. By default, when -o2 or -o3 is specified, the compiler optimizes primarily for performance. (Under lower optimization levels, the priorities are compilation time and debugging ease.) You can adjust the priorities between performance and code size by using the code size flag -msn. The -ms0, -ms1, -ms2, and -ms3 options increasingly favor code size over performance.

It is recommended that a code size flag not be used with the most performance-critical code. Using -ms0 or -ms1 is recommended for all but the most performance-critical code. Using -ms2 or -ms3 is recommended for seldom-executed code. Either -ms2 or -ms3 should be used also if you need the minimum code size. In all cases, it is generally recommended that the code size flags be combined with -o2 or -o3. At lower levels of optimization, you may be trading more performance than necessary.

Note:

  • If you use -ms with no code size level number specified, the option level defaults to -ms0.

Q: I’m using an older compiler to link in a library built with a newer compiler and I get an error message from the linker similar to: “>> error: illegal relocation type 050002 found in section .debug_something, file filename”. What’s wrong, and what can I do about it?

The object code in the library (or file) includes Dwarf debug information that the older linker cannot read. Dwarf is a new and improved way to encode debug information. Debug information is read by a debugger like Code Composer Studio (CCS). The format of the debug information changed between the compilers released with CCS 2.X and CCS 3.X. If you are seeing this message, you are doing the final build with a CCS 2.X compiler while using a library (or other object module) built with a CCS 3.X compiler.

The rest of this FAQ presumes a library is the source of the problem. If you have this problem with a single object file instead, then the problem is no different conceptually. But the details of how you address the problem change. The rest of this FAQ presumes you are dealing with a library. The adjustments when handling a file instead are straightforward.

Presuming you cannot update to the newer compiler, you have two options. One is to rebuild the library to not use Dwarf debug information. The other option is to strip the debug information out of the library.

Rebuild the Library:

These directions presume you are using a CCS 3.X compiler to rebuild the library. Build the library the same as before, but use an additional switch to change the format of the debug information. The compiler switch --symdebug:none turns off all debug information. The switch --symdebug:coff enables the old style Stabs (sometimes called COFF) debug information that the old compiler can read. Note using --symdebug:coff interferes with optimization.

Strip the Library:

This process removes all the debug information from the library. These directions use executables from the C5500 compiler toolset. If you are using a different toolset, replace the “55” with the abbreviation for your toolset. For instance, C6000 users should replace ar55 with ar6x.

The name of the example library is: mylib.lib.

  1. Copy the library to an empty directory
  2. Extract all the library members: ar55 -x mylib.lib
  3. Strip the debug information by applying strip55 to each .obj file in the directory: strip55 *.obj
  4. Delete the old library: del mylib.lib
  5. Rebuild the library: ar55 -r mylib.lib *.obj

Note you have to perform these steps each time you receive an update of the library.

Q:Can I split my .bss section into two different memories while building a library so that I can keep the non-time critical code on external memory?

You can use linker tricks to segregate critical code from libraries into separate sections so you can link them to internal memory instead of external memory. In terms of swapping code back and forth that is certainly doable.

If you are intending to do overlays then the linker supports the UNION directive which allows you to have two different pieces of code execute from same address (at different times) while being loaded to distinct addresses. You can also use the table feature of the linker to generate copy tables that can then be used by a C program to access the start and sizes of the different sections to swap them in and out of internal memory. The latest run time support library even has a copy table routine that supports this.

There is a secondary bootloading application note on C6000 devices that has example code and discussion of many of these topics.


Q: what is the sequence order of memory loads / stores when the compiler schedules them in parallel in the same execute packet?

This discussion is specific to C6000 devices.

This information is especially important when it is needed to have a specific sequence in the cpu writes / reads to external memory when interfaced to real HW, e.g. an FPGA or an external controller.

The load and store order rule is as follows:

 -- For LD||ST, the LD goes before the ST.
 -- For LD||LD or ST||ST, the "T1" goes before the "T2."

T1/T2 is determined by which register file provides the data. (These are sometimes called "DA1" and "DA2".) The register file that provides the address is ignored, as is the position within the execute packet. This ordering applies to all C6000 family members.

Example 1:
    [ A1]   LDB     .D2T2   *B4++(2),B5       ; Load Byte 2
 || [ A1]   LDB     .D1T1   *+A9[A8],A9       ; Load Byte 3
The LDB into A9 goes before the LDB into B5.
Example 2:
    [ A1]   STB     .D1T2   B5,*A5++(2)       ; Store Byte 2
 || [ A1]   STB     .D2T1   A9,*+B2[B1]       ; Store Byte 3
The STB from A9 goes before the STB from B5.


This is in SPRU609 and SPRU610 (the cache documentation for C621x/C671x and C64x).

see http://focus.ti.com/general/docs/techdocsabstract.tsp?abstractName=spru610c

In SPRU610C, it's under "memory system policies," under "memory access ordering."

This information should also be added in the future release of SPRU732 and SPRU871.

Generally it is always best to use the keyword volatile for pointers related to memory mapped hw; volatile instructs the compiler to not reorder the sequence of instructions during compilation, when having some C code accessing memory locations (performing loads / stores)

Q: Does the TI compiler support variadic macros?

The TI compiler does not support variadic macros; it conforms to the ISO/ANSI C standard (C89), and variadic macros came with C99.

Still, depending on which target compiler and version, this should be supported through the tools' GCC language extensions.

These are enabled with the --gcc compile switch

Q: I am porting my C project to C++ and the compiler does not recognize the _nassert keyword

This would be expected, since _nassert in C++ is part of the standard namespace. The correct syntax is std::_nassert()

Eventually you could have your own wrapper functions or macros to have it defined in a compatible way between the two languages

Q: How can I get the linker to place a piece of code or data so that it comes before all the rest?

First, some terminology and concepts need to be established. You may be familiar with these ideas, but perhaps not by these names. Consider this simple linker command file fragment:

SECTIONS
{
   output_section_1 : {
      /* first list of input sections */
   } > MEMORY_RANGE_1

   output_section_2 : {
      /* second list of input sections */
   } > MEMORY_RANGE_1

   ...
}

The key relationships are:

  • Input sections are combined together into an output section
  • Output sections are allocated to memory ranges

Note that both output sections are going into the same memory range. Which one is allocated into that memory range first? The answer is at the end of this FAQ.

There are two kinds of ordering the linker does which must be understood:

  1. When input sections are combined into output sections, what order do they go in?
  2. When output sections are allocated to memory ranges, what order do they go in?

It is very important to understand that these orderings occur completely independent of each other.


For 1) if you use input section wild-card syntax like this

output_section_1 : { *(.text) } > MEMORY_RANGE_1

then the linker is free to order the input sections however it wants. It tries very hard to avoid holes between input sections, and to fill them when they occur. The same thing is true if you use this even shorter form:

.text > MEMORY_RANGE_1   /* Collects all .text input sections */

If you give the linker a specific order like this:

output_section_1 : {
   file1.obj(.text)
   file2.obj(.text)
   -lrts.lib<lib_file.obj>(.text)
  ...
} > MEMORY_RANGE_1

then the linker will use that exact ordering.


You can combine those techniques together, like:

output_section_1 : {
   -lbios.lib<boot.obj>(.text)
   *(.text)
} > MEMORY_RANGE_1

In this example, the .text section from the boot.obj member of the bios.lib library is placed in the output section first, followed by all the remaining .text input sections.


As to 2), when multiple output sections are allocated to the same memory range, as in the first example above, the linker is free to order them however it wants. It tries very hard to avoid holes between output sections, and to fill them whenever they occur. Larger sections tend to be placed first, but that is not guaranteed.

If you need output sections to go into a memory range in a specific order, use the GROUP directive. The first example above, rewritten to use GROUP, looks like this:

GROUP {
   output_section_1 : {
      /* first list of input sections */
   }

   output_section_2 : {
      /* second list of input sections */
   }
} > MEMORY_RANGE_1


Now the linker guarantees that output_section_1 is allocated before output_section_2.

Q: How can I generate a list of the compiler predefined macros?

For the full list of pre-defined macros, compile the null C program ("void main(void) { }") with the -ppm option. This will produce the file <filename>.pp which contains the macro definitions of all the pre-defined macros. Or use the -ppm option on any source file. The resulting .pp file will contain the pre-defined and user defined macros.

Q: Is there a compiler predefined macro that I can use to detect that it is a TI compiler?

You can check for the macro __TI_COMPILER_VERSION__ to be defined. Please also refer to the FAQ on how to generate a list of other compiler predefined macros.

Note, there are more details on __TI_COMPILER_VERSION__ here.

Q: What does linker error "Tag_Memory_Model attribute value of "1" that is different than one previously seen ("2"); combining incompatible files" mean?

This means that the build is combining files with different memory models (small, large, huge) which the linker does not allow. Check the build options for all source files and libraries to make sure they are all built for the same memory model.