The C28x Code Generation Tools now support an
ELF-based ABI, which allows support for new features such as shared object files.
This new ELF ABI is referred to as "EABI".
This document describes changes that should be made when migrating existing C28x COFF
ABI libraries and applications to use the C28x EABI. This document *is not* an overview of EABI or new features
available only in EABI. For information about C28x EABI, see the following documents:
* *C28x Embedded Application Binary Interface Application Report* ([SPRAC71](https://www.ti.com/lit/pdf/sprac71))
* *TMS320C28x Optimizing C/C++ Compiler User's Guide* ([SPRU514](https://www.ti.com/lit/pdf/spru514) version R or later)
* *TMS320C28x x Assembly Language Tools User's Guide* ([SPRU513](https://www.ti.com/lit/pdf/spru513) version R or later)
This document is intended for object library vendors and developers who
have been supporting COFF and wish to migrate their code base.
The focus of this document is on migrating COFF
ABI applications to EABI or producing code that works equally well
with both COFF ABI and EABI.
Most Common EABI Migration Issues
======================================
While this document details changes between COFF ABI and EABI
and the changes needed to support both, most users only need to
perform a few changes to their code to move from COFF to ELF. The most
common issues you are likely to encounter are:
* __The `double` type is 64 bits.__
The size of double changes from 32 bits to 64 bits when you migrate from COFF to EABI.
* __There is no leading underscore on symbols.__
COFF adds a leading underscore to symbol names, but EABI does not. Assembly file references to symbols need special handling.
Migration Strategies
====================
There are various migration strategies to choose from.
Do You Need to Migrate?
-----------------------
Before converting a COFF project to ELF, consider whether
you need any EABI features. A working COFF program need not be
converted to ELF immediately unless ELF-only features are needed. COFF
will continue to be supported for some time. We encourage our customers
to migrate applications to EABI for systems that are actively being developed.
Will COFF Support be Eliminated?
--------------------------------
ELF and EABI will eventually completely displace COFF and the COFF ABI;
however, COFF will continue to be supported for some time. COFF ABI
support will be phased out slowly.
- Most new compiler features will only be supported in EABI
mode going forward. Some features like dynamic linking *cannot* be added to
COFF due to limitations of the COFF format.
- TI continuously improves the C2000 device family by introducing
advanced C2000 ISAs. For new ISAs, the compiler defaults to EABI mode. You must
use the `--abi=coffabi` option to build COFF ABI objects for
new ISAs.
- At some point in the future, new C2000 family ISAs will *only* be
supported in EABI mode.
- Later, at a time chosen based on feedback from our customers, we
will completely stop supporting COFF ABI in new compiler releases.
At this point users will be required to use older versions of the
compiler to compile for COFF ABI.
Supporting Both COFF and ELF
----------------------------
By using conditional compilation judiciously, it is easy to make code
work for both COFF and ELF. However, you will need to compile two sets of object files,
because it is not possible to link COFF and ELF object files together.
### Conditional Compilation Using a Predefined Symbol
Both the compiler and assembler pre-define the symbol `__TI_EABI__`
to indicate that source is being compiled under EABI. This option is
defined when the `--abi=eabi` option is specified. If C code or
assembly code cannot be written in a way that works for both COFF ABI
and EABI, use this symbol to conditionally compile the appropriate
version of the code.
```
#if defined(__TI_EABI__)
static char abi[] = "EABI";
#else
static char abi[] = "COFF ABI";
#endif
printf("ABI used: %s\n", abi);
```
### Recommendations for Library Vendors
Library vendors are encouraged to distribute both COFF and ELF
versions of each library. For portably written C code, the effort to
support both COFF and ELF is minor. For assembly code, the effort is typically a
matter of renaming global symbols using conditional compilation.
### Creating an Index Library that Includes both COFF and EABI Libraries
Use the libinfo2000 tool to create an index library (like the RTS index
`libc.a`) that can be linked against instead of directly linking to a COFF
or EABI-specific library. The linker then uses the index library to
choose the appropriate version of the library to use.
### Dealing With COFF-Only Object Libraries
To convert an object file from COFF ABI to EABI, it is strongly
recommended that you have access to at least the assembly code so that
it can be appropriately modified and reassembled. If you do not have
source code, for example because you only have an object library from
a vendor, the best choices are to either leave the application as a COFF
ABI application or to request that the vendor release an EABI version.
There is no tool for converting a COFF object file to an ELF
object file; reverse-engineering the assembly code by using a
disassembler is error-prone and could violate licensing agreements for
some packages.
C and C++ Code Changes
=================================================
Programs written entirely in C or C++ have the easiest migration
path. Portably written C and C++ code may not need any changes
at all, so such code can be shared unmodified between COFF and ELF
projects.
Maximally portable C and C++:
- Does not rely on exact sizes of types beyond what the C standard guarantees
- Does not assume a particular bit-field layout
- Does not assume a particular enum type size
- Does not use intrinsics
- Does not use asm() statements
If your code avoids non-portable assumptions, the code may be
reused without modification or inspection. Code that does make any of these
assumptions needs to be examined to determine if the code will
behave differently for EABI and COFF ABI. This section describes areas where
EABI and COFF ABI differ with regard to C and C++ language features.
The `double` Type is 64 Bits in EABI
--------------------------
Floating-point types have the following widths in COFF and EABI.
| Type | COFF | EABI |
|------------- |--------- |--------- |
| float | 32 bits | 32 bits |
| double | 32 bits | 64 bits |
| long double | 64 bits | 64 bits |
Notice that the `double` floating-point type is 64
bits wide in the EABI model, but 32 bits wide in the COFF ABI
model. To make your code portable between COFF ABI and EABI, you should declare
32-bit floating-point variables as `float`, not as `double`.
This change to type sizes when migrating is true for both CLA and C28x.
For CLA we provide basic
arithmetic helper functions such as add, multiply, etc., but do not
provide functions defined in math.h, since these do not exist for 32-bit
floating types.
Another approach to using floating-point types portably is to use the `float32_t`
and `float64_t` types. These are conditionally defined in `hw_types.h`
based on whether `__TI_EABI__` is defined.
### Use of 64-bit Floating Point Operations
If you want all floating-point operations to be performed using 32-bit operations,
set the following compiler option to 32 to emit errors if any 64-bit
floating point operations are used:
```
--float_operations_allowed=32
```
This option defines the floating-point precision accepted by the compiler. If you do not
specify this option, the compiler defaults to --float_operations_allowed=all, which allows
both 32-bit and 64-bit operations.
### Use of Floating Point Unit (FPU) Intrinsics
If you want to use 64-bit hardware floating point support (FPU64), you must use EABI mode.
The 32-bit hardware floating point support (FPU32) is portable between COFF and EABI modes.
### Floating Point Constants
With EABI, floating point constants without any suffix are interpreted
as doubles. You can use the "f" suffix to declare 32-bit floating point constants.
The following example first converts the constants to 64-bit doubles,
then adds the constants, and finally converts back to 32-bit float.
```
float flt = 1.0 + 2.0;`
```
The following example does not use any 64-bit operations:
```
float flt = 1.0f + 2.0f;`
```
### Type Change for Floating-Point Intrinsics
The definitions of the following intrinsics have been changed to
use `float` instead of `double` so that the types will always be 32 bits wide.
This change affects both COFF ABI and EABI. Though the change affects
declarations, it should have no effect on the behavior of these intrinsics.
```
int __f32toi16r(float);
uint __f32toui16r(float);
float __fracf32(float);
float __eisqrtf32(float);
float __einvf32(float);
float __fmin(float, float);
float __fmax(float, float);
float __fsat(float, float, float);
void __f32_min_idx(float &, float, float &, float);
void __f32_max_idx(float &, float, float &, float);
void __swapff(float &, float &);
void __swapf(float &, float &);
float __divf32(float, float);
float __mpy2pif32(float);
float __div2pif32(float);
float __sinpuf32(float);
float __cospuf32(float);
float __atanpuf32(float);
float __atan2puf32(float);
float __quadf32(float &, float, float);
```
### C Declarations of Assembly Functions Involving double
C-callable assembly functions written for the COFF ABI that accept or
return a 32-bit double value will have been declared in the C code with
a prototype that uses the `double` or `float` type. Change the prototypes for such
functions to use only the `float` type.
Bit-Field Layout
----------------
The *declared type* of a bit-field is the type that appears in the source code.
The *container type* of a bit-field is the type of addressable storage unit used to hold the field.
The container type determines how bit-fields are packed and aligned.
The size and layout of the container of a bit-field may differ in COFF ABI and EABI.
In summary:
- For EABI, the container type is the same as the declared type.
- For COFF ABI, the smallest possible container is used.
For code that must be portable between COFF ABI and EABI, bit-fields
should not be used. If they must be used, the bit-field may need to
be declared with conditionally compiled code.
### C and C++ Standard Requirements for Bit-Fields
To hold the value of a bit-field, the C and C++ standards allow an
implementation to allocate any addressable storage unit large enough to
hold the specified number of bits; the type need not be the same as the declared type.
(This strategy is used for COFF, but not for EABI.)
C89, C99, and C++ have different options for possible declared types:
- C89: `int`, `unsigned int`, `signed int`
- C99: `int`, `unsigned int`, `signed int`, `_Bool`, or "some other implementation-defined type"
- C++: any integral or enumeration type, including `bool`
There is no `long long` type in strict C++, but because C99 has it, C++
compilers commonly support it as an extension. The C99 standard does not
require an implementation to support `long` or `long long` declared types
for bit-fields, but because C++ allows it, it is not uncommon for C
compilers to support them as well.
The TI compiler supports using any integral type as the declared type of a bit field in
both C and C++, but only in EABI. For COFF ABI, bit-fields must have
a declared type of `int`, `unsigned int`, or `signed int`.
### EABI Layout Scheme
For EABI, the declared type is also used as the container type. This has
two major consequences:
- The containing structure will be at least as large as the declared type.
- If there is not enough unused space in the current container, the
bit-field will be aligned to the next container.
If a 1-bit field has a declared type of `int`, the EABI layout allocates an
entire `int` container for the bit-field. Other fields can share the
container, but each field is guaranteed to be stored in a container
exactly the size of the bit-field.
Further reading on the bit-field layout can be found in the Itanium C++ ABI
specification (https://itanium-cxx-abi.github.io/cxx-abi/abi.html).
### COFF ABI Layout Scheme
The COFF ABI scheme uses a different strategy. It starts by using the
smallest possible container. It grows the current container if
growing it allows the bit-field to be allocated at the current
position.
### Examples Comparing Layout with COFF and EABI
`P` stands for padding
__Example 1:__
`struct S { int a:1; };`
For both COFF and EABI, the container is one 16-bit `int` with the following contents:
`aPPPPPPPPPPPPPPP`
__Example 2:__
`struct S { long a:1; };`
The container size and layout differ for COFF and EABI.
COFF: `aPPPPPPPPPPPPPPP` (one 16-bit container. which is the smallest available container size)
EABI: `aPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP` (one 32-bit container, as specified in the declared type)
__Example 3:__
`struct S { int a:1; int b:1};`
For both COFF and EABI, the container is one 16-bit `int` with the following contents:
`abPPPPPPPPPPPPPP`
__Example 4:__
`struct S { int a:15; int b:2; };`
For both COFF and EABI, the container is two 16-bit ints with the following contents:
`aaaaaaaaaaaaaaaPbbPPPPPPPPPPPPPP`
Although the emphasis for bit fields is on packing efficiency, if multiple fields do not fit in the current field,
a new container is created and packing begins at the start of that container.
__Example 5:__
`struct S { int a:15; long b:2 };`
For both COFF and EABI, the container is one 32-bit container and one 16-bit container inside the 32-bit container.
`aaaaaaaaaaaaaaabbPPPPPPPPPPPPPPP`
### Compatibility Impact of EABI
As shown above, EABI can produce a bit-field layout that is not quite
the same as it would be with
COFF ABI. Programs that rely on bit-fields for precise data
layout--such as for reading a binary file or setting bits in a status
register--should be examined for compatibility. Such test cases may need
to use conditional compilation to change the declared types of bit-field
definitions. However, many existing test cases will be unchanged.
Incompatibilities fall into two categories:
* **Structure size:** Structures can be larger with EABI if they contain bit-fields with
mostly unused bits. If a structure needs to use the smaller size that
would have been used with COFF ABI, the declared type needs to be
changed to a type of the desired size, such as char.
* **Bit-field position:** Bit-fields can usually be stored at a different position
only if there is enough space left in the current container to fit the
next bit-field, but not a properly aligned object of
the declared type. The narrower the declared type of a bit-field, the
more likely that there will be an incompatibility. Declaring all bit-fields
with an int-sized type (as is typical of code written for C89),
minimizes the incompatibility of bit-field positions.
### Access Type
For efficiency, the compiler may access bit-fields using a type that
does not match either the *declared type* or the *container type*. The
declared type and container type are used only to determine bit
field packing and alignment.
The type used by the compiler to actually load
the bit-field is the *access type*, which can be a narrower type computed
from the size and offset of the bit-field. In the
following EABI example, the container type is 32 bits, but the bit-field
is loaded using a 16-bit access:
`struct S { long af:16; long bf:16; };`
For EABI, the compiler does not use a narrower type to access `volatile`
bit-fields (bit fields declared with a volatile-qualified type). EABI
instead uses exactly the declared type. (COFF does use a smaller, more
efficient size for volatile` bit-fields if possible.)
Enumerated Type Sizes
--------------------
Many enumerated types have members with values that are small enough to
fit into integer types smaller than `int`. Both COFF ABI and EABI use
int-sized containers to store variables of such enumerated types.
For C++ code, both COFF ABI and EABI use integer types wider than `int`
for enumerated types with values too large to fit in an `int`.
In short, there are no COFF ABI to EABI migration issues related to
enumerated types.
Data Page (DP) Pointer Load Optimization
--------------------
The C28x supports direct addressing through the data page pointer register, DP.
The DP register points to the beginning of a page, which is 64 words long.
To avoid loading the DP for every direct access, the compiler "blocks" some data and sections. Blocking
ensures that an object is either entirely contained within a single page or is aligned to a 64-word page
boundary.
Differences between the blocking rules for COFF and EABI are described in Section 3.11
of the *TMS320C28x Optimizing C/C++ Compiler User's Guide*.
STABS Debugging Not Supported
----------------------------------------------------------------
The `--symdebug:coff` and `--symdebug:profile_coff` compiler options request
the use of STABS debugging information, which is
available only for COFF files. These compiler options are not supported in
EABI mode. ELF files must use DWARF as required by
the ELF specification.
Run-Time-Support Library
-----------------------------------------
The compiler automatically links with an EABI version of the Run-Time Support Library
when you compile with the `--abi=eabi` option.
If libc.a is explicitly used, the appropriate run-time-support library is included
in the search order where libc.a is specified.
Statements in asm()
----------------
The contents of `asm()` statements are assembly code rather than C/C++ code, and need to
be changed as shown [below](#assembly-code-changes).
Conflicts Between Variable and Register Names
---------------------------------------------
In the following code, the variables `acc` and `p` are
named the same as the machine registers ACC and P:
```
extern unsigned long acc;
unsigned long p;
void foo(void)
{
acc = p;
}
```
When compiled under COFF ABI, the `acc` and `p` symbols get an
underscore prefix in the assembly code that is generated by the
compiler.
Under the EABI model, however, the compiler does not add an
underscore prefix to symbol names. The compiler avoids
conflicts between variable names in C/C++ and register names by
using an escape character sequence around C/C++ variables. In the above
example, the compiler refers to the `acc` and `p` variables
using `||acc||` and `||p||`, respectively.
For example, compiling the above for EABI yields assembly like the following:
```
.global ||foo||
.global ||acc||
.global ||p||
.bss ||p||,4,4
.sect ".text"
||foo||:
MOVW DP, #||p||
MOVW ACC, #||p||
MOVW DP, #||acc||
MOVW @||acc||, ACC
LRETR
```
Assembly Code Changes
=============================================
The C ABI is how the compiler expresses C code programs in assembly
language. Assembly code that defines a C-callable function or calls a C
function must conform to the ABI. This section describes changes that
must be made to assembly code due to the differences between COFF and EABI in the way
C and C++ features are implemented in assembly code.
The changes that need to be made to existing assembly code are
primarily limited to places where assembly code interfaces with C or
C++ code. Assembly functions that do not interface with C or C++ code
directly do not need to be changed.
COFF Underscore Name Mangling
-----------------------------
The COFF ABI uses underscores to keep the assembly code namespace and the C
code namespace separate. The C compiler prepends an underscore to every
externally visible identifier so that it will not collide with an
assembly object with the same name. We call this the *COFF underscore*.
For example, this source code:
```
int x;
int func(int y) { }
```
Becomes the following in assembly compiled for the COFF ABI:
```
.bss _x, 4, 4
_func:
```
Note how the C/C++ symbol `x` becomes `_x` in the assembly code.
Assembly functions that attempt to use `x` need to use the name `_x`.
**EABI does not add the COFF underscore.** This is a generic ELF
requirement. The code must ensure that user-defined names
don't collide. Assembly code that is intended to work for both COFF ABI
and EABI must handle the difference in mangling (see
[Conditional Redefinition Method](#conditional-redefinition-method) or
[Double Label Method](#double-label-method)).
The C source code above becomes the following in EABI:
```
.bss x, 4, 4
func:
```
Removing the COFF Underscore
----------------------------
The COFF ABI adds a leading underscore to C and C++ symbols to prevent name
collisions with symbols defined in hand-coded assembly, but EABI does
not add this underscore. When using COFF ABI, a function named `red_fish`
written in C produces a function entry label with the name
`_red_fish` in the assembly source. Under the EABI, the name of the
function as it appears in the assembly source will be exactly as it
appears in the C code, so the function entry label for `red_fish` will be
`red_fish`.
Functions and variables may be defined in assembly code and used in C
code. To use functions and variables in a hand-coded assembly file from
a COFF ABI program in EABI, the symbol label needs to be changed, or
augmented with a second label. There are approaches to managing this
issue.
### Conditional Redefinition Method
The preferred solution for code that will be used with both COFF and
EABI is to replace the COFF ABI mangled name with an EABI C name using
an `.asg` assembler directive.
For example, a function `red_fish` called
from C will have a definition in the COFF ABI assembly code with a
function entry label named `_red_fish`. Insert a conditional `.asg`
directive in front of the definition as follows:
```
.if __TI_EABI__
.asg red_fish, _red_fish
.endif
.global _red_fish
_red_fish:
```
In the above example, all instances of `_red_fish` are replaced with
`red_fish` due to substitution symbol expansion. The assembler
defines the label, `red_fish` and makes it visible externally via the
`.global` directive.
### Double Label Method
Another easy solution is to provide two labels, one providing the COFF
ABI mangled name, and the other providing the EABI name. For example:
```
.global _red_fish, red_fish
_red_fish:
red_fish:
```
A drawback to this solution is that there remains an extra symbol name
that might collide with a user-defined name.
### Preprocessor Redefinition Method
For projects in which the assembly code cannot be readily modified, the
assembler's substitution symbol mechanism can be used to redefine
individual symbols. The technique is to create either a C source header
file or an assembly include file that redefines each symbol. This
include file can then be implicitly included in an assembly file
using the `--include_file` assembler option.
C++ Name Mangling and Overloaded Functions
-----------------
The compiler uses name mangling to encode into the name of C++ functions
the types of its parameters so that the linker can distinguish
overloaded functions.
COFF ABI and EABI use different name mangling schemes for C++ functions,
so assembly code that refers to the mangled names directly must
be changed to use the EABI mangling.
This is an example of the difference in name mangling:
| | `int func(int);` | `int func(float);` |
|------------ |---------------- |------------------ |
| **COFF ABI** | `_func__Fi` | `_func__Ff` |
| **EABI** | `_Z4funci` | `_Z4funcf` |
Mangled function names become more complex for functions with multiple arguments.
Direct references to mangled C++ names are unlikely unless the output
assembly file from compiling a C++ file was captured and hand modified.
The best migration path is to just re-compile the original C++ file. If
the hand-modifications are too extensive to do this, the fastest way
to find the EABI mangled names is to re-compile the original C++ file
and examine the generated assembly code to see the EABI mangled names.
Pass the `--abi=eabi` option to `dem2000` to demangle EABI C++ names.
Structures Passed or Returned by Value
--------------------------------------
With COFF ABI, all structs that are passed or returned by value in C code
are transformed by the compiler so that in the generated assembly code
they are passed by reference. The compiler puts the struct in a
temporary location and passes a pointer to this temporary location in place of
the struct.
With EABI, small, homogeneous float structs passed or returned by value in
C code are passed or returned by value in the generated assembly code,
either in a register or on the stack as appropriate. Larger structures
are passed by reference as with the COFF ABI. A small, homogeneous float struct
is defined as a struct of a size less 128 bits that contains only float
typed data or consists of nested structs/arrays that themselves only
contain float-typed structs. For example, these are all small, homogeneous float structs:
```
struct S1 { float f1; float f2 }
struct S2 { float f1; float array[2]; }
struct S3 { struct S1 array[2]; }
```
Structs passed in registers use the same registers as scalars, R0H-R3H.
C-callable assembly functions that accept, return, or pass small
structures by value need to be re-written to follow this convention.
### Structure Passing with the CLA Compiler
For CLA functions compiled in COFF ABI mode, all structs that are passed
or returned by value in C code are transformed by the compiler so that
in the generated assembly code they are passed by reference. As in C28x
generated code, the compiler puts the struct in a temporary location and
passes a pointer to this temporary location in place of the struct.
For CLA functions compiled in EABI mode, small structs containing only
scalar type members up to 96-bits in size that are passed or returned by
value in C code are passed or returned by value in the generated
assembly code, either in registers or on the stack as appropriate.
Similarly, small structs containing only pointer type members up to
64-bits in size that are passed or returned by value in C code are
passed or returned by value in generated assembly code, whether in
registers or on the stack as appropriate.
Larger structures are passed
by reference with EABI (as in COFF ABI mode). Scalar type members of a struct, up to
32-bits in size will be passed in MR0, MR1, or MR2, and returned in MR0,
MR1, or MR2. Any 32-bit pointer type members of a struct are passed and
returned in MAR0 or MAR1.
The exact registers used in a call to a given
function depend on the type and order of the arguments. Likewise,
the exact registers containing the return struct type value depend
on the details of the return struct type's members.
Relocation Expressions Are Not Supported by EABI
----------------------------------------
Assembly expressions involving two or more relocatable symbols cannot
be represented in C2000 ELF object files. Any such expression will need
to be rewritten into two or more instructions.
For example, the following will not work with EABI if both symbols are resolved at
link time:
```
thing_size: .word (thing_end - thing_begin)
```
Legacy .cinit Use in Assembly Source
--------------------------------
The COFF ABI uses the .cinit mechanism to initialize global variables.
This mechanism is intended to be used only by the compiler, but some hand-coded
assembly source encodes variable initialization with hand-encoded .cinit
tables. This will work under COFF ABI so long as the encoding is
correct. However, this method will not work in EABI, because EABI uses
direct initialization instead, which means the linker creates all .cinit
records.
The recommended migration path is to rewrite the .cinit initialization
as direct initialization and let the linker handle creating the
initialization record. For example, the following .cinit record can be
rewritten as shown:
```
glob: .usect ".far", 8, 4 ; 8-byte object aligned to 4 bytes in uninitialized section ".far"
.sect ".cinit"
.align 8
.field 8, 32 ; length in bytes
.field glob, 32 ; address of memory to initialize
.field 2, 32 ; initialize first word to 2
.field 3, 32 ; initialize second word to 3
.sect ".fardata", RW ; 8-byte object in initialized section ".fardata"
.align 4
glob: .field 2, 32 ; directly initialize first word to 2
.field 3, 32 ; directly initialize first word to 3
```
For more information about using direct initialization, see the
*TMS320C28x Optimizing C/C++ Compiler User's Guide* ([SPRU514](https://www.ti.com/lit/pdf/spru514)).
Legacy STABS Directives in Assembly Source
------------------------------------------
If there are any STABS (COFF debug) directives in an
assembly file (this typically only happens for assembly code generated
by the compiler), these directives must be deleted or conditionally
compiled out when using EABI mode.
ELF does not support STABS, and the assembler emits an error message
if the input file contains STABS directives. To reuse the file for EABI,
strip out all the STABS directives.
Example STABS directives are: `.file`, `.func`, `.block`, `.sym`
Run-Time-Support Library Helper Functions
-----------------------------------------
The RTS library contains some *helper functions* to perform complicated
operations for certain high-level language features. It is not expected
that hand-coded assembly code would call these functions, but it is
possible, particularly if the output of the compiler is tweaked by hand
and transformed into an assembly input file. These helper functions have
different names in EABI. If the assembly code directly calls a library
helper function, the code needs to use the new name for the
function. The easiest way to deal with these functions is to use the
assembler `--include_file` option to include a list of assembler defines
to change the names of the old functions.
For example, create a C header file `coff_to_elf_helpers.h`:
```
#define __divi __c28xabi_divi
#define __divu __c28xabi_divu
...
```
Include this file in another header file `coff_to_elf_helpers.i`:
```
.cdecls C, LIST, "coff_to_elf_helpers.h"
```
Then include this file at the beginning of every assembly file:
```
cl2000 --include_file=coff_to_elf_helpers.i
```
Linker Command File Changes
===========================
When porting a COFF ABI application to EABI, the most likely place you
will need to make changes is the linker command file. The linker
supports linker command file preprocessing. See the
*TMS320C28x x Assembly Language Tools User's Guide* ([SPRU513](https://www.ti.com/lit/pdf/spru513)).
EABI Sections
-------------
The names of some sections have changed for EABI.
EABI re-uses most compiler-generated section names used by COFF ABI. It
also introduces some new section names. Each section needs to be allocated to
appropriate memory.
Your linker command
file should have an explicit placement for each section. If you do not
do this, the linker will try to use the placement for the old section name if
it is specified in the linker command file.
Make the following changes when migrating from COFF to EABI:
* `.ebss` -> `.bss`
* `.econst` -> `.const`
* `.esysmem` -> `.sysmem`
* `.pinit` -> `.init_array`
* `.cio` -> `.bss:.cio`
The following sections have the same names in both COFF and EABI:
* `.text`
* `.data`
* `.cinit`
* `.args`
* `.stack`
The following sections are new for EABI:
* `.c28xabi.exidx` (like `.const`)
* `.c28xabi.extab` (like `.const`)
![](images/c28x_migrate_coff_to_eabi_sections.png "COFF to EABI Sections")
### Conditional Control of Sections
You can use the `__TI_EABI__` predefined symbol to conditionally control section placement.
```
#if defined(__TI_EABI__)
.init_array : > FLASHC, PAGE = 0
.const : > FLASHB, PAGE = 1
#else
.pinit : > FLASHC, PAGE = 0
.econst : > FLASHB, PAGE = 1
#endif //__TI_EABI__
```
### Read-Only Sections
EABI introduces the following read-only sections
- `.init_array` data, used to register C++ global variable constructors
- `.c28xabi.exidx` data, index table for C++ exception handling
- `.c28xabi.extab` data, unwinding instructions for C++ exception hand
The data section `.init_array` serves the same purpose that `.pinit` does for
COFF ABI. EABI does not use the name `.pinit`.
### The `.init_array` Section
For EABI, if `.init_array` is not allocated in the linker command file and the `.pinit`
section is allocated, the linker automatically allocates the
`.init_array` section to the same memory area as the `.pinit` section.
If the `-w` option is used, the linker also generates a warning.
Either explicitly allocate the `.init_array` section in the linker
command file or if there are no `.pinit` sections, remove the `.pinit`
allocation from the linker command file.
No Leading Underscores
----------------------
The symbol names used in linker command files are the names that
appear in object files. For COFF, this means the mangled names. For
EABI, the object file names are the same as the high-level language
names, so any reference or definition of a symbol in a linker command
file will need to be changed.
For example, to set a symbol to the value of the `main` function.
COFF ABI:
```
mainaddr = _main;
_symbol = 0x1234;
```
EABI:
```
mainaddr = main;
symbol = 0x1234;
```
Section and Struct Initialization Issues
----------------------------------------
In EABI mode, the compiler initializes any uninitialized sections. This supports the C language,
which states that uninitialized global variables are initialized to zero.
Such zero-initialization can cause some issues:
* **Header file structures:** One issue occurs when using peripheral or register structs
in header files and in the linker command files associated with those header files.
All of these structs are uninitialized, so when compiling for EABI, the registers
are zero-initialized during the `__c_int00` code. This causes the CPU to write to those
registers. However, writing to DCSM key registers may cause a device reset, which would
make `__c_int00` unable to complete and get to `main()`.
Therefore, it is recommended that such sections (including all register sections from
the header file structures) should be set to NOINIT in the linker command file. For example:
```
DcsmZ1RegsFile : > DCSM_Z1, PAGE = 1, type=NOINIT
```
* **Message RAMs:** Another issue concerns message RAMs. The CPU is not able to write
to some message RAMs that are meant to be read-only by that CPU. In this case,
you should also add NOINIT to the message RAMs. Additionally, some RAM init bits are available
for the application to use to initialize data in the message RAMs.
Another way to prevent structs from being zero initialized,
is to use the `noinit` attribute when declaring them in C code.
To disable all zero-initialization in EABI mode, you may use the `--zero_init=off` linker option.
Partial Linking
---------------
Relocation entries are not processed during a partial link under the
EABI. Relocation entries that involve a static base reference will simply
be carried forward until you are ready to create an executable
output file with the linker. At that point, the linker defines a
value for the `__TI_STATIC_BASE` symbol used in the resolution
of any static-base relative relocation that is encountered.
Conditional Linking: Section Removal or Retention
---------------------------
In COFF ABI mode, if an object file is explicitly included in the link
step or is pulled in from an object library to resolve a symbol
definition, then, by default, the linker includes all
sections in such an object file into the linked output file. This can be
inefficient when an object file contains many sections that are not
needed in the link but are included solely because one section in
the file resolves a symbol.
To alleviate this inefficiency in COFF, the Code Generation Tools have
for a long time provided a `.clink` assembler directive, which allows you
to indicate that a section is eligible for removal by
the linker if it is not referenced. This technique is referred to
as *conditional linking*. In COFF ABI the compiler generates a `.clink`
directive for code sections automatically. That is, for COFF, compiler-generated
code sections are eligible for removal via conditional
linking. (Compiler-generated data sections are always linked by the
linker.)
In EABI mode, by contrast, all sections are eligible for removal via conditional
linking *by default*. This means that when migrating a COFF ABI application to
EABI, one must make sure that needed but unreferenced sections (such as
overlays or debug functionality) are explicitly retained.
To help developers migrate COFF applications to
EABI and create new EABI applications, the Code Generation Tools now
support the following mechanisms:
* The following pragma can be used in C/C++ source files
```
#pragma RETAIN(``)
```
When this pragma is applied to a function or data object symbol,
it instructs the compiler to generate a `.retain` assembler
directive into the section that contains the definition of the
symbol. This provides a mechanism for the developer to indicate
in their C/C++ source that a section containing the specified
symbol is to be considered ineligible for removal during
conditional linking.
**NOTE:** When compiling code for an interrupt function that is written in C/C++,
the compiler generates a `.retain` directive into the section that contains
the definition of the interrupt function. This can be overridden by applying
`#pragma CLINK()` to the interrupt function symbol.
* The following directive can be used in assembly source files:
```
.retain [""]
```
If a "section name" argument is provided to the `.retain`
directive, the assembler marks the specified section as
ineligible for removal by conditional linking. If no "section
name" argument is specified, then the currently active
initialized section is marked as ineligible for removal via
conditional linking.
* The linker option `--retain` can be used to specify a symbol or
section to be retained by the linker.
Note also that the compiler now automatically detects interrupt vectors.
It marks them ineligible for conditional linking to help
users easily migrate from COFF ABI to EABI.
If you want to retain all sections, you can use the `--unused_section_elimination=off`
linker option. However, be aware that code size may be significantly larger with this setting.
Special Symbol Names
===============
Both COFF ABI and EABI define special symbols to manage ABI
functionality and memory usage. Some variables were renamed for EABI to
bring them in line with the EABI standard. Note that a `__TI` prefix is
now a standard part of many symbol names.
Symbol Name Changes
-------------------
In the table below, the COFF ABI name is the name as it would appear in assembly code or the
linker command file. The EABI name is the new name for the symbol in
EABI. Uses of the old name in linker command files or assembler files
should be updated or conditionalized to refer to the new name, as
appropriate.
| COFF ABI Name | EABI Name | Purpose | COFF names in EABI? | Notes |
|---------------------- |---------------------- |----------------------------------------------- |--------------------- |------------------------------------------------------------------------------------------- |
| `___binit__` or `binit` | `__binit__` or `binit` | Boot-time initialization | | Changes from 3 leading underscores to 2 |
| `___c_args__` | `__c_args__` | Command-line arguments | Yes | Changes from 3 leading underscores to 2 |
| `___cinit__` or `cinit` | `__TI_CINIT_Base` | Start of C global variable initializers table | No | New compressed table format in EABI. Not NULL terminated in EABI; see `__TI_CINIT_Limit` |
| N/A | `__TI_CINIT_Limit` | End of C global variable initializer data | | |
| `___data__` | N/A | Beginning of the .data section | | |
| `___edata__` | N/A | End of the .data section | | |
| `___end__ | N/A | End of the .bss section | | |
| `___etext__` | N/A | End of the .text section | | |
| `___pinit__` or `pinit` | `__TI_INITARRAY_BASE` | Start of C++ global object initializers table | Yes | Not NULL terminated in EABI; see `__TI_INITARRAY_Limit` |
| N/A | `__TI_INITARRAY_Limit` | End of C++ global object initializer data | | |
| `___text__` or `.text` | N/A | Beginning of the .text section | | |
| `__bss__` `.bss` or `$bss` | `__TI_STATIC_BASE` | Start of DP-relative data | Yes | |
| `__STACK_SIZE` | `__TI_STACK_SIZE` | Size available for function frame stack | Yes | |
| `__SYSMEM_SIZE` | `__TI_SYSMEM_SIZE` | Size available for heap allocation | Yes | |
| `__STACK_END` | `__TI_STACK_END` | End of the .stack section | Yes | |
| `C$$EXIT` | `C$$EXIT` | Special host I/O trap | | |
| `C$$IO$$` | `C$$IO$$` | Special host I/O trap | | |
Symbol Termination and Format
-------------------
In COFF ABI `.pinit` and `.cinit` are terminated with NULL records.
In EABI the ending addresses of `.init_array` and `.cinit` are indicated by
the corresponding LIMIT symbol. For more information about the format of
`.init_array` and `.cinit`, see the
*TMS320C28x Optimizing C/C++ Compiler User's Guide* ([SPRU514](https://www.ti.com/lit/pdf/spru514)
and the *C28x Embedded Application Binary Interface Application Report* ([SPRAC71](https://www.ti.com/lit/pdf/sprac71)).
Also note that with EABI the CINIT table has a new compressed format. For
details, see the *TMS320C28x Optimizing C/C++ Compiler User's Guide*.
Backward Compatibility
----------------------
To provide backward compatibility under EABI, the linker will continue to recognize
several of the old symbols names and will define them at link time *if*
they are used, while also generating a warning referring you to
their new name. Refer to the "COFF names in EABI?" column in the table above to identify
symbols that are supported in this manner.