GCC by itself only compiles the C or C++ code into assembler. Typically
GCC invokes all the passes required for you. These passes are cpp, cc1,
gas, ld. cpp
is the C preprocessor. This will merge in the
include files, expand all macros definitions, and process all the
#ifdef
sections. To see the output of ccp, invoke gcc with the
-E
option, and the preprocessed file will be printed on the
stdout. cc1 is the actual compiler pass that produces the assembler for
the processed file. GCC is actually only a driver program for all the
compiler passes. It will format command line options for the other passes.
The usual command line GCC uses for the final link phase will have LD
link in the startup code and additional libraries by default.
GNU AS started it’s life to only function as a compiler pass, but
these days it can also be used as a source level assembler. When used as
a source level assembler, it has a companion assembler preprocessor
called gasp
. This has a syntax similar to most other assembler
macros packages. GAS emits a relocatable object file from the assembler
source. The object file contains the executable part of the application,
and debug symbols.
LD is responsible for resolving the addresses and symbols to something
that will be fully self-contained. Some RTOS’s use relocatable object
file formats like a.out
, but more commonly the final image will
only use absolute addresses for symbols. This enables code to be burned
into PROMS as well. Although LD can produce an executable image, there
is usually a hidden object file called crt0.o
that is required as
startup code. With this startup code and a memory map, the executable
image will actually run on the target environment. Startup
Files.
The startup code usually defines a special symbol like _start
that is the default base address for the application, and the first
symbol in the executable image. If you plan to use any routines from the
standard C library, you’ll also need to implement the functions that
this library is dependent on. Porting Newlib.