gcc invokes all the
required GNU passes for you with the following utilities.
cpp
The preprocessor which processes all the
header files and macros that your target requires.
gcc
The compiler which produces assembly language
code from the processed C files. For more information, see Using
GNU CC in GNUPro Compiler Tools.
gas
The assembler which produces binary code
from the assembly language code and puts it in an object file.
ld
The linker which binds the code to addresses,
links the startup file and libraries to the object file, and produces the
executable binary image.
There are several machine-independent compiler
switches, among which are, notably, -fno-exceptions
(for C++), -fritti (for C++) and -T (for linking).
You have four implicit file extensions:
.c , .C , .s , and .S. For more information,
see Using
GNU CC in GNUPro Compiler Tools.
gcc,
the GNU compiler
When you compile
C or C++ programs with gnu C, the compiler quietly inserts a call at the
beginning of mainto a gcc
support subroutine called __main . Normally this is invisible--you
may run into it if you want to avoid linking to the standard libraries,
by specifying the compiler option, -nostdlib.
Include -lgcc at the end of your compiler command line to resolve
this reference. This links with the compiler support library libgcc.a.
Putting it at the end of your command line ensures that you have a chance
to link first with any of your own special libraries.
__main is the initialization routine
for C++ constructors. Because GNU C is designed
to interoperate with GNU C++, even C programs must have this call: otherwise
C++ object files linked with a C main might
fail. For more information on gcc, see Using
GNU CC in GNUPro Compiler Tools.
cpp,
the GNU preprocessor
cpp merges in the #include
files, expands all macros definitions, and
processes the #ifdef sections. To see the output of cpp,
invoke gcc with the -E option,
and the preprocessed file will be printed on stdout.
There are two convenient options
to assemble handwritten files that require C-style prepro
ffb
cessing.
Both options depend on using the compiler driver program, gcc,
instead of calling the assembler directly.
Name the source file using the extension .S
(capitalized) rather than .s. gcc recognizes files with
this extension as assembly language requiring C-style preprocessing.
Specify the "source language" explicitly for
this situation, using the gcc option, -xassembler-with-cpp
.
For more information on cpp, see
The
C Preprocessor in GNUPro Compiler Tools.
gas,
the GNU assembler
gas can be used as either a compiler
pass or a source-level assembler.
When used as a source-level assembler,
it has a companion assembly language preprocessor called gasp.
gasp has a syntax similar to most other assembly language macro
packages.
gas emits a relocatable object
file from the assembly language source code.
The object file contains the binary code and the debug symbols.
For more information on gas,
see Using AS
in GNUPro Utilities.
ld,
the GNU linker
ldresolves
the code addresses and debug symbols, links the startup code and additional
libraries to the binary code, and produces an executable binary
image.
For more information on ld, see
Using LD
in GNUPro Utilities.
.coff
for object file formats
.coffis
the main object file format when using the
tools on embedded target systems. For more information on object files
and object file formats, see The
GNU Binary Utilities in GNUPro Utilities.
binutils,
the GNU binary utilities
The following are the binary utilities,
although they are not included on all hosts: ar, nm
ffb
,
objcopy, objdump, ranlib, size, strings,
and strip.
The most important of these
utilities are objcopyand
objdump.
objcopy
A few ROM monitors, such as a.out,
load executable binary images, and, consequently, most load an S-record.
An S-record is a printable ASCII representation of an executable binary
image.
S-records are suitable
both for building ROM images for standalone boards and for downloading
images to embedded systems. Use the following example's input for this
process.
objcopy -O srec
infileoutfile
infile
in the previous example's input is the executable binary filename, and
outfile is the filename for the S-record.
Most PROM burners
also read S-records or some similar format. Use the following example's
input to get a list of supported object file types for your architecture.
objdump -i
For more information
on S-records, see the discussions for FORMAT
output-formatin the documentation
for MRI
compatible script files and the discussion for BFD
in Using LD
in GNUPro Utilities . For more discussion of making an executable
binary image, see objcopy
in The
GNU Binary Utilities in GNUPro Utilities.
objdump
objdump displays information about one or more object files.
The options control what particular information to display. This information
is mostly useful to programmers who are working on the compilation tools,
as opposed to programmers who just want their program to compile and work.
When specifying
archives, objdump shows information on each of the member object
files. objfile... designates the object files to be examined.
A few of the more useful
options for commands are: -d, -disassembleand
--prefix-addresses.
-d
--disassemble
Displays
ffb
the assembler mnemonics for the machine instructions from
objfile . This option only disassembles those sections that are
expected to contain instructions.
--prefix-addresses
For disassembling, prints the complete address on each line, starting
each output line with the address it's disassembling. This is the older
disassembly format. Otherwise, you only get raw opcodes.
gdb,
the debugging tool
To run gdbon
an embedded execution target, use a gdb backend with the gdb
standard remote protocol or a similar protocol. The most common are the
following two types of gdb backend.
A gdb stub
This is an exception handler for breakpoints,
and it must be linked to your application. gdb stubs use the gdb
standard remote protocol.
An existing ROM monitor used as a gdb
backend
The most common approach means using the following processes.
With a similar protocol to the gdb
standard remote protocol.
With an interface that uses the ROM monitor
directly. With such an interface, gdb only formats and parses
commands.
For more information on debugging tools,
see Debugging
with GDB in GNUPro Debugging Tools.
Useful
debugging routines
The following routines are
always useful for debugging a project in progress.
print()
Runs standalone in libglosswith
no newlibsupport. Many times
print() works when there are problems that make printf()
cause an exception.
outbyte()
Used for low-level debugging.
putnum()
Prints out values in hex
so they are easier to read.
libgloss,
newlib and libstd++, the GNU libraries
GNUPro Toolkit has three libraries:
libgloss, newliband
libstd++.
libgloss
libgloss , the library for GNU Low-level OS Support
, contains the startup code, the I/O support for gcc and newlib
(the C library), and the target board support packages that you need to
port the GNU tools to an embedded execution target.
The C library used throughout this manual
is newlib , however libgloss could easily be made to
support other C libraries. Because libgloss resides in its own
tree, it's able to run standalone, allowing it to support GDB's remote
debugging and to be included in other GNU tools.
Several functions that are essential to
gcc reside in libgloss. These include the following functions.
The Cygnus libraries, including the C library,
libc, and the C math library,
libm.
libstd++
The C++ library in development by Cygnus
crt0,
the main startup file
The crt0 (C RunTime 0) file
contains the initial startup code.
Cygnus provides a crt0 file, although
you may want to write your own crt0 file for each target. The
crt0 file is usually written in assembler as 'crt0.S',
and its object gets linked in first and bootstraps the rest of your application.
The crt0 file defines a special symbol like _start,
which is both the default base address for the application and the first
symbol in the executable binary image.
If you plan to use any routines
from the standard C library, you'll also need to implement the functions
on which libgloss depends. The crt0 file accomplishes
the following results.
crt0
ffb
initializes everything in your program that needs it.
This initialization section varies. If you are developing
an application that gets downloaded to a ROM monitor, there is usually
no need for special initialization because the ROM monitor handles it for
you. If you plan to burn your code in a ROM, the crt0 file typically
does all of the hardware initialization required to run an application.
This can include things like initializing serial ports and running a memory
check; however, results vary depending on your hardware.
The following is a typical basic initialization
of crt0.S.
1. Set up concatenation macros.
#define CONCAT1(a, b) CONCAT2(a, b)
#define CONCAT2(a, b) a ## b
Later, you'll use these macros.
2. Set up label macros,
using the following example's input.
#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__ _
#endif
#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
These macros make the code portable between
coff and a.out. coff always has an __ (underline)
prepended to the front of its global symbol names.
a.out has none.
3. Set up register names
(with the right prefix), using the following
example's input.
#ifndef __REGISTER_PREFIX__
#define __REGISTER_PREFIX__
#endif
/* Use the right prefix for registers. */
#define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
#define d0 REG (d0)
#define d1 REG (d1)
#define d2 REG (d2)
#define d3 REG (d3)
#define d4 REG (d4)
#define d5 REG (d5)
#define d6 REG (d6)
#define d7 REG (d7)
#define a0 REG (a0)
#define a1 REG (a1)
#define a2 REG (a2)
#define a3 REG (a3)
#define a4 REG (a4)
#define a5 REG (a5)
#define a6 REG (a6)
#define fp REG (fp)
#define sp REG (sp)
Register names are for portability between
assemblers. Some register names have a % or $ prepended
to them.
4.&nbs
ffb
p;Set up space for the stack
and grab a chunk of memory.
.set stack_size, 0x2000 .
comm SYM (stack), stack_size
This can also be done in the linker script,
although it typically gets done at this point.
5. Define an empty space for
the environment, using the following example's input.
.data
.align 2
SYM (environ):
.long 0
This is bogus on almost any ROM monitor,
although it's best generally set up as a valid address, then passing the
address to main(). This way,
if an application checks for an empty environment, it finds one.
6. Set up a few global symbols
that get used elsewhere.
.align 2
.text
.global SYM (stack)
.global SYM (main)
.global SYM (exit)
.global __bss_start
This really should be __bss_start,
not SYM (__bss_start.
__bss_start needs to be declared
this way because its value is set in the linker script.
7. Set up the global symbol,
start, for the linker to use
as the default address for the .text section. This helps your
program run.
SYM (start):
link a6, #-8
moveal #SYM (stack) + stack_size, sp
crt0zeroes the .bsssection
Make sure the .bss
section is cleared for uninitialized data, using the following example's
input. All of the addresses in the .bss section need to be initialized
to zero so programs that forget to check new variables' default values
will get predictable results.
moveal #__bss_start, a0
moveal #SYM (end), a1
1:
movel #0, (a0)
leal 4(a0), a0
cmpal a0, a1
bne 1b
Applications can get wild side effects
from the .bss section being l
ffb
eft uncleared, and it can cause particular
problems with some implementations of malloc() .
crt0calls main()
If your ROM monitor supports
it, set up argc and argv for command line arguments and
an environment pointer before the call to main(), using the following
example's input.
For g++, the code generator inserts
a branch to __main at the top of your main() routine.
g++ uses __main to initialize its internal tables and
then returns control to your main() routine.
For crt0 to call your main()
routine, use the following example's input. First, set up the environment
pointer and jump to main(). Call the main routine from the application
to get it going, using the following example's input with main (argc,
argv, environ), using argvas
a pointer to NULL.
pea 0
pea SYM (environ)
pea sp@(4)
pea 0
jsr SYM (main)
movel d0, sp@-4
crt0calls (exit)
After main()
has run, the crt0 file cleans things up and returns control of
the hardware from the application. On some hardware there is nothing to
return to--especially if your program is in ROM--and if that's the case,
you need to do a hardware reset or branch back to the original start address.
If you're using a ROM monitor,
you can usually call a user trap to make the ROM take over. Pick a safe
vector with no sides effects. Some ROM's have a built-in trap handlerjust
for this case.
Implementing (exit) here is easy.
First, with _exit, exit from the application. Normally, this causes
a user trap to return to the ROM monitor for another run. Then, using the
following example's input, you proceed with the call.
SYM (exit):
trap #0
Both rom68kand
bugcan handle a user-caused
exception of 0 with no side effects. Although the bug
monitor has a user-caused trap that returns control to the ROM monitor,
the bug monitor is more portable.
The linker
script
The linker script
accomplishes the following processes to result.
When your application is loaded into memory,
it allocates some RAM, some disk space for I/O, and some registers. The
linker script makes a memory map of this memory allocation which is important
to embedded systems because, having no OS, you have the ability then to
manage the behavior of the chip.
The actual section names
vary depending on your object file format. For a.out and coff,
the three main sections are .text,
.dataand .bss.
Sets the default values for variables
used elsewhere.
These default variables are used by sbrk()and
the crt0 file, typically called by
_bss_startand _end.
Memory map
There are two ways to
ensure the memory map is correct.
By having the linker create the memory map
by using the option, -Map.
By, after linking, using the nm utility
to check critical addresses like start, bss_end and _etext.
The following is an example of a linker
script for an m68k-based target board.
1. Use the STARTUP
command, which loads the file so that it executes
first.
STARTUP(crt0.o)
The m68k-coff configuration
default does not link in crt0.o because it assumes that a developer
has crt0. This behavior is controlled in the config file
for each architecture in a macro called STARTFILE_SPEC.
If STARTFILE_SPEC is set to NULL, gcc formats its command
line and doesn't add crt0.o. Any filename can be specified with
STARTUP, although the default is always crt0.o .
If you use only
ld to link, you control whether or not to link in crt0.o
on the command line.
If you have multiple
crt0 files, you can leave STARTUP
ffb
out, and link in crt0.o in the makefile or use different linker
scripts. Sometimes this option is used to initialize floating point values
or to add device support.
2. Using GROUP,
load the specified file.
GROUP(-lgcc-liop-lc)
In this case, the file is a relocated library
that contains the definitions for the low-level functions needed by libc.a
. The file to load could have also been specified on the command line,
but as it's always needed, it might as well be here as a default.
3. SEARCH_DIRspecifies
the path in which to look for files.
SEARCH_DIR(.)
4. Using _DYNAMIC,
specify whether or not there are shared dynamic libraries.
In the following example's case, there are no shared libraries.
__DYNAMIC = 0;
5. Set _stack, the variable
for specifying RAM for the ROM monitor.
6. Specify a name for a section
that can be referred to later in the script. In the following example's
case, it's only a pointer to the beginning of free RAM space
with an upper limit at 2M. If the output file exceeds the upper limit,
MEMORYproduces an error message.
First, in this case, we'll set up the memory map of the board's stack for
high memory for both the rom68k and mon68k monitors.
MEMORY
{
ram : ORIGIN = 0x10000, LENGTH = 2M
}
Constructor
and destructor tables for g++
The following discusses setting up
constructor and destructor tables for g++.
Set up the .text
section, using the following example's input.
SECTIONS
{
.text :
{
CREATE_OBJECT_SYMBOLS
*(.text)
etext = .;
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
ffb
PRE>
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;
*(.lit)
*(.shdata) }
> ram
.shbss SIZEOF(.text) + ADDR(.text) : {
*(.shbss)
}
In a coff
file, all the actual instructions reside in .text for also setting
up the constructor and destructor tables for g++. Notice that
the section description redirects itself to the RAM variable
that was set up in Step 5 of the earlier process for the crt0
file, Set stack, the
variable for specifying RAM for the ROM monitor.
Set up the .datasection.
.talias : { } > ram
.data : {
*(.data)
CONSTRUCTORS
_edata = .;
} > ram
In a coff
file, this is where all of the initialized data goes. CONSTRUCTORS
is a special command used by ld.
Default
values for variables, _bss_startand _end
The following documentation discusses setting
default values for variables, _bss_start and _end
Set up the .bss
section, using the following example code.
In a coff file,
this is where uninitialized datagoes.
The default values for _bss_start and _end are set here
for use by the crt0 file when it zeros the .bss section.
.bss SIZEOF(.data) + ADDR(.data) :
{
__bss_start = ALIGN(0x8);
*(.bss)
*(COMMON)
end = ALIGN(0x8);
_end = ALIGN(0x8);
__end = ALIGN(0x8);
}
.mstack : { } > ram
.rstack : { } > ram
.stab . (NOLOAD) :
{
[ .stab ]
}
.stabstr . (NOLOAD) :
{
[ .stabstr ]
}
}
ffb
I/O support
code
Most applications use calls
to the standard C library. However, when you initially link libc.a,
several I/O functions are undefined. If you
don't plan on doing any I/O, you're OK; otherwise, you need to create two
I/O functions: open() and close(). These don't need to
be fully supported unless you have a file system, so they are normally
stubbed out, using kill().
sbrk()is
also a stub, since you can't do process control
on an embedded system, and it is only needed by applications that do dynamic
memory allocation. It uses the variable, _end,
which is set in the linker script.
The following routines are
also used for optimization.
-inbyte
Returns a single byte from
the console.
-outbyte
Used for low-level debugging,
takes an argument for print() and prints a byte out to the console
(typically used for ASCII text).
Memory support
The following routines are
for dynamic memory allocation.
sbrk()
The functions, malloc(), calloc(), and
realloc() all call sbrk() at their lowest levels. sbrk()
returns a pointer to the last memory address your application used before
more memory was allocated.
caddr_t
Defined elsewhere as char *.
RAMSIZE
A compile-time option that moves a pointer to heap memory and checks
for the upper limit.
Miscellaneous
support routines
The following support routines
are called by newlib, although they don't apply to the embedded
environment.
isatty()
Checks for a terminal device.
kill()
Simply exits.
getpd()
Can safely return any value
greater than
c3
1, although the value doesn't effect anything in newlib.