Translation Tools
Preprocessors, Interpreters, Compilers, and Linkers
After the source code has been written, it needs to be translated into
machine code, since machine code is the only language the hardware can directly
execute. All other
languages need development tools that generate the
corresponding machine code the
hardware will understand. This mechanism
usually includes one or some combination of
interpretation
preprocessing, translation, and/or
machine code generation techniques.
These mechanisms are
implemented within a wide variety of translating development tools.
Preprocessing is an optional step that occurs either before the translation or
interpretation of source code, and whose functionality is commonly implemented by
a preprocessor.
The preprocessors role is to organize and restructure the source code to make
translation or interpretation of this code easier. The preprocessor can be a separate
entity, or can be
integrated within the translation or interpretation unit.
Many languages convert source code, either directly or after having been
preprocessed, to target code through the use of a
generates some target
compiler, a program which
language, such as machine code, Java byte code, etc., from
the source language, such as
assembly, C, Java, etc
A compiler typically translates all of the source code to a target code at one time.
As is usually the case in embedded systems, most compilers are located on the
programmers host machine and generate target code for hardware platforms that
differ from the platform the compiler is actually running on.
These compilers are commonly referred to as cross-compilers.
Some generate machine code while others generate other high-level languages,
which
then require what is produced to be run through at least one more
compiler.
Still other compilers generate assembly code, which must be run through an
assembler.
After all the compilation on the programmers host machine is completed, the
remaining target code file is commonly referred to as an object file depending
on the programming language used.
A linker integrates this object file with any other required system libraries,
creating
executable binary file, either directly onto the boards memory or
ready to be transferred to the target embedded systems memory by a loader.
One of the fundamental strengths of a translation process is based upon the
concept of software placement (referred to as object placement), the ability to divide
the software into modules and relocate these modules of code and data anywhere in
memory.
This is an especially useful feature in embedded systems, because:
Embedded designs can contain several different types of physical
memory
They typically have a limited amount of memory compared to
other types of computer systems
Memory
can
defragmentation
typically
become
very
fragmented
and
functionality is not available out-of-the-box
or too expensive
Certain types of embedded software may need to be executed from a particular
memory
location.
This software placement capability can be supported by the master processor, which
supplies specialized instructions that can be used to generate position independent
code, it could be separated by the software translation tools alone.
Where a compiler/assembler produces relocatable modules, process instruction
formats, and may do some translation of relative to physical (absolute)
addresses. An interpreter generates (interprets) machine code one source code
line at a time from source code or
target code generated by a intermediate
compiler on the host system
An embedded developer can make a big impact in terms of selecting translation
tools for a project by understanding how the compiler works and, if there are
options, by
selecting the strongest possible compiler.
This is because the compiler, in large part, determines the size of the executable
code by how well it translates the code. This not only means selecting a
compiler based on
support of the master processor, particular system
software, and the remaining toolset (a compiler can be acquired separately, as
part of a starter kit from a hardware vendor, andor integrated within an IDE). It
also means selecting a compiler based upon a feature set that optimizes the
codes simplicity, speed, and size.
Optimizing the code for performance means that the compiler understands and
makes
use of the various features of a particular ISA, such as math operations,
the register set, knowing the various types of on-chip ROM and RAM, the
number of clock cycles for
various types of accesses, etc. By understanding
how the compiler translates the code, a developer can recognize what support is
provided by the compiler and learn.