12. Extended attributes¶
An attribute is a property attachable to functions, data objects,
or types, specified as a keyword. Standard C includes built-in
keywords like const and volatile.
Extended attributes provide access to behaviors or properties beyond Standard C. They are either target-specific or useful for embedded systems.
12.1. Overview¶
Attributes can be applied with either keyword syntax (e.g.,
__far) or attribute syntax (e.g.,
__attribute__((far))). Both are functionally equivalent,
but the C parser may not accept the keyword form in some situations.
Usage is largely a matter of preference. Preprocessor macros can rename attributes for portability, enabling them to be toggled off for other targets or renamed to match different compilers or targets.
Note
The C parser sometimes produces unexpected errors with the keyword
form of attributes (e.g., __far). If this occurs,
use the __attribute__((far)) form instead.
12.2. Using attributes¶
Type attributes can be applied to type declarations, following the same
syntax as type qualifiers like const and volatile.
Syntax for data objects¶
You can apply attributes to data objects as follows:
__attribute__((far)) int a, b;
int __far c, d;
When applied to an object, the attribute’s location is irrelevant.
The example above applies the Far memory attribute to all
defined objects (a, b, c, and d).
Syntax for pointer types¶
Attributes can also be applied to pointer types, where their location is significant. This determines whether the pointer itself is constant or what it points to is constant.
The easiest way to decipher attributes in function types is to read the type from right to left.
int __attribute__((far)) * p1;
long * __attribute__((far)) p2;
Here, p1 is a pointer stored in default memory that points to an
int in Far memory memory. p2 is a pointer stored
in Far memory memory that points to a long in default
memory.
12.3. Attribute reference¶
This section goes through all available extension keywords and attributes.
Summary of attributes¶
The following table summarizes available attributes. For the keyword
form, prefix with two underscores (e.g., __far). For
attribute syntax, use the attribute name with __attribute__ (e.g.,
__attribute__((far))).
Attribute name |
Description |
|---|---|
|
Specify alignment of data object or function |
|
Specify section name to use for a data object or function |
|
Control storage of data object to near area |
|
Control storage of data object to far area |
|
Used to define an interrupt function |
|
Amiga style interrupt function |
|
Used to declare an intrinsic function |
|
Entry point that needs to initialize
the base pointer in register |
|
Relaxes preserving registers |
Description of attributes¶
This section describes each attribute in detail.
aligned¶
This attribute can be applied to functions, global and static data objects to force a certain minimal alignment.
The aligned attribute takes an argument which is the alignment to
use:
__attribute__((aligned(16))) struct sprite ship;
Note
Certain data types may impose an alignment by themselves. The actual alignment is choosen so that all alignment constraints are satisfied.
section¶
This attribute can be applied to functions, global and static data objects to control the name of the section it is placed in.
The section attribute takes an argument which is the section name
to use:
// Place in vram
__attribute__((section("vram")))
const char tiles[256] = { .. };
__attribute__((section("trueCode")))
long foo () {
return 42;
}
See Description of pragma directives for how you can specify a section for multiple functions, global and static data objects.
near¶
This specifies a data object or a pointer to a data object that resides in a Near area. Accessing a global or static object in this area saves two bytes for each machine instruction used compared to the Far area.
Register A4 is reserved to hold a base pointer to this area.
far¶
This specifies a data object or a pointer to a data object that can reside anywhere in memory.
The code needed to access Far memory tend to be slightly larger compared to the Near memory.
interrupt¶
An interrupt function is meant to serve as an interrupt handler. The interrupt attribute has the following effects:
An interrupt function cannot take any parameters
An interrupt function will preserve all registers used
Leaving the interrupt function uses a different instruction sequence compared to normal functions
The interrupt attribute may optionally be given a vector address as an argument.
The interrupt vector specified as an argument to the interrupt attribute:
int counter;
__attribute__((interrupt(0x0064)))
void irq () {
counter++;
}
Note
The vector argument is optional. Omitting it means that there will be
no vector section entry generated for that interrupt function.
You can also suppress all vector sections from being generated by
using the --no-vector-sections command-line option.
amiga_interrupt¶
The amiga_interrupt attribute defines an interrupt function
intended to be used with the Amiga operating system. The
Amiga interrupt has the following effects:
An Amiga interrupt function cannot take any parameters
Follows the register convention of an Amiga interrupt, registers
D0,D1,A0,A1,A5andA6are considered scratch registers.The return type should be
intand you normally want to return0to allow interrupt processing further interrupt chain.
Here is a simple example of how an Amiga interrupt definition may look:
int counter;
__attribute__((amiga_interrupt))
int irq () {
counter++;
return 0;
}
Note
There is no interrupt vector associated with an Amiga interrupt definition. You need to use the Amiga operating system calls to install the interrupt handler.
intrinsic¶
The intrinsic attribute is used to declare intrinsic built-in
functions. This can only be done on intrinsic functions that is
already known to the compiler. Normally you use this by including the
calypsi/intrinsics68000.h file which contains all such valid declarations.
saveds¶
A saveds function sets up the A4 base address upon entry and
restores the previous value of A4 when returning. This is useful
for API functions called from another context where A4 may
point to another base area or used for another purpose.
task¶
A task attribute can be used on functions such as main which
is the start of the application. You will not normally call such
functions from any C code. In that case you can apply the task
attribute which relaxes preserving registers that would otherwise be
saved on the stack. This can save a little stack space and will make
the application a tiny bit smaller.