Using GNU tools on embedded systems
Using GNU tools on embedded systems    
The following seven GNUPro Toolkit tools can be run on embedded targets.

Invoking the GNU tools
    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 main to 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 preprocessing. 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.
 

ld, the GNU linker

ld resolves 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
    .coff is the main object file format when using the tools on embedded target systems. For more information on object files and object file formats, see Using binutils in GNUPro Utilities.

binutils, the GNU binary utilities

The following are the binary utilities, although they are not included on all hosts: ar, nm, objcopy, objdump, ranlib, size, strings, and strip.
 
For more information on the GNU binary utilities, see Using binutils in GNUPro Utilities.

The most important of these utilities are objcopy and objdump.

gdb, the debugging tool

To run gdb on 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 libgloss with no newlib support. 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, newlib and libstd++.
      •  newlib
        • The Cygnus libraries, including the C library, libc, and the C math library, libm.

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.
 

See also I/O support code.
        The following is a typical basic initialization of crt0.S.
          #define CONCAT1(a, b) CONCAT2(a, b)
          #ifndef __USER_LABEL_PREFIX__
          #ifndef __REGISTER_PREFIX__
          .set stack_size, 0x2000 .
               .data
          .align 2
          SYM (start):
          moveal #__bss_start, a0
        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 argv as a pointer to NULL.
        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 handler just 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.

The linker script

The linker script accomplishes the following processes to result.
       
    • Sets up the memory map for the application.

    • 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.
       
    • For g++, sets up the constructor and destructor tables.

    • The actual section names vary depending on your object file format. For a.out and coff, the three main sections are .text, .data and .bss.
       
    • Sets the default values for variables used elsewhere.

    • These default variables are used by sbrk() and the crt0 file, typically called by _bss_start and _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 .
          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.
       
       
          SEARCH_DIR(.)
          __DYNAMIC = 0;
          MEMORY

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
         .talias : { } > 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_start and _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 data goes. The default values for _bss_start and _end are set here for use by the crt0 file when it zeros the .bss section.

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.
   

Memory support

The following routines are for dynamic memory allocation.

Miscellaneous support routines

The following support routines are called by newlib, although they don't apply to the embedded environment.
 
© 2005 Red Hat, Inc. All rights reserved.
About Red Hat  :  Legal statement  :  Privacy statement  :  Contact