The Reference section describes the ARM ABI and ARM-specific attributes of the main GNUPro tools.
This section describes features of the GNUPro ARM and Thumb compilers.
By default the ARM compiler supplied with eCos will produce code optimized for the ARM7m processor. This code will run on other, higher, ARM processors including the StrongARM, but to get the best possible performance the target cpu should be specified on the compiler command line using the '-mcpu=' switch documented below.
For a list of available generic compiler options, refer to "GNU CC Command Options" in Using GNU CC in GNUPro Compiler Tools . In addition, the following 'arm-elf-gcc' and 'thumb-elf-gcc' specific command-line options are supported:
-mabort-on-noreturnThis switch tells the compiler to insert a call to the library function 'abort' at the end of any function which has the 'noreturn' attribute.This is disabled by default because some eCos configurations may not have the abort library call present.
Generate a stack frame upon entry to a function, as defined in the ARM Procedure Calling Standard.
Do not generate a stack frame upon entry to a function. The APCS specifies that stack frames are optional, and omitting them produces lightly smaller and faster code. However, debugging with stack frames omitted can be more difficult. This is the default setting.Produce assembly code that conforms to the 32-bit version of the ARM Procedure Calling Standard. This is the default setting.
Produce assembly code that conforms to the 26-bit version of the ARM Procedure Calling Standard, as used by earlier versions of the ARM processor (ARM2, ARM3).Produce assembly code which checks the amount of stack space available upon entry to a function and which calls a suitable function if their is insufficient space available.Do not produce code to check for stack space upon entry to a function. This is the default setting.
Produce assembly code that is position independent and reentrant.Do not produce position independent, reentrant assembly code. This is the default setting.Two byte values should be loaded by performing two individual byte loads and then merging the results. This allows shorts to be loaded from non-aligned addresses without generating a memory access fault.
Two byte values should be loaded using the most space efficient method. On an ARM processor that supports half word loads these instructions will be used. This is the default setting.Floating point instructions should be emulated by the ARM Floating Point Emulator code, which is supplied by the operating system.Floating point instructions should be emulated by the ARM Floating Point Emulator code version 'N'. Valid version numbers are 2 and 3. 2 is the default setting.
Floating point instructions should be emulated by library calls. This is the default setting.Floating point instructions can be performed in hardware.Produce assembly code which is targeted for a big endian processor.Produce assembly code which is targeted for a little endian processor. This is the default setting.
Produce assembly code which is targeted for a big endian processor, but which stores words in a little endian format. This is for backward compatibility with older versions of GCC.Produce assembly code which supports calls between the ARM instruction set and the Thumb instruction set.Do not produce code specifically intended to support calling between ARM and Thumb instruction sets. This is the default setting.Allow instructions in function prologues to be rearranged to improve performance. This is the default setting.Do not allow the instructions in function prologues to be rearranged. This guarantees that function prologues will have a well-defined form, depending upon their nature.Produce assembly code specifically for the indicated processor. The variable 'XXXX' can be one of the following processors.
Note: If '-mcpu' is not specified, the default is to generate code for the 'arm7m' .
Produce assembly code specifically for an ARM processor of the indicated architecture. The variable 'XXXX' can be one of the following architectures.
armv2
armv2a
armv3
armv3m
armv4
armv4t
Note: If '-march' is not specified, the default is to generate code for the 'armv4' .
-mtpcs-frame
Generate a stack frame upon entry to a non-leaf function, as defined in the Thumb Procedure Calling Standard. A leaf function is a function that does not call any other function.Do not generate a stack frame upon entry to a non-leaf function. The TPCS specifies that the generation of stack frames is optional, hence this pair of options. This is the default setting.Generate a stack frame upon entry to a leaf function, as defined in the Thumb Procedure Calling Standard.Do not generate a stack frame upon entry to a leaf function. This is the default setting.
Produce assembly code which is targeted for a big endian processor.Produce assembly code which is targeted for a little endian processor. This is the default setting.Produce assembly code which supports calls between the ARM instruction set and the Thumb instruction set.Do not produce code specifically intended to support calling between ARM and Thumb instruction sets. If such calls are used, they will probably fail. This is the default setting.
The following 'arm-elf-gcc' and 'thumb-elf-gcc' specific preprocessor symbols are supported:
For a compete description of attributes, see "Declaring Attributes of Functions" and "Specifying Attributes of Variables" in "Extensions to the C Language Family" in Using GNU CC in GNUPro Compiler Tools. There is one ARM-specific attribute:
naked
This is a function attribute. GCC will not generate any prologue or epilogue code for any function with this attribute. It is up to the programmer to provide any necessary prologue and epilogue code themselves (possibly via asm() statements).
The GNUPro compiler and linker have been improved by Cygnus to provide even more benefits for customers developing for embedded targets. These features are guaranteed order of initialization at startup, and selective linking.
In C++, you can define static and global objects with constructors, or initialize static and global variables from a function. This means that the constructors or functions are run before the rest of your program starts. However, when you have these objects spread over multiple files, the C++ standard does not specify the order in which they are initialized, and for all practical purposes the order is random. For an embedded system, this can be a problem, as you may want to ensure that a static scheduler object is initialized before static threads can attach to it, or that devices are initialized before they are used. GNUPro solves this problem by allowing you to define a priority when the static or global is declared. The following example shows the syntax:
static object_t myobj __attribute__((init_priority (30000) ));
The syntax is slightly different if the object takes any arguments to its constructor:
static object_t myobj __attribute__((init_priority (30000) )) = object_t(arg1, arg2);
The numeric priority can be from 1 to 65535, with 1 being the highest priority, and 65535 being the lowest. The default priority for objects without this attribute is 65535. Constructors with a higher priority are guaranteed execution before constructors with lower priority.
In all cases, you must provide the argument '-finit-priority' to the compiler on its command-line for it to recognize this attribute when you are compiling your C++ source files.
If you are using eCos, be warned that eCos uses initialization priorities internally. Ensure you choose an appropriate priority level so that other eCos subsystems will have initialized before you refer to them in your own constructor.
When writing C and C++ code, it is sometimes natural to include more than one function in a source file. For example in C++, it is common to have all methods for a particular class contained in the same C++ source file. However, there is a drawback that, conventionally, if you use just one of these functions, then all the functions defined in that file also get included in the final executable image. For an embedded system, this can substantially and unnecessarily increase the size of the final image stored in ROM, or loaded into RAM when debugging.
The GNUPro C and C++ compilers can now optionally remove these unnecessary functions from the final image. They also ensure that any shared global data is removed that is only referenced by functions that are removed. This can be done by including the options '-ffunction-sections' and '-fdata-sections' on the command-line, when you invoke the C or C++ compiler. The '-ffunction-sections' option removes unnecessary functions, and the '-fdata-sections' option removes unnecessary data.
In addition, when classes define virtual methods in C++, it is possible to remove any unused methods from the final image by passing the option '-fvtable-gc' to the C++ compiler on its command-line.
In all cases, you must also supply a command-line option when linking. If invoking the linker ld directly, use '--gc-sections' on its command-line; alternatively, if you are using the preferred method of linking your executable, using the form:
then also pass the option '-Wl,--gc-sections' on the compiler command-line, for example:
The ARM tools adhere by default to the APCS (ARM Procedure Call Standard). The Thumb tools adhere to the TPCS (Thumb Procedure Call Standard). The following ABI summary is consistent with both these standards.
The following table shows the size and alignment for all data types:
The following describes the calling conventions for subroutine calls. The first table outlines the registers used for passing parameters. The second table outlines other register usage.
The following table describes the APCS and TPCS names for the general purpose registers.
The names are presented in the format: <Raw register name>, <APCS name>
This section describes the ARM and Thumb stack frame:
Stack frames for functions that take a fixed number of arguments look like this:
Stack frames for functions that take a variable number of arguments look like this:
A floating-point value occupies one, two, or three words, as appropriate to its type. Floating point values are encoded in IEEE 754 format, with the most significant word of a double having the lowest address.
Note: When targetting little-endian ARMs, the words that make up a double will be stored in big-endian order, while the bytes inside each word will be stored in little-endian order..
The C compiler widens arguments of type float to type double to support inter-working between ANSI C and classic C.
Char, short, pointer and other integral values occupy one word in an argument list. Character and short values are widened by the C compiler during argument marshalling.
A structure always occupies an integral number of words (unless this is overridden by the '-mstructure-size-boundry' command line option).
Argument values are collated in the order written in the source program
The first four words of the argument values are loaded into 'a1' through 'a4', and the remainder are pushed on to the stack in reverse order (so that arguments later in the argument list have higher addresses than those earlier in the argument list). As a consequence, a floating-point value can be passed in integer registers, or even split between an integer register and the stack.
The following sections describe how different data types are returned.
Floats and integer-like values are returned in register 'r0'.
A type is integer-like if its size is less than or equal to one word and if the type is a structure, union or array, then all of its addressable sub-fields must have an offset of zero.
struct {int a:8, b:8, c:8, d:8;}
is not, because it is possible to take the address of fields B, C or D, and their offsets from the start of the structure are not zero.
Doubles and 'long long' integers are returned in registers 'r0' and 'r1'. For doubles 'r0' always contains the most significant word of the double. For 'long long' values 'r0' only contains the most significant word if the target is big-endian.
All other values are returned by placing them into a suitably sized area of memory provided for this purpose by the function's caller. A pointer to this area of memory is passed to the function as a hidden first argument, generated at compile time. For example:
LargeType t;
t = func(arg);
LargeType t;
(void) func(&t,arg);
This section describes ARM-specific features of the GNUPro Assembler.
For a list of available generic assembler options, refer to "Command-Line Options" in Using AS in GNUPro Utilities.
-m[arm][1|2|3|6|7[xx][t][[d]m]|8[10]|9[20][tdmi]]
-mstrongarm[110[0]]
Select processor variant.Select architecture variant.Only allow Thumb instructions.Allow any instruction.
Select the v1.0 floating point architecture.Select the v1.1 floating point architecture.Don't allow floating-point multiple instructions.Don't allow any floating-point instructions.Mark the assembled code as supporting inter-working.Mark the code as supporting the 26 bit variant of the ARM Procedure calling standard. This is the default.Mark the code as supporting the 26 bit variant of the ARM Procedure calling standard.
Assemble code for a big endian CPU.Assemble code for a little endian CPU. This is the default.
The ARM syntax is based on the syntax in the Advanced RISC Machine Architecture Reference Manual.
Assembler comments start with the '@' (at symbol) and extend to the end of the line.
These are the supported register names, in the format:
The assembler supports hardware floating point, but the compiler does not.
For detailed information on the ARM machine instruction set, see Advanced RISC Machines Architectural Reference Manual. The GNU Assembler (GAS) implements all the standard opcodes.
The assembler supports the following synthesized instructions (pseudo instructions, which correspond to two or more actual machine instructions).
.arm
The following code uses the ARM instruction set.The following code uses the Thumb instruction set.
An alias for .thumbAn alias for .armThe following code uses the Thumb instruction set, and should be assembled even if the target processor does not support Thumb instructions.The following label is the name of function which has been encoded using Thumb instructions, rather than ARM instructions.Start a literal pool.
Error: Unrecognized opcodeThis instruction is misspelled or there is a syntax error somewhere.
An immediate value was specified that is too large for the instruction
eCos generates linker scripts appropriate for the exact eCos configuration you have chosen. Instructions on how to use this linker script are provided in the manual Getting Started with eCos.
For a list of available generic linker options, refer to "Linker scripts" in Using LD in GNUPro Utilities. There are no ARM-specific command-line linker options.
This section describes ARM-specific features of the GNUPro Debugger.
The following instructions connect GDB to the remote target board. To load your program onto the target board, build eCos for the hardware with RAM startup. Provided the board is fitted with CygMon ROMs, or GDB loader stub ROMs, you may connect to the target board in GDB using the command 'target remote <devicename>' where '<devicename>' will be a serial device such as 'com2' (Windows NT) or '/dev/ttyS1' (Unix). Then load the code onto the target board by typing 'load'. After being downloaded, the program can be executed.
Little-endian targets may require the use of the 'set endian little' command to connect correctly. It may also be necessary to change the default baud rate before connecting to the target board by the using the 'set remotebaud <baudrate>' command.
Note: When using the remote target, GDB does not accept the 'run' command. However, since downloading the program has the side effect of setting the PC to the start address, you can start your program by typing 'continue' (the letter 'c' works as a shortcut for the 'continue' command).
For the available generic debugger options, refer to Debugging with GDB in GNUPro Debugging Tools. There are no ARM-specific debugger command-line options.
Programs with multiple threads can be debugged using either the graphic user interface to GDB, InsightTM or the GDB command line interface. The following describes how to debug multiple threads using the GDB command line.
In some operating systems, such as eCos, a single program may have more than one thread of execution. The precise semantics of threads differ from one operating system to another, but in general the threads of a single program are akin to multiple processes, except that they share one address space (that is, they can all examine and modify the same variables). On the other hand, each thread has its own registers and execution stack, and perhaps private memory.
GDB provides the following functions for debugging multi-thread programs
The GDB thread-debugging facility allows you to observe all threads while your program runs, but whenever GDB takes control, one thread in particular is always the focus of debugging. This thread is called the current thread. Debugging commands show program information from the perspective of the current thread.
For debugging purposes, GDB associates its own thread number, always a single integer, with each thread in your program.
info threads
Display a summary of all threads currently in your program. GDB displays for each thread (in the following order):
An asterisk '*' to the left of the GDB thread number indicates the current thread. Use the following example for clarity.
1 thread 1 Cyg_HardwareThread::thread_entry (thread=0x1111aaa2) |
Name: Idle Thread, State: running, Priority: 31, More: <none> |
Make thread number '<threadno>'the current thread. The command argument, '<threadno>', is the internal GDB thread number, as shown in the first field of the `info threads' display. GDB responds by displaying the system identifier of the thread you selected, and its current stack frame summary, as in the following output.
thread apply [<threadno>][<all>] <args>
The thread apply command allows you to apply a command to one or more threads. Specify the numbers of the threads that you want affected with the command argument '<threadno>', where '<threadno>' is the internal GDB thread number, as shown in the first field of the 'info threads' display. To apply a command to all threads, use 'thread apply all args'.
Whenever GDB stops your program, due to a breakpoint or a signal, it automatically selects the thread where that breakpoint or signal happened.
When your program has multiple threads, you can choose whether to set breakpoints on all threads, or on a particular thread.
If '<linespec>' specifies source lines, then there are several ways of writing them. Use the qualifier 'thread <threadno>' with a breakpoint command to specify that you only want GDB to stop the program when a particular thread reaches this breakpoint. '<threadno>' is one of the numeric thread identifiers assigned by GDB, shown in the first column of the 'info threads' display.
If you do not specify 'thread <threadno>' when you set a breakpoint, the breakpoint applies to all threads of your program.
You can use the thread qualifier
on conditional breakpoints as well; in this case, place 'thread
<threadno>'
before the breakpoint condition, as the following example shows.
Whenever your program stops under GDB for any reason, all threads of execution stop; not just the current thread. This allows you to examine the overall state of the program, including switching between threads, without worrying that things may change.
Conversely, whenever you restart the program, all threads start executing. This is true even when single stepping with commands like 'step' or 'next'. In particular, GDB cannot single-step all threads in lockstep. Since thread scheduling is up to your debugging target's operating system (not controlled by GDB), other threads may execute more than one statement while the current thread completes a single step. In general other threads stop in the middle of a statement, rather than at a clean statement boundary, when the program stops.
You might even find your program stopped in another thread after continuing or even single stepping. This happens whenever some other thread runs into a breakpoint, a signal, or an exception before the first thread completes whatever you requested.
For targets that support it, GDB has a new command that helps to debug multi-threaded programs.
Normally GDB does not attempt to interfere with thread scheduling. This means that in the default mode ('scheduler-locking off'), the current thread may be scheduled out, and a different thread may begin running, at any time (as determined by the native scheduler). For instance, you may give a GDB command such as 'step' or 'finish', and when the command completes, you may be looking at a different thread.
If you set the scheduler-locking mode to 'step', then GDB will try to interfere with the native scheduler just enough to prevent another thread from popping up while you debug. Other threads may get to run sometimes, but whenever a command such as 'step' or 'finish' completes, you should be looking at the same thread that was running before the command. Of course, if another thread gets to run and hits a breakpoint, GDB will still switch you to that thread (so if you don't want that to happen, then disable your breakpoints).
For even greater (and more intrusive)
control over the thread scheduler, GDB provides the mode 'scheduler-locking
on'. In this mode, the native scheduler is completely locked, and
no thread may run except the current one. Obviously this will radically
change the behavior of your program, and may lead to deadlock or other
unpleasant consequences, so use it with caution.
set scheduler-locking [off on step]
Set mode for locking scheduler during target execution.
off
No locking (threads may preempt at any time).
on
Full locking (no thread except the current thread may run).
step
The scheduler is locked during every single-step operation. In this mode, no other thread may run during a step command. However, other threads may run while stepping over a function call ('next').