LSP RM
LSP RM
Xtensa®
Linker Support Packages (LSPs)
Reference Manual
This publication is provided “AS IS.” Cadence Design Systems, Inc. (hereafter “Cadence") does not make any warranty of any
kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a partic-
ular purpose. Information in this document is provided solely to enable system and software developers to use our processors.
Unless specifically set forth herein, there are no express or implied patent, copyright or any other intellectual property rights or
licenses granted hereunder to design or fabricate Cadence integrated circuits or integrated circuits based on the information in
this document. Cadence does not warrant that the contents of this publication, whether individually or as one or more groups,
meets your requirements or that the publication is error-free. This publication could include technical inaccuracies or typo-
graphical errors. Changes may be made to the information herein, and these changes may be incorporated in new editions of
this publication.
© 2019 Cadence, the Cadence logo, Allegro, Assura, Broadband Spice, CDNLIVE!, Celtic, Chipestimate.com, Conformal,
Connections, Denali, Diva, Dracula, Encounter, Flashpoint, FLIX, First Encounter, Incisive, Incyte, InstallScape, NanoRoute,
NC-Verilog, OrCAD, OSKit, Palladium, PowerForward, PowerSI, PSpice, Purespec, Puresuite, Quickcycles, SignalStorm, Sig-
rity, SKILL, SoC Encounter, SourceLink, Spectre, Specman, Specman-Elite, SpeedBridge, Stars & Strikes, Tensilica, Triple-
Check, TurboXim, Vectra, Virtuoso, VoltageStorm, Xcelium, Xplorer, Xtensa, and Xtreme are either trademarks or registered
trademarks of Cadence Design Systems, Inc. in the United States and/or other jurisdictions.
OSCI, SystemC, Open SystemC, Open SystemC Initiative, and SystemC Initiative are registered trademarks of Open Sys-
temC Initiative, Inc. in the United States and other countries and are used with permission.
RI-2019.1
Contents
List of Figures
List of Tables
Preface
Notation
italic_name indicates a program or file name, document title, or term being defined.
$ represents your shell prompt, in user-session examples.
literal_input indicates literal command-line input.
variable indicates a user parameter.
literal_keyword (in text paragraphs) indicates a literal command keyword.
literal_output indicates literal program output.
... output ... indicates unspecified program output.
[optional-variable] indicates an optional parameter.
[variable] indicates a parameter within literal square-braces.
{variable} indicates a parameter within literal curly-braces.
(variable) indicates a parameter within literal parentheses.
| means OR.
(var1 | var2) indicates a required choice between one of multiple parameters.
[var1 | var2] indicates an optional choice between one of multiple parameters.
var1 [, varn]* indicates a list of 1 or more parameters (0 or more repetitions).
4'b0010 is a 4-bit value specified in binary.
12'o7016 is a 12-bit value specified in octal.
10'd4839 is a 10-bit value specified in decimal.
32'hff2a or 32'HFF2A is a 32-bit value specified in hexadecimal.
Terms
0x at the beginning of a value indicates a hexadecimal value.
b means bit.
B means byte.
flush is deprecated due to potential ambiguity (it may mean write-back or discard).
Mb means megabit.
MB means megabyte.
PC means program counter.
word means 4 bytes.
The following changes (denoted by change bars) were made for the RI-2019.1 release:
Updated Section 2.4.1, Section 2.4.5, and Section 2.8.3 to describe new 'uncached'
attribute.
Updated Table 1–1 and Section 1.3.4 to describe new min-rt-stacklocal LSP.
Removed select board-specific libraries in Section 1.1.1.
Updated board-specific library in Section 1.1.4.
Improved description of special code and data sections in Chapter 2.
Added a note in Section 2.4.3 emphasizing that in the case of multiple uses of the
same parameter, the last use has precedence.
Added a note in Section 2.6 that the ':' syntax must be used (instead of multiple RE-
SERVE_SEGMENT_AREA parameters) to handle multiple segments.
A linker support package (LSP) specifies object files to pull into an executable using a
specific memory map, and is used as a convenient short-hand for telling the linker what
it needs for a particular target environment. Thus, an LSP ties together components that
may need to be adapted as an Xtensa processor is used in different systems, including
various portions of the Xtensa software development kit. This document describes how
to use and customize LSPs and related components.
Note: All command-line examples in this document assume that Xtensa Tools are in-
stalled and readily available; that is, with <xtensa_tools_root>/bin in the user's
PATH. They also assume that an Xtensa core package (processor configuration) has
been successfully built, downloaded, and installed in a directory referred to here as
<xtensa_root>.
Note: Throughout this guide, there are many references to Xtensa that refer generally to
any Xtensa processor that implements the Xtensa instruction set architecture.
1. For those familiar with GCC specs files, note that the XCC driver (xt-xcc) only implements a subset of the specs file features supported by
the GNU C compiler driver. Specifying anything other than object files and libraries in specs files used by XCC may result in undefined behavior.
Each LSP pulls in object files and libraries according to their specific requirements.
Figure 1–1 shows some of the elements commonly used with LSPs.
_start main
C Runtime
Initialization
crt1*.o
SIMCALL BREAK
instruction instruction
KC705
ISS GDB
board h/w
Certain LSPs combine the above to provide a complete single-threaded C runtime. This
runtime is not for use in production systems without modification and validation.
In many instances, you can override library objects specified in the specs file by speci-
fying on the link line an object(s) that defines the appropriate symbols. See also
Section 2.8.8 on page 54 for an alternative method involving the linker search path.
For details about vectors, handlers, the basic runtime (XTOS), and the processor config-
uration description (HAL), refer to the Xtensa System Software Reference Manual.
The compiler driver and linker search for files based on the location of the LSP directory.
Standard LSP directories are:
<xtensa_root>/xtensa-elf/lib/<lsp>/
where <xtensa_root> is the base of the installed Xtensa core package, and <lsp> is
the name of a standard LSP. Custom LSP directories may be located anywhere.
Note that xcc is not a standard LSP. It is a directory that contains XCC-specific objects
and libraries (see below).
The compiler driver uses the specs file in the LSP directory to invoke the linker. The
linker itself does not use the specs file. The linker uses the linker scripts in the ld-
scripts subdirectory of the LSP directory.
The linker also looks for object files and libraries in specific directories. Libraries speci-
fied using the -l option (e.g., -lhal which specifies the libhal.a library file) are
searched in the library search path, in the following directories and in this order:
<libpath>
<lspDir>
<xtensa_root>/xtensa-elf/lib/xcc/ (searched by the compiler only)
<xtensa_root>/xtensa-elf/arch/lib/ (independent of C library)
<xtensa_root>/xtensa-elf/lib/ (compiled using C library headers)
where <lspDir> is the LSP directory, and <libpath> is the list of search directories
specified on the compiler driver or linker command-line using the -L <libdir> flag.
For object files and libraries specified in the specs file by explicit filename without a full
pathname (such as object.o or libhal.a), the linker searches the library search
path above, then the current directory. When such filenames are specified on the com-
mand line, they are searched in the current directory only.
To examine the expanded contents of an LSP specs file as well as the exact library
search path, you can use the compiler driver’s --print-lsp option. For example:
An executable image containing C or C++ code generally begins at the reset vector (or
in some cases a stand-in, such as crt0-app.o) which initializes the processor. It then
passes control to _start, which is a routine contained in crt (C and C++ runtime li-
brary startup) that initializes certain special registers, sets up a stack for the program,
and clears the bss section(s). It then calls __clibrary_init, a C library specific ini-
tialization routine (specific to newlib or xclib) that performs any other initialization re-
quired by the program such as calling C++ constructors and registering C++ destructors
and other finalization code. Once initialization of the program is complete, the code initi-
ates execution of the program by calling the main function. It then typically calls exit
with main’s return value.
Note: Certain LSPs omit or simplify these steps. See Section 1.3.10.
Each target may have a specific version of crt. For example, an LSP used for emula-
tion boards uses a different version of crt than an LSP used for the instruction set sim-
ulator (ISS). For example, the ISS crt obtains and passes xt-run command line argu-
ments to the main function, whereas a typical crt designed for a board simply passes
an empty argument list.
A related target-specific function is the _exit routine, which is called by exit after the
program completes its execution. The code contained in the _exit routine terminates
the execution of the program in a target specific manner. The simulator-specific _exit
routine, for example, terminates the simulation; it is contained in the libsim library. The
_exit routine for boards is located in the libhandlers-boards library.
See Section 4.1 on page 65 for an example that modifies the C runtime initialization.
The GNU Low-level Operating System Support (GLOSS), or libgloss library, provides
low-level support for the C library (libc) when an application runs without the support
of operating system (OS) services.
The routines provided in this library include reentrant stubs and wrappers for file and
other operations such as _open_r, _close_r, _read_r, _write_r, _fstat_r,
_stat_r, _lseek_r, _getpid_r, _kill_r, and a non-reentrant version of _sbrk_r
(see the Red Hat newlib C Library Reference Manual for more details). Because the rou-
tines provided in the library assume a minimal environment, many of them simply return
an appropriate error code. Even in a minimal environment, I/O through the standard
read and write routines, and, consequently, through higher-level C functions such as
scanf and printf, is very important to an application. For this reason, libgloss pro-
vides everything necessary to support character I/O except for target-specific functions,
namely inbyte and outbyte. These target-specific character input and output rou-
tines are provided by the board-specific libraries (e.g., libxtkc705.a for the KC705
emulation board).
Interrupt and exception handlers can run when the underlying application (or lower-pri-
ority handler) is in the middle of executing a given function. If a handler calls that func-
tion, it can cause the function to be re-entered. For correctness, interrupt and exception
handlers must only call functions that allow such use, i.e., reentrant functions.
Functions are reentrant if they don’t use resources that might become shared concur-
rently when re-entered, including, for example, writable global variables.
Many C library functions are reentrant, such as the self-contained memcpy and strcmp.
Many other C library functions are not, such as strtok (which maintains state between
calls), and malloc (which typically accesses a shared heap).
newlib C Library
The newlib C library documents reentrancy in the Reentrancy chapter of the Red Hat
newlib C Library Reference Manual, which lists C library functions that have both a reen-
trant and a standard name. Many of these functions can be made reentrant by following
the instructions in that chapter. However, some of these functions are non-reentrant,
causing all their callers to be non-reentrant as well. For example, _sbrk_r (and thus in-
directly malloc) accesses a shared heap, and setenv accesses a shared environment
array, making them non-reentrant.
Arrange for the _impure_ptr global pointer variable to point to the current thread’s
struct _reent structure. This generally involves explicitly context-switching the
value of this global pointer in the thread context-switching code.
Upon thread termination, call the following (undocumented) function for cleanup
(e.g., call _atexit routines):
void _wrapup_reent(struct _reent *ptr);
Upon thread deletion, call the following (undocumented) function to free memory ref-
erenced by the re-entrancy structure:
void _reclaim_reent(struct _reent *ptr);
Before calling either of the above two functions, some RTOS execute the following,
purportedly to avoid closing stdin, stdout, and stderr, so that other threads can
continue using them:
int i; for (i = 0; i < 3; i++) ptr->__sf[i]._close = NULL;
Provide custom implementations of the following newlib lock routines, documented
in the Red Hat newlib C Library Reference Manual. The default implementation of
these functions does nothing. By explicitly linking in one’s own versions, the linker
doesn’t pull in these routines from the C library.
void __malloc_lock (struct _reent *reent);
void __malloc_unlock (struct _reent *reent);
void __env_lock (struct _reent *reent);
void __env_unlock (struct _reent *reent);
Typical implementations of these routines acquire (lock) and release (unlock) a glob-
al mutex semaphore initialized at startup. In some environments, where the C library
can be invoked before the multi-threading environment is fully initialized, these rou-
tines must be careful to simply return if invoked before this initialization is complete.
Optionally, for operating systems that manage the heap themselves, provide a cus-
tom version of _sbrk_r() to coordinate with the operating system’s allocator.
Note: The C library protects calls to _sbrk_r() with calls to __malloc_lock(),
so with a proper implementation of the latter, _sbrk_r() itself need not be re-en-
trant (unless it gets called directly, i.e. outside newlib’s malloc, which is not recom-
mended when using newlib’s malloc).
Note that in newlib, the exit() function is meant to be called at program termination,
not at termination of each thread. The global re-entrancy structure (pointed to by
_global_impure_ptr, and initially pointed to by _impure_ptr at startup) tracks exit
routines to be invoked at global program termination.
Note that the newlib C library was not tested by Cadence to be thread-safe.
Users are responsible for verifying any use of the C library that requires thread-safety.
xclib C Library
The xclib C library supports thread safety when used with the appropriate user-sup-
plied overrides and data structures. The hooks provided for this purpose are briefly de-
scribed here. Refer to the library HTML documentation for more details.
Note that thread safety does not mean per-thread state for everything. In particular, the
file handle table is shared across all threads, so files can be accessed by multiple
threads. The file access functions are protected by locks, and the locking functions must
be provided by the user implementation as described below. The locale information is
also not thread-specific; only one copy of locale data is maintained for all threads. The
heap is also shared among all threads, although the heap access functions are protect-
ed by locking.
Due to their asynchronous nature, interrupt and exception handlers behave essentially
as independent threads of execution. The default single-threaded runtime (XTOS) does
not allocate or manage reentrancy structures for handlers. Handlers written for XTOS
(and most other runtimes and kernels) must avoid calling, directly or indirectly, the C li-
brary functions that are known to be non-reentrant. Many of these functions can be
called by allocating and managing the reentrancy structure explicitly for each handler in-
stance; this does not include any function that is inherently non-reentrant or involves any
sort of locking (such as malloc which calls _sbrk_r).
To select a specific LSP when invoking the compiler driver to link the application, add
the –mlsp=<lsp> option, where <lsp> is the name of a standard LSP or the path to a
directory containing a custom LSP. Following is an example that selects a standard LSP
named rtos-rom.
When invoking the linker directly, use the –-multilib-dir=<lsp> option instead. For
example:
In either case, if the <lsp> parameter does not contain any directory separator, it is in-
terpreted as the name of a standard LSP (see Section 1.3), i.e. as the name of a directo-
ry under the standard location for LSPs: <xtensa_root>/xtensa-elf/lib. In Unix,
the directory separator is a forward slash (/); in Windows, both forward and backward
slashes are accepted (/ or \). If the <lsp> parameter does contain a directory separa-
tor, it is interpreted as the pathname to an LSP directory relative to the current directory,
or as an absolute pathname if it is rooted. This allows you to refer to a custom LSP cre-
ated outside the standard location. Following is an example that selects an LSP created
in directory mylsp in the current directory.
Standard LSPs listed in Table 1–1 on page 10 are always present regardless of proces-
sor configuration. However, a number of LSPs have specific requirements to be func-
tional. If an LSP’s requirements are not met, its linker scripts contain assertions that
cause any attempt to link using that LSP to fail with an informative error message.
These requirements are described for each relevant LSP in the subsections that follow.
For example, rtos-res and various *-rom LSPs require a read-only memory in the
memory map.
Table 1–1 outlines the various linker support packages and provides a short description
of each. The subsections following the table elaborate on each LSP.
The gdbio LSP is used to build an application to be executed on a target controlled us-
ing an Xtensa debugger and the Xtensa OCD Daemon. It interacts with the debugger to
route all file and console I/O, as well as a few other system calls, to the host running the
debugger. The C library’s standard input and output go to the debugger’s console.
The gdbio LSP implements this feature using a special breakpoint instruction reserved
for this purpose: break 1,14. This breakpoint is a request for services from the host.
Details of the request are specified in registers just prior to executing the breakpoint, ac-
cording to some convention. The Xtensa OCD Daemon detects this special breakpoint
instruction and translates it into a remote file I/O request to GDB. See the Xtensa Debug
Guide for details on the Xtensa OCD Daemon.
If the application is run on the Xtensa ISS simulator, the I/O functions automatically de-
tect the presence of the simulator and switch to using the simulator’s hosted I/O capabil-
ities.
This LSP automatically links into the application the vectors, exception handlers, and
runtime routines necessary for the execution of a simple single-threaded application.
The gdbio-local LSP is identical to the gdbio LSP, except that if the processor is
configured with local memories, the application’s code is put in the first local instruction
RAM (iram0) and its data is put in the first local data RAM (dataram0).
The gdbio-stacklocal LSP is identical to the gdbio LSP, except that the applica-
tion’s stack (but not other data) is put in the first local data RAM, if a data RAM is config-
ured. Otherwise, the gdbio-stacklocal LSP does not work.
Sources for the libgdbio.a library are located in the following directory:
<xtensa_tools_root>/xtensa-elf/src/libgdbio
1.3.2 LDAPP
The ldapp LSP is similar to the nort LSP, but is customized for the Xtensa verification
test bench. The ldapp LSP is used to build the diagnostics so that they can be execut-
ed on the Xtensa verification test bench. Because of its customization, changes to this
LSP may prevent the diagnostics from executing on the test bench.
For example, the default memory map of the ldapp LSP may define a few system mem-
ories created for the purpose of running diagnostics. They are not intended for any other
use. Such memories might be named, for example: cached, noncached, or dynamic,
among other possible names. These memories are created automatically by the Xtensa
Processor Generator (XPG). Modifying them, as well as any other modification of the
ldapp LSP memory map, may prevent diagnostics from executing properly.
1.3.3 LINUX
The linux LSP is used to build Linux user applications using Xtensa Tools. Linux user
applications may also be built using versions of GCC built specifically for Linux.
Here, Linux refers to Linux running on an Xtensa processor configured with an MMU.
Notes:
The linux LSP is custom-built, and therefore cannot be generated using the tools
described in Chapter 2.
Refer to the Xtensa OSKit Guide for more details on Linux for Xtensa processors.
The min-rt LSP contains minimal run-time support. It is used to build an application to
be executed on almost any system or simulation (as long as obvious constraints, such
as sufficient available memory, are satisfied). To this end, this LSP does not provide any
board-specific support such as character I/O, nor make use of any simulator-specific
support such as SIMCALL instructions. The min-rt LSP can be used for RTL simula-
tion, for example, or as a starting point to develop a custom LSP for a specific system or
board.
The min-rt LSP automatically links into the application the vectors, exception han-
dlers, and runtime routines necessary for the execution of the application. The C library
can be used. However, standard output goes to a small circular array in memory, and
standard input always returns EOF. This behavior is implemented in the libminrt.a li-
brary, built from a small C source file:
<xtensa_tools_root>/xtensa-elf/src/boards/mingloss.c
The min-rt-local LSP is identical to the min-rt LSP, except that the application’s
code is put in the first local instruction RAM and its data is put in the first local data RAM.
The min-rt-local LSP only works on processors configured with local memories.
The min-rt-stacklocal LSP is identical to the min-rt LSP, except that the applica-
tion’s stack (but not other data) is put in the first local data RAM, if a data RAM is config-
ured. Otherwise, the min-rt-stacklocal LSP does not work.
For minimal memory footprint at the cost of somewhat reduced functionality, see the
tiny LSP described in Section 1.3.10 on page 16.
To be functional, these LSPs require a read-only memory in the memory map. If no read-
only memory was specified in the Xtensa Processor Generator, these LSPs are present
but cause any attempt to link using them to fail with an informative error message. You
can customize the LSP to add a read-only memory. See Chapter 2 for details.
1.3.6 NORT
The nort LSP is used to build an application with user-supplied vectors, exception han-
dlers, and runtime routines. Unlike LSPs such as sim and xtav60-rt, the nort LSP
does not automatically link into the application any vectors, exception handlers, or run-
time routines. The user must explicitly provide them when building the application.
Example code for these components can be found in the Xtensa Tools directory under
<xtensa_tools_root>/xtensa-elf/src. Example vectors and exception handlers
for XTOS are in the xtos subdirectory. Example startup code is in crt1-*.S in the
same subdirectory. Example runtime routines can be found in the newlib/libgloss,
boards, and sim subdirectories.
Besides the addition of the –mlsp=nort flag, the compilation command line must in-
clude user-supplied vectors and handlers, as in the following example:
The files myvectors.S, myhandlers.S, and myruntime.c contain the vectors, ex-
ception handlers and runtime routines required by the application.
The piload and pisplitload LSPs are used to build position-independent libraries
for loading with the Library Loader tool-flow as described in the Xtensa System Software
Reference Manual.
Notes:
The piload and pisplitload LSPs cannot be generated using the tools de-
scribed in Chapter 2.
The rtos LSPs are typically used for various Real Time Operating Systems (RTOS).
However, they are also useful for other system software and applications that provide or
specify their own exception vectors, libraries, and startup code.
These LSPs contain empty specs files. Hence they do not provide any default vectors,
libraries, or crt type startup code. These are assumed to be OS specific, and must be
specified on the linker command line (or to the compiler driver, xt-xcc).
Whereas most LSPs are tied to a specific system or board, the rtos LSPs are intended
to be more generic; that is, to avoid most dependencies on system parameters (features
outside the Xtensa processor). At this time, the rtos LSPs still contain a system param-
eter: system RAM and ROM addresses as specified in the Xtensa Processor Generator.
Hence you must customize the relevant LSP if you move system RAM or ROM outside
their initial location (see Chapter 2).
To be functional, the rtos-res and rtos-rom LSPs require a read-only memory in the
memory map. If no read-only memory was specified in the Xtensa Processor Generator,
these LSPs are present but cause any attempt to link using them to fail with an informa-
tive error message. You can customize the LSP to add a read-only memory. See
Chapter 2 for details.
For details on specific supported RTOS, refer to the Xtensa OSKit Guide.
The sim LSP is used to build an application to be executed on the instruction set simu-
lator (ISS). This LSP automatically links into the application the vectors, exception han-
dlers, and runtime routines necessary for the execution of the application on the ISS.
The sim LSP is typically used during application development before any of the final
vectors, exception handlers, and runtime routines are available.
The sim-local LSP is identical to the sim LSP, except that if the processor is config-
ured with local memories, the application’s code is put in the first local instruction RAM
(iram0) and its data is put in the first local data RAM (dataram0).
The sim-stacklocal LSP is identical to the sim LSP, except that the application’s
stack (but not other data) is put in the first local data RAM, if a data RAM is configured.
Otherwise, the sim-stacklocal LSP displays an error at link time.
The sim LSP is the default used by Xtensa Tools when no LSP is specified.
1.3.10 TINY
The tiny LSP offers a reduced memory footprint at the cost of reduced functionality rel-
ative to other LSPs such as min-rt. Like min-rt, the tiny LSP automatically links
into the application the vectors, exception handlers, and runtime routines necessary for
a main program written in C or assembler. However, it has the following limitations:
Does not support multiple *.bss sections (see Section 2.5 on page 37). Startup
code only clears the .bss section, not any other *.bss sections.
Does not call C++ static constructors and destructors, or any other code that might
have been placed inside .init or .fini sections.
Does not set __progname or __environ.
Calls main() with no arguments, not even empty ones.
Does not expect main() to return. If it does, it loops forever without calling exit().
Ignores any output (for example, to stdout or stderr), and always returns EOF
on input.
Does not dispatch interrupts of a given priority level unless the application calls its
specific initialization routine _xtos_dispatch_level<N>_interrupts(),
where <N> is the priority level. This mechanism allows linking in only the dispatch
code and data required. Otherwise, _xtos_set_interrupt_handler() cannot
distinguish between these levels at link-time and would have to link them all in. In
particular, each high-priority level interrupt dispatch involves a default stack of about
1 kB.
The above restrictions allow the tiny LSP runtime to avoid referencing C library func-
tions that significantly increase code and data size. Maintaining a small memory foot-
print requires being very selective about which C library functions to call. In other words,
the application writer must be very careful about invoking library functions, otherwise all
advantages of the tiny LSP can be easily lost. For example, most string routines such
as memcpy() and strcmp() are standalone and don’t pull-in other code. On the other
hand, when using newlib, calling directly or indirectly any of the C library functions that
require special reentrancy support such as open(), write(), strtok(), and many
others, pulls in the associated re-entrancy data structure of approximately 1 kB (see
also the Reentrancy chapter of the Red Hat newlib C Library Reference Manual). Also,
the printf() family of functions are typically quite large. One of the most reliable ways
to evaluate the size impact of any particular function is to try calling it and examine the
resulting code and data size (e.g. using xt-size -C <elffile>).
Unlike other LSPs, the tiny LSP relies on very careful ordering of object files and librar-
ies within the specs file for linking to occur correctly and optimally. This technique pro-
vides the following automatic optimizations:
The handler for the syscall exception is omitted if -lnosyscall is provided on
the link line. If the application is known to not use theSYSCALL instruction, this fur-
ther reduces the code size; otherwise, omitting this handler may result in unhandled
exceptions. The SYSCALL instruction may be used to spill register windows to the
stack for C++ exception handling, for setjmp(), and for similar functions. Deter-
mining whether this instruction is present may require disassembling the entire
linked executable (e.g. using xt-objdump -d <elffile>).
If the xtos_set_exception_handler() is not called, the C exception handler
dispatch code is omitted, and an alternate smaller user exception vector is used.
If there is no user exception to be handled, the user exception vector is replaced
with a stub vector. That is, if you provide -lnosyscall on the link line, and call nei-
ther xtos_set_exception_handler() nor _xtos_dispatch_level<N>_in-
terrupts(), you save a few extra bytes.
The tiny LSP can be used to build an application to be executed on almost any system
or simulation. It does not provide any board-specific support such as character I/O, nor
make use of any simulator-specific support such as SIMCALL instructions. The tiny
LSP can be used for RTL simulation, for example, or as a starting point to develop a
custom LSP for a specific system or board.
The stubbed console I/O hooks are implemented in the libtinyrt.a library, built from
a small C source file:
<xtensa_tools_root>/xtensa-elf/src/boards/tinygloss.c
The sim-mc LSP is used to build an XTOS based multi-core application to be executed
on the simulator. This LSP automatically links into the application vectors, exception
handlers, and runtime routines necessary for the execution of the application on the sim-
ulator. It also places various data and BSS sections appropriately. This LSP is typically
used during application development and as a basis for creating a custom LSP to sup-
port the actual multi-core system.
The sim-mc-stacklocal LSP is identical to the sim-mc LSP, except that the applica-
tion’s stack (but not other data) is put in local data RAM, if a data RAM is configured.
Otherwise, the LSP displays an error at link time.
Both LSPs require the presence of at least one local data RAM. They use the standard
PLACE SECTION directive to relocate the program sections. They also use a custom
parameter "NO_MERGE_BSS=true" to disable automatic merging of adjacent BSS sec-
tions. This parameter is only to be used in this context (i.e., in LSPs derived from either
of these two and intended for multi-core applications).
It is important to note that neither LSP creates an uncached shared memory region for
placement of lock variables and global C library data. If this is required for your multi-
core application, copy one of the LSPs and modify it to create the uncached region.
For more information on how to build and run an XTOS-based multi-core application,
see the Xtensa System Software Reference Manual.
Once the core package is downloaded and installed, you may decide to change the sys-
tem memory map to better match the development environment. For example, you can
add new system memories or change the size of existing ones, change the location to
which program code and data are loaded, or relocate the stack and heap.
Bear in mind that certain changes to the memory map are only possible by modifying the
processor hardware. This generally involves configuring a new processor using the
Xtensa Processor Generator. Such changes include adding, removing or moving1 ex-
ception vectors or local memories (instruction or data RAM or ROM, or the Xtensa Local
Memory Interface, XLMI).
In both cases, older syntax is also accepted for backward compatibility. Starting with the
RB-2007.2 release, any such syntax not matching that which is described here causes a
warning to be displayed. See previous releases of this document for details.
Table 2–2 and Table 2–3 describe the options specific to each utility. Table 2–4 de-
scribes the options common to both.
1. It is possible, however, to relocate vectors on a processor configured with relocatable vectors. See the -mvecbase,-mvecselect, and
-mvecreset options.
board devices.
MEMORY MAXSIZE is too small to contain certain exception or interrupt vectors.
Specifies the run-time location of dynamic vectors. That is, the value of the VECBASE
register. This option only works for processors configured with relocatable vectors.
It is equivalent to setting the parameter VECBASE=<addr>; see Section 2.4.3.9 for
-mvecbase addr details.
Unlike that parameter however, this option implies -mref (it generates a new memory
map). On xt-genldscripts, it also implies -p if the LSP directory is known, i.e. if
either -b or -std is specified.
Specifies the static vector select pin value n, which must be 0 or 1. This selects one of
two possible locations for the reset vector, as well as for the memory error vector if the
memory integrity option is configured. It is equivalent to setting the parameter
-mvecselect n VECSELECT=n; see Section 2.4.3.10 for details.
Unlike that parameter however, this option implies -mref (it generates a new memory
map). On xt-genldscripts, it also implies -p if the LSP directory is known, i.e. if
either -b or -std is specified.
Specifies the reset vector address to be used for memory map generation. This option is
especially useful when generating linker scripts for processors with the External
Reset Vector option. It can also be used as an alternative to the
-mvecselect option. xt-genldscripts outputs a warning if addr is not a
supported reset address for the processor, or if addr is not aligned to 16 bytes. If the
-mvecreset addr argument -mvecselect 0 is specified along with -mvecreset, or if
VECSELECT=0, then -mvecreset is ignored. It is equivalent to setting the
parameter VECRESET=addr; see Section 2.4.3.10 for details.
Unlike that parameter however, this option implies -mref (it generates a new memory
map). On xt-genldscripts, it also implies -p if the LSP directory is known, i.e. if
either -b or -std is specified.
The last three options are standard Xtensa processor configuration selection options de-
scribed in more detail in the Xtensa Software Development Toolkit User’s Guide.
The following sections provide additional details on the use of these options.
The easiest way to create an LSP is to copy one of the existing standard LSPs that is
closest to what is required (see Section 1.3 for a list of standard LSPs), and edit it as
needed. See also Section 2.3.1 for a quick way to copy all standard LSPs. After editing a
memory map, run xt-genldscripts to generate the linker scripts.
For example, let us create an LSP in /home/user/mylsp based on the min-rt LSP.
The core package (<xtensa_root>) is installed in /home/user/s1. We can do this:
After this, we can use the new LSP to build an application by invoking xt-xcc with the
-mlsp=/home/user/mylsp option. A relative path name containing a slash can also
be used, for example -mlsp=./mylsp if the current directory is /home/user. Using
-mlsp=mylsp (no slash) does not work: it refers to a standard LSP named mylsp
(which does not exist).
xt-genldscripts processes one or more memory map files to construct the memory
map used to generate linker scripts. It always starts with the main memory map file,
which defaults to <lspDir>/memmap.xmm. This can be overridden with the -m option
(or with -mref).
You can specify extra memory map files using the -a and -r options. This can be used
to add new memories to the main memory map without modifying it. For example:
The -a option is essentially equivalent to concatenating the contents of the text file
<addedMapFile> onto the end of the main memory map file. An error is reported if any
memory, segment, or section is encountered that was already defined (by name).
The -r option is similar to the -a option. However, rather than strictly adding, it rede-
fines (overrides) any element already encountered (that is, with the same name) without
causing an error. Redefining a memory causes the previous definition of that memory to
be discarded, along with any contained segments and sections.
Redefining a segment by name2 causes it to be removed from the memory that previ-
ously contained it, along with any contained sections. Redefining a section removes it
from its previous segment. For example:
The -v option in this example is not required. However, it is useful in combination with
the -r option as it reports any replaced element.
You can specify multiple -a and -r options. They are processed in the order encoun-
tered on the command line. The order of the -m option, if specified, is not important; the
main memory map file is always processed first.
The xt-regenlsps tool invokes xt-genldscripts for each specified LSP. By de-
fault, all standard LSPs are copied, except those LSPs that xt-genldscripts cannot
regenerate (see end of Section 2.1).
To keep the core package installation pristine, Cadence recommends that you create
your own LSP or start from a copy. For example, you can copy a single standard LSP
using the -mlsp and -b options of xt-regenlsps, or copy all standard LSPs using
just the -dstbase option. Avoid using xt-regenlsps to modify standard LSPs; doing
so modifies the core package installation (this ability is kept for backward compatibility
only, and may be removed in a future release).
Note: By default, xt-regenlsps simply copies each LSP memmap.xmm file from the
source to the destination LSP. It does not update the destination memmap.xmm file based
on other options given to it. To update the destination memmap.xmm file accordingly, use
the -u option.
For example, to override or add system memories to all the standard LSPs’ default
memory maps, move default code and data to local memories, and place the resulting
LSPs under the <baseDir> directory, invoke xt–regenlsps as follows:
2. Segments are currently matched by name. Future versions of xt-genldscripts may instead match segments by address, which is prefer-
able, given segment names often carry no useful semantics. For this reasons, it is best not to rely on identifying segments by name.
memmap.xmm file are processed. Thus, the -m option to xt-regenlsps can be made to
work with Xtensa Tools version 6.0 by using the memory map output by xt-genld-
scripts -memsonly -noldscripts -map <map> as a starting point for the new
global memory map file. However, the default memory maps of standard LSPs may be-
come more distinct from each other in future releases, making the use of this flag im-
practical. Use of the -m option of xt-regenlsps is discouraged.
Comments start from the first # (hash character) or // (two forward slashes) on the line
to the end of the line. Comments, new lines, and white spaces are ignored. Keywords
and identifiers are case-sensitive unless specified otherwise.
The following sections provide detailed syntax and semantics of memory descriptions.
<memory> in Section 2.4.1
<parameter> in Section 2.4.3
<primitive> in Section 2.4.4
Section 2.4.5 summarizes the full syntax tree
Each memory is described by name, type, starting address, size in bytes, attributes
(e.g., writable, executable), and a list of address ranges or segments contained within
that memory.
The words BEGIN and END (capitalized) are reserved keywords. They must each be at
the start of a line. The <name> identifiers following each of a pair of these keywords
must match, but are otherwise ignored. The <mem-name> field names the memory.
The <addr> and <size> fields indicate the memory’s address and size in bytes. They
are constant integers in hexadecimal (when prefixed with 0x) or decimal. Each may op-
tionally be split into virtual and physical address and size separated by a comma. Such
a split is only meaningful, that is, with virtual and physical parameters potentially differ-
ent, with processor configurations that provide for memory address translation. In this
case, <addr> and <size> are the default address and size at which the memory can
be found in virtual address space, and <phys-addr> and <phys-size> are the actual
address and size of memory in physical address space.
Virtual addresses are normally expected to be located within one of the processor’s stat-
ically mapped address ranges, but can be at any allowed virtual address as long as the
application ensures the proper mapping exists before the memory is used. Both <addr>
and <phys-addr> fields must refer to the same sequence of bytes in memory, but
<size> can be smaller than <phys-size> when only part of the physical memory is
mapped into virtual space.
The <mem-type> field is an identifier that indicates the type of memory. Its main pur-
pose is to identify the types of local memories and XLMI. Type names dataRam,
dataRom, instRam, instRom, dataPort, and XLMI3 are reserved for this purpose.
Other memories (for example, memories mapped on the PIF) are generally given a type
name of sysram or sysrom, however, any non-reserved type name is accepted.4
Note: It is possible to define memories that cover only portions of a local memory inter-
face, or that span multiple contiguous local memory interfaces of the same type. Howev-
er, defining a memory that spans different types of memory interfaces (for example,
spanning both a local data RAM and PIF) causes xt-genldscripts to issue an error.
This helps avoid a number of such spanning scenarios that are not allowed by the ISA,
such as executing fall-through code (without branching) across memory interfaces, or a
single unaligned load or store spanning data RAM and PIF, etc.
3. For compatibility among releases, both type names dataPort and XLMI are accepted for XLMI; the two names are synonymous.
4. For backward compatibility with previous releases, the memory will be given the device attribute if given one of the following type names:
Uart, Led, Ethernet, EDM, TraceBuffer, FpgaRegs, BusInt, V3. Use of these type names is discouraged. This compatibility
behavior will be dropped in a future release.
device if segments need to be placed in it. A memory marked device cannot contain
any segments5; it serves to reserve space in the memory map for non-memory compo-
nents. Memories within a local memory interface address range can only be given attri-
butes valid for that memory interface—for example, memory addressed in a local in-
struction RAM interface may be marked executable and writable, but memory in a
local data ROM interface cannot be given either of these two attributes.
Most segments are marked with a “C” meaning the segment can be changed. The stack
and heap can only be allocated to changeable segments. Segments containing an inter-
rupt or exception vector are marked with an "F" to indicate they are fixed for a given pro-
cessor configuration (or for a given setting of the VECBASE and VECSELECT parame-
ters, for processors configured with relocatable vectors). The start address of a fixed
segment is the corresponding vector’s address, and can only be changed for processors
configured with relocatable vectors, and only in concert with changing the VECBASE pa-
rameter (for most vectors) or VECSELECT parameter (for the reset vector and memory
error vector). Any other change to a vector address impacts the processor configuration,
and may only be done using the Xtensa Processor Generator. To enforce conventions,
modifying a fixed segment’s first section also results in an error. However, you can easi-
ly modify a fixed segment’s size, as long as this does not cause overlap with other seg-
ments.
The default stack may be assigned to at most one segment in the memory map by add-
ing the :STACK field. This causes the generated linker scripts to define two symbols
whose addresses delineate the boundaries of the stack area. The __stack symbol is
located at the base of the stack, that is, near the end of the stack area. The stack pointer
(a1 in the Xtensa ABI) can be initialized to the address of this symbol. The
_stack_sentry symbol is located at the deepest stack location, that is, at the start of
5. For backward compatibility, the device attribute causes the addition in the generated linker script of a symbol whose name and value (address)
are the memory’s name and address, unless the name matches an emulation board memory (iocached, iobypass, rambypass). The
use of these symbols is deprecated. Other mechanisms to define device addresses, such as header files, are usually more appropriate.
the stack area which follows the last section in the segment. Code that checks for stack
overflow can check that the value of the current stack pointer against the address of this
symbol. Note that according to Xtensa calling conventions (the ABI), the stack grows
downward, that is, from high to low addresses.
Note: It is up to the runtime or OS to use the symbols created as a result of placing the
STACK keyword, or allocate its stack(s) in some other manner. XTOS, the basic runtime
provided by Cadence and used by many standard LSPs, is single-threaded and makes
use of this single stack. Third-party operating systems generally use their own mecha-
nism instead. See the Xtensa System Software Reference Manual for details on XTOS.
The default “heap” (memory pool for dynamic memory allocation, e.g. using malloc)
may be assigned to at most one segment in the memory map by adding the :HEAP field.
This causes the generated linker scripts to define two symbols whose addresses delin-
eate the boundaries of the heap area. The _end symbol is located at the start of the
heap area, just after the last section in the segment. (While this symbol name may seem
confusing, it is in common use: the _end symbol in typical simple linker scripts points to
the end of code and data, which is usually followed by freely available memory and thus
chosen as the start of the heap.)
The _heap_sentry symbol is located at the end of the heap, which is at the end of the
segment. In other words, its address is that of the first byte past the segment. If both the
heap and stack are located in the same segment, they completely overlap. This is useful
because the heap generally grows upwards and the stack always grows downwards,
such that they start at opposite ends of the segment and meet in the middle. In this way,
available memory can be used most effectively when the required sizes of stack and
heap are not known a priori. However, be aware that such stack and heap growth are
not checked against each other (with the exception of heap allocation under ISS, as im-
plemented by sbrk() in libsim.a).
Note: It is up to the memory pool allocator implementation to use the symbols created
as a result of placing the HEAP keyword, or allocate the heap in some other manner. The
C library calls sbrk() (implemented in libsim.a and libgloss.a), which makes use
of the heap defined in this way.
For example:
ENTRY = _start
Values are either a word composed of alphanumerics and underscores (possibly a num-
ber), or a double quote delimited string that can contain most other ASCII characters.
For Boolean type parameters (see below), the value must be true or false.
Note: If the same parameter is assigned multiple times, the last one always has prece-
dence. Unrecognized parameters cause warnings, but are otherwise ignored.
Boolean parameter, defaults to false. Enables generation of special linker scripts used
to construct a ROM image. Sections located in RAM can be stored in ROM (or some
other specific segment) and copied to their proper locations in RAM at system startup
time. See Chapter 3 for details.
Defines the program start address symbol for ELF executables linked using this LSP.
This ELF start address can be used by certain tools. For example, GDB loads this ad-
dress into the PC after a "load" command.
Defaults to "_ResetVector".
Boolean parameter, defaults to false. Filters out all read-only memories, i.e. memories
without the writable attribute. This parameter’s effect is not visible in memory maps
output by the -map or -u option of xt-genldscripts.
Boolean parameter, defaults to false. When used in the context of Xtensa processors
built specifically for one of the supported FPGA emulation boards (XT-AV200, XT-AV60,
XT-AV110, XT-ML605, or XT-KC705), this parameter adds a number of memories spe-
cific to these boards. This parameter is incompatible with the INCLUDE_DV_SECTIONS
parameter, because memories added by these two parameters may overlap.
Reserves a specific area away from a memory segment. This is meant as a simple
mechanism for creating pairs of LSPs that split allocatable memory so that they can be
loaded separately. See Section 2.6 for details.
Boolean parameter, defaults to false. Makes the generated linker scripts follow the
conventions of rtos standard LSPs (i.e. rtos-ram, rtos-ramp, rtos-rom, rtos-
res), which use this parameter. Among other effects, setting this parameter:
- attempts to generate a linker script that merges input sections into just three
output sections named .text, .data, and .bss, according to the traditional
linker output expected by some third-party operating system build environments.
As a consequence, some segment overflows can no longer be detected by the
linker.
- adds a number of comments to the generated linker scripts.
For processors configured with relocatable vectors, this specifies the location of dynam-
ic vectors (all vectors except reset and memory error vectors); in other words, the ex-
pected value of the VECBASE register. The value of this parameter must match the loca-
tion of dynamic vectors in the memory map. Thus, modifying an existing memory map to
relocate such vectors involves changing both this parameter, and the memory segments
and sections corresponding to dynamic vectors. On the other hand, when generating a
new memory map (that is, when using the -genmap, -map, or -mref options, or in cer-
tain invocations of xt-genldscripts as detailed in the -mref option description),
vector segments and sections are automatically placed at the location specified by the
VECBASE parameter (or -mvecbase option), assuming a suitable memory is present by
default at that location.
If this parameter is not specified, its value is the processor’s reset value of VECBASE.
For processors configured with relocatable vectors, this specifies the expected value of
the external vector select pin, which must be 0 or 1, selecting one of two locations for
static vectors. Static vectors consist of the reset vector and, for processors configured
with the memory integrity option, the memory error vector.
The value of the VECSELECT parameter must match the location of static vectors in the
memory map. Thus, when modifying an existing memory map to alternate the location of
these vectors, you must change both this parameter and the memory segments and
sections corresponding to the static vectors.
However, when generating a new memory map (that is, when using the -map, -genmap,
or -mref options, or in certain invocations of xt-genldscripts as detailed in the
-mref option description), static vector segments and sections are automatically placed
at the location implied by the VECSELECT parameter (or -mvecselect option). Note:
this only works if a suitable memory is present by default (in the generated memory
map) at the specified location. If such a suitable memory does not exist, which may hap-
pen when selecting the alternate (non-default) location of static vectors, then rather than
generate a new memory map, you must provide a complete memory map that correctly
places the segments and sections needed for static vectors. In this case, you cannot
use the VECSELECT parameter or -mvecselect option when generating a new memo-
ry map. Start by generating a memory map without using the VECSELECT parameter or
-mvecselect option (they cannot be used in this case to generate a memory map),
edit the resulting memory map (add a memory where needed, with segments and sec-
tions for each of the static vectors, and the VECSELECT parameter to select this location
of static vectors), and re-invoke xt-genldscripts using this edited memory map.
If this parameter is not specified, its value is as defined in the processor configuration
used with the software tools (this configuration parameter does not affect processor
hardware; it merely specifies to software the expected external vector select pin value).
This specifies the reset vector address of the processor for the generation of the linker
scripts. This option is especially useful when generating linker scripts for processors
with the External Reset Vector option. It can also be used as an alternative to the
-mvecselect option. xt-genldscripts outputs a warning if addr is not a supported
reset address for the processor, or if addr is not aligned to 16 bytes. If the argument
-mvecselect 0 is specified in addition to VECRESET, or if VECSELECT=0, then
VECRESET is ignored.
The value of the VECRESET parameter must match the location of static vectors in the
memory map. Thus, when modifying an existing memory map to the alternate location of
these vectors, you must change both this parameter and the memory segments and
sections corresponding to the static vectors.
When generating a new memory map using the -map, -genmap, or -mref options, or in
certain invocations of xt-genldscripts (as detailed in the -mref option description),
static vector segments and sections are automatically placed at the VECRESET parame-
ter value or placed as specified by the -mvecreset option. Note: this only works if a
suitable memory is present by default in the generated memory map at the specified lo-
cation. If such a suitable memory does not exist, which may happen when selecting the
alternate (non-default) location of static vectors, then rather than generate a new memo-
ry map, you must provide a complete memory map that correctly places the segments
and sections needed for static vectors. In this case, you cannot use the VECRESET pa-
rameter or -mvecreset option when generating a new memory map. Start by generat-
ing a memory map without using the VECRESET parameter or -mvecrest option (they
cannot be used in this case to generate a memory map), edit the resulting memory map
(add a memory where needed, with segments and sections for each of the static vec-
tors, and the VECRESET parameter to select this location of static vectors), and re-in-
voke xt-genldscripts using this edited memory map.
Specifies how many overlays should be created in the executable file. One section will
be defined for each overlay, and an overlay “map area” will be reserved for mapping
overlays. In principle, the number of overlays possible is limited only by the amount of
storage available, although no testing has been done with numbers larger than 100. If
the number is zero or negative, no overlay support is generated. The default is no over-
lay support. See Section 2.8.9 for details.
Specifies the load address (LMA) alignment for the overlay sections. The load address-
es are assigned by the linker such that these addresses are aligned to the specified val-
ue. For instance, a value of 8192 will ensure that the load addresses all start on 8 KB
boundaries. This is useful in aligning the overlay sections with block start addresses if
they are stored in flash, for example. This parameter is optional, the minimum value be-
ing 16 and the maximum 2^10, i.e., 1 MB. The value specified must be a power of 2.The
default is 16. if OVERLAYS is not specified then this parameter will be ignored.
Specifies the segment in which the overlay should be mapped for execution, the VMA
segment. The named segment must exist in the memory map file and must not be empty
(i.e., at least one section name must be assigned to it). The section name does not mat-
ter, and the section can be empty. This parameter is optional. If not specified, overlays
will be mapped in the same segment that they are loaded.
Specifies the segment into which the overlay sections are loaded, the LMA segment.
The named segment must exist in the memory map file and must not be empty (i.e., at
least one section name must be assigned to it). This parameter is optional. If not speci-
fied, overlays will be loaded into the same segment in which text resides.
Specifies the maximum size (in bytes) of the named memory. OVERRIDE MEMORY lim-
its the size of the specified memory by reducing the memory’s size to the specified size,
while leaving the starting address the same. When using an FPGA emulation board, this
parameter is used to specify the size of each memory.
Boolean parameter, defaults to false. Allows memory map to specify physical address-
es for memories, to be used for LMA addresses in the output linker scripts. Even if the
parameter is true, this will only take effect if the memory has different virtual and phys-
ical addresses. This option is not compatible with the ROMING option and will cause an
error if both are specified.
Note: This option does not work with overlays at this time.
Specifies the pattern to use to fill otherwise unspecified regions of memory within an out-
put section. This is an optional parameter; if not specified then zeros will be used for fill-
ing. <expr> can be a decimal or hex number. Hex numbers (beginning with 0x) can be
of any length. Decimal numbers will be truncated to the four least significant bytes.
Numbers smaller than four bytes are allowed. In all cases, the numbers will be treated
as big-endian. The fill pattern is repeated as necessary to fill the required amount of
space.
2.4.4 Primitives
This primitive overrides the memory map, moving the sections (if any) specified by the
SECTIONS() keyword into the segment specified by <seg-specifier>, i.e. the segment
containing the section named by WITH_SECTION() or the segment named by
IN_SEGMENT(). If any of the sections to be moved do not exist in the memory map,
they are simply added. However, the destination segment must exist.
The placement effected by this primitive completes before a resulting memory map is
output by the -map or -u option of xt-genldscripts. In other words, the effect of this
primitive (if specified in a file referenced by other options) is visible in the memory map
output by the -map or -u option. Without these options, this primitive simply affects the
generated linker scripts.
2.4.4.2 NOLOAD
This primitive specifies that the listed sections should be marked as NOLOAD. The linker
will process the sections normally, but the loader will not load these sections into memo-
ry at runtime. This is useful when the sections are empty to begin with, or when they are
loaded via alternate methods (e.g., executable sections in IROM). Caution must be ex-
ercised when using this primitive, as the program will misbehave if required sections are
not loaded.
This primitive specifies the fill pattern to be used to fill otherwise unspecified regions of
memory within the specified section(s). This specification overrides the FILL_PATTERN
parameter, if any. The rules for specifying the pattern are the same as for the FILL_PAT-
TERN parameter. Use this primitive to specify the fill pattern for specific output sec-
tion(s). Use FILL_PATTERN to specify the default fill pattern for all output sections.
Memory map file syntax can be summarized as follows, in Backus Naur Form (BNF).
The BNF notation used here is extended with square brackets to denote [optional
items], and curly brackets to denote {grouped items}. Items grouped with curly brack-
ets repeat zero or more times if followed by an asterisk (*), and repeat one or more
times if followed by a plus sign (+).
The xt-genldscripts tool, assembler, and linker expand this mechanism to multiple
memories. For example, you can place uninitialized data in a data RAM named "dram0"
by placing it in a section named ".dram0.bss" contained in that data RAM.
The assembler marks any section whose name ends with ".bss" or starts with ".bss."
(the latter are input sections merged into the .bss output section, see Section 2.8.2.1)
or specified in a .section directive with the @nobits flag, as an allocate-only section
(see the GNU Assembler User’s Guide for more details). The xt-genldscripts tool
also recognizes any section whose name ends with ".bss" as an uninitialized data sec-
tion. Such allocate-only sections must be the last listed in their containing segment(s),
which allows the linker to avoid taking up space for them in the generated ELF file.
For each section whose name ends in ".bss", xt-genldscripts generates corre-
sponding “<section_name>_start” and "<section_name>_end” symbols pointing
to the start and end of the section. Here, <section_name> is the name of the section
with periods replaced with underscores. It also generates, in the .rodata output sec-
tion, a table of all these *.bss sections with their start and end addresses. The table it-
self is bracketed by symbols _bss_table_start and _bss_table_end. The startup
code uses these to zero all uninitialized data sections.
For example:
Note: The .rodata section can be packed in ROM LSPs, so the above initialization
code must execute after section unpacking is complete. This allows the above code to
be located outside the reset vector, such as in a packed section. See Chapter 3 for de-
tails on section unpacking.
This is a simplistic mechanism for simple cases. More elaborate memory partitioning
scenarios generally require writing custom memory maps (LSPs) for each program.
The value of either parameter is a string that consists of three space-separated fields,
possibly repeated, separated by colons. Because of whitespace, the entire value must
be quoted. In summary, the <value> string consists of:
The segment to be split is identified by section name. The <section-name> field is the
name of a section (any section) in that segment. The <size> field is the size of the re-
served area in bytes. The segment must be at least <size> plus <extrasize> bytes
in size, or an error is reported. If <extrasize> is not specified, it defaults to 1/8 of
<size>. The reserved area is located at the start or end of the segment according to
the start or end keyword in the third field.
For example, to make an LSP reserve 512 kB at the end of the memory used for data,
and ensure at least 64 kB remains for the application:
RESERVE_SEGMENT_AREA = ".iram0.text
BEGIN dport0
0x3ffc0000: dataPort : dport0 : 0x20000 : writable ;
dport0_0:C: 0x3ffc0000-0x3ffdffff : .dport0.rodata .dport0.literal
.dport0.data .dport0.bss;
END dport0
BEGIN dram0
0x3ffe0000: dataRam : dram0 : 0x20000 : writable ;
dram0_0:C: 0x3ffe0000-0x3fffffff : .dram0.rodata .dram0.literal
.iram0.literal .dram0.data
.dram0.bss;
END dram0
BEGIN iram0
0x40000000: instRam : iram0 : 0x20000 : executable, writable ;
iram0_0:C: 0x40000000-0x4001ffff : .iram0.text;
END iram0
BEGIN srom
0x50000000: sysrom : srom : 0x1000000 : executable ;
srom0:F: 0x50000000-0x500002ff : .ResetVector.text;
srom1:C: 0x50000300-0x50ffffff : .srom.rodata .srom.literal
.srom.text .rom.store;
END srom
BEGIN sram
0x60000000: sysram : sram : 0x4000000 : executable, writable ;
sram0 :F: 0x60000000-0x60000177 : .WindowVectors.text;
sram1 :C: 0x60000178-0x6000017f : .Level2InterruptVector.literal;
sram2 :F: 0x60000180-0x600001b7 : .Level2InterruptVector.text;
sram3 :C: 0x600001b8-0x600001bf : .Level3InterruptVector.literal;
sram4 :F: 0x600001c0-0x600001f7 : .Level3InterruptVector.text;
sram5 :C: 0x600001f8-0x600001ff : .Level4InterruptVector.literal;
sram6 :F: 0x60000200-0x60000237 : .Level4InterruptVector.text;
sram7 :C: 0x60000238-0x6000023f : .Level5InterruptVector.literal;
sram8 :F: 0x60000240-0x60000277 : .Level5InterruptVector.text;
sram9 :C: 0x60000278-0x6000027f : .DebugExceptionVector.literal;
sram10:F: 0x60000280-0x600002b7 : .DebugExceptionVector.text;
sram11:C: 0x600002b8-0x600002bf : .NMIExceptionVector.literal;
sram12:F: 0x600002c0-0x600002f7 : .NMIExceptionVector.text;
sram13:C: 0x600002f8-0x600002ff : .KernelExceptionVector.literal;
sram14:F: 0x60000300-0x60000337 : .KernelExceptionVector.text;
sram15:C: 0x60000338-0x6000033f : .UserExceptionVector.literal;
sram16:F: 0x60000340-0x60000377 : .UserExceptionVector.text;
sram17:C: 0x60000378-0x600003bf : .DoubleExceptionVector.literal;
sram18:F: 0x600003c0-0x600003ff : .DoubleExceptionVector.text;
sram19:C: 0x60000400-0x63ffffff : STACK : HEAP : .sram.rodata .rodata
.lit4 .sram.literal .literal
.ResetVector.literal .sram.text .text
.sram.data .data .sram.bss .bss;
END sram
This example memory map contains five memories: dram0, iram0, dport0, srom, and
sram.
The dram0 memory, for example, is a 128 kB DataRAM (type dataRam) located at ad-
dress 0x3ffe0000. Like all Xtensa processor DataRAMs it is writable but not
executable. It contains a single segment named dram0_0 that spans the entire
DataRAM, and contains the following sections, in this order: .dram0.rodata,
.iram0.literal, .dram0.literal, .dram0.data, and .dram0.bss.
The sram memory, on the other hand, is a 512 MB system memory (accessed using the
PIF interface) divided into multiple segments due to the various exception and interrupt
vectors located within it. Ten of these segments are for the vectors themselves; these
cannot be changed (except for their sizes) without creating a new processor configura-
tion. The sram18 segment is the biggest within sram, spanning almost the entire mem-
ory, and contains the heap, stack, and most default sections.
2.8.1 Overview
The ELF file format structures a compiled object or linked executable as a list of named
sections with specific contents and attributes. Certain sections contain or describe code
or data at a specified address in the processor’s memory map. Other sections contain
information that is not generally loaded in the target system, such as symbols, debugger
information, relocations, and other information. We are concerned here with the former
sections, in how code and data find their way into the processor’s memory map.
Many section names are reserved for specific uses. An application’s code and data are
most often found in just five of these sections:
The .text section, which contains code. It can sometimes contain literals.
The .data section, which contains initialized global variables.
The .bss section (or- common block), which contains un-initialized (or zero-initial-
ized) global variables.
The .rodata section, which contains read-only global variables, constants, jump
tables, etc.
The .literal section (or .lit4), which contains literals (32-bit constants) used
in the code. This section is specific to the Xtensa architecture.
By default, C compilers place code and data in these sections. The assembler provides
special directives for placing code and data in these sections, in addition to directives for
placing them in any named section.
Compilation and assembly produce object files. The sections present in an object file
can be examined using xt-objdump (see the GNU Binary Utilities User’s Guide for de-
tails). For example:
The linker aggregates a number of input object files into an output object file. It resolves
symbol references and merges input sections (the input objects’ sections) into output
sections (the output object’s sections) according to the instructions of a linker script.
Most default linker scripts merge each of the above five sections from all input files into
an output section of the same name. For example, they usually merge all .text input
sections into the .text output section. Linker scripts used for linking final executables
also merge various other input sections into each output section. For example, the
.init input section is merged into the .text output section. As another example, any
global variables placed in the common block (including uninitialized globals not declared
static in C code compiled with -fcommon, and variables declared in assembler using
.comm or .lcomm directives) to avoid multiple definition errors are merged into the out-
put .bss section by the final linker script.
The following sections provide more details on the use of specific linker section names,
and how this can be used to place code and data in specific areas of the memory map.
Here are more details on specific section names, starting with the most common:
.text: An application's instructions are placed in the segment containing this section.
Thus, this section must be assigned to a segment contained in an executable memory.
.literal: An application's literals are placed in the segment containing this section.
Literals are constant 32-bit data items, typically addresses of global or static variables
and functions. The L32R instruction loads a literal, normally at an immediate negative
offset from the PC. In this PC-relative mode, the L32R instruction requires that the literal
it loads resides in the 256 KB that precedes the instruction. Thus, the .literal (or
<memname>.literal) section that contains such literals must precede, or be com-
bined with, the corresponding .text (or <memname>.text) section.
Xtensa LX1 through LX3 processors feature a LITBASE register that selects one of two
modes for L32R: PC-relative (as described above), or base-relative (extended L32R) in
which case literals go in the .lit4 section instead, as described below.
.lit4: On Xtensa LX1 through LX3, Xtensa 6 through Xtensa 8, and Diamond Stan-
dard Cores Rev. A through Rev. C processors (Tensilica releases RA through RC), this
section contains an application's literals when using base-relative L32R (extended
L32R) instead of the usual PC-relative mode (see above). (On these processors, load-
ing a literal from an instruction RAM is slow, so base-relative mode is used for large in-
struction RAMs where the range of PC relative L32R cannot reach a preceding data
RAM.) In this mode, L32R instructions load literals from a single literal pool of up to 256
KB. The LITBASE register specifies the address of the end of this pool. All base-relative
literals are placed in the .lit4 (or <memname>.lit4) sections and combined into this
single literal pool in the .lit4 output section. (This contrasts with PC-relative L32R
where literals may be interspersed with the code and spread across multiple output sec-
tions.)
The LITBASE register is initialized once at startup, and assumed constant throughout
program execution. Other than in the early reset handler, a given program being linked
uses only one of the two L32R modes: PC-relative, or base-relative. For consistency
among all software tools and target libraries, the Xtensa Processor Generator extended
L32R software option selects one of the two (extended L32R means base-relative).
.rodata: An application's read-only data is placed in the segment containing this sec-
tion. Read-only data typically includes compiler generated jump tables and other infor-
mation, constant strings, and global variables declared with the const modifier. As an
optimization, global variables declared with the const modifier and assigned a value of
zero may be placed in the .bss section instead. Similarly, global variables with the
const modifier but not assigned a value may be placed in either the .bss section or the
common block instead of the .rodata section. The XCC compiler implements both of
these optimizations.
.data: An application's initialized data is placed in the segment containing this section.
Initialized data refers to global variables that are assigned an initial value. If the value
assigned is zero, certain compilers (such as the XCC compiler) place the global variable
in the .bss section instead of the .data section. Initialized data does not include func-
tion-local (automatic) variables, which are placed on the stack, or dynamically allocated
variables, which are placed on the heap. Applications typically write to this data, so the
memory containing this section must be writable.
.bss: An application's uninitialized data is placed in the segment containing this sec-
tion. Uninitialized data refers to global variables that are not assigned an initial value.
The term may be misleading: the C standard specifies that such variables are cleared,
that is, initialized to zero, before the program starts. Thus, uninitialized data is initialized
to zero. Certain compilers, when requested (usually to work-around old code using non-
ANSI semantics), may place uninitialized data in the common block instead of the .bss
section. At a small performance cost, and at the cost of not catching the error of defining
two global variables with the same name, this avoids multiple definition errors when the
same global variable is declared without an assignment or the extern or static key-
word in multiple compilation units (see the -fcommon option description in the Xtensa C
and C++ Compiler User’s Guide). The linker merges the common block in the output
.bss section. Uninitialized data does not include function-local (automatic) variables,
which are placed on the stack, or dynamically allocated variables, which are placed on
the heap. Applications typically write to this data, so the memory containing this section
must be writable. You can define multiple uninitialized data sections with similar proper-
ties by using section names ending in .bss; see Section 2.5 for details. The advantage
of the .bss sections is that they don’t take any space in the executable file or in ROM.
For this to work correctly, all .bss sections (sections with names ending in .bss) must
be the last sections listed in their segment.
The startup code (or loader) automatically clears the .bss sections using a linker-script
generated table defining their location as described in Section 2.5. If only the section
named .bss exists (that is, no other section name ends in .bss), this startup code can
be simplified to use linker-script generated symbols _bss_start and _bss_end point-
ing to its beginning and end, instead of the table.
In the example memory map of Section 2.7, all default sections are placed in the
sram13 segment in the sram memory. Note that .literal is placed ahead of .text,
and that .bss is the last section in the segment. Other sections, such as
.iram0.text, can be used to explicitly place code and data into non-default memory
locations as described below.
Other more specific sections frequently encountered in memory maps are as follows.
Here, <d> is 0 (zero) for the first instance of a memory, 1 for the next instance, etc.6
.iram<d>.text :
.iram<d>.literal :
This section contains literals (see .literal section description above) associated with
the instructions in section .iram<d>.text. In RD-2010.0 and later cores,
.iram<d>.literal is usually located in instruction RAM alongside .iram<d>.text.
In earlier cores, this section (despite its name) is normally in a preceding data or PIF
6. For backward compatibility with previous releases, input section names referring to local memories are accepted without the <d> index in gen-
erated linker scripts. For example, .iram.text is accepted in addition to .iram0.text. Corresponding output section names always
have the <d> memory index by default. This compatibility behavior is not applied if multiple local memories of the same type are configured (e.g.
two instruction RAMs, or two data RAMs) or if the unnumbered names are mentioned explicitly in the memory map. This compatibility behavior
may be dropped in a future release. Always use numbered names where possible.
connected memory, in L32R range of the instruction RAM, to avoid accessing literals in
instruction RAM (which, while possible on these earlier cores, is many times slower than
accessing them in a data memory or data cache).
.irom<d>.text :
.irom<d>.literal :
This section contains (PC-relative) literals for .irom<d>.text, similarly to what is de-
scribed above for instruction RAMs.
.dram<d>.rodata ,
.dram<d>.data ,
.dram<d>.bss :
These sections contain read-only data, initialized data, and zero-initialized data, respec-
tively, for a local data RAM.
.drom<d>.rodata :
.dport<d>.rodata ,
.dport<d>.data ,
.dport<d>.bss :
These sections contain read-only data, initialized data, and zero-initialized data, respec-
tively, for a hypothetical RAM which by default is as big as the entire range of the XLMI
interface. These sections are not used by default. However, various sections will be
placed in this hypothetical RAM if they have nowhere else to go, e.g., the .data and
.bss sections will be placed in it if no data RAM or system RAM is configured. XLMI is
often used to map various devices rather than one large RAM. When customizing an
LSP, it may be worthwhile to edit the memory map such that these sections are removed
or made to reflect the correct location and size of any RAM on XLMI, to avoid any acci-
dental placement of data where there is no RAM. The XLMI is normally represented as a
memory named dport0 in the memory map.
.dram<d>.literal
.drom<d>.literal
.dport<d>.literal :
These sections are obsolete. They are meant to place literals in specific data memories,
but are rarely useful. When assigning literals used by code running out of an instruction
memory, for instance, it is preferable to let them default to the corresponding
.iram<d>.literal or .irom<d>.literal section, and place that section appropri-
ately (see .literal above).
.sram<d>.literal ,
.sram<d>.text ,
.sram<d>.rodata ,
.sram<d>.data ,
.sram<d>.bss :
The last four of these sections contain instructions, read-only data, initialized data, and
zero-initialized data, respectively, for a system RAM, that is, a RAM accessed over the
PIF interface. The first contains PC-relative literals for the code in .sram<d>.text (the
two are usually adjacent, in that order, thus allowing the linker to intersperse literals and
code to avoid limiting the amount of code to L32R’s 256 KB range).
.srom<d>.literal ,
.srom<d>.text ,
.srom<d>.rodata :
The last two of these sections contain instructions and read-only data, respectively, for a
system ROM, that is, a ROM accessed over the PIF interface. The first contains literals
for the code in .srom<d>.text (the two are usually adjacent, in that order, thus allow-
ing the linker to intersperse literals and code to avoid limiting the amount of code to
L32R’s 256 KB range).
.<vector>.text :
This section contains the instructions for an interrupt or exception vector named
<vector>. Its address must be that of the vector, which must be contained in an exe-
cutable memory.
.<vector>.literal :
This section contains PC-relative literals associated with the interrupt or exception vec-
tor named <vector>. The window vectors do not use any literals and hence have no
corresponding literal section. The default reset vector usually does not use a separate
literal section: it is usually built with the -mtext-section-literals option so that
any PC-relative literals are placed among instructions, which allows the reset vector to
be placed at the first byte of ROM without space for preceding literals. In this case, the
.ResetVector.literal section is always empty (the assembler emits it anyway) and
can safely be ignored. Note that for backward compatibility, xt-genldscripts does
not complain if this section is out of L32R range of .ResetVector.text, because
such empty sections needed to be in the memory map to satisfy the GNU linker in some
previous software tools releases.
The following section names are generally encountered in object files, that is, as input to
the linker. However, they are not usually found in executables, that is, as output from the
linker. This is because linker scripts generated by xt-genldscripts automatically
merge these input sections into an appropriate output section already described above.
This simplifies memory map files (memmap.xmm), because they don’t need to list these
input section names (among others) explicitly. In other words, these section names
should not be present in a memory map.
.literal.* ,
.lit4.* ,
.text.* ,
.rodata.* ,
.data.* ,
.bss.* :
The “*” match any sequence of zero of more characters. These input sections are
merged into the corresponding .literal, .lit4, .text, .rodata, .data, and.bss
output sections.
The compiler may generate such section names to make them unique, for example by
appending function or variable names to the default section names when given the
-ffunction-sections or -fdata-sections options.
Such section names can also be used directly in source code using section attributes,
assembler section directives, or section renaming options (see Section 2.8.4).
IMPORTANT: in the memmap.xmm file, avoid using any section names that match these
input section patterns, because those sections will end up in the corresponding default
output section instead of where you specify if the generated linker script happens to re-
fer to the default section first (xt-genldscripts normally emits references to sections
in order of containing segment address). For this reason, sections named explicitly in a
memmap.xmm file are usually suffixed rather than prefixed with the default section name
(for example, .dram0.data and not .data.dram0) to avoid such matches.
.iram<d>.lit4 ,
.irom<d>.lit4 :
.sram<d>.lit4 ,
.srom<d>.lit4 :
.<vector>.lit4 :
.gcc_except_table ,
.eh_frame :
These sections are used to implement C++ exception handling and stack unwinding.
Merged into .rodata.
.clib.literal ,
.clib.text ,
.clib.rodata ,
.clib.data ,
.clib.bss ,
.clib.percpu.data ,
.clib.percpu.bss :
Some or all of these section names may be used by the C library to control code and
data placement. Most of the time exact placement of C library internal data is not critical,
and these sections are placed by default to be adjoining to the corresponding default
sections. For example .clib.data is placed together with .data. For multi-core sys-
tems, global data and per-cpu data must be placed differently. To facilitate this, all per-
cpu data (i.e. data that must be replicated per core) is placed in sections .clib.per-
cpu.data and .clib.percpu.bss. Global data (i.e. where a single copy is shared by
all cores) is placed in one of the other sections. For an example of how these are used,
see the sim-mc LSP. Note that these section names are reserved for the C library only
and must not be used by any other code.
.rtos.literal ,
.rtos.text ,
.rtos.rodata ,
.rtos.data ,
.rtos.bss ,
.rtos.percpu.data ,
.rtos.percpu.bss :
Some or all of these section names may be used by XTOS and HAL libraries to control
code and data placement, similar to what is described above for the C library. Operating
systems (RTOS) can also take advantage of this nomenclature to place their data in the
same way for multi-core systems. These names may be used for the OS part of RTOS
ports, but not for any other purpose.
There are essentially five ways to control the placement of code and data when building
an application. They may be used in combination. The five methods are:
Using C language extensions to place specific variables, functions and/or types into
specific sections, for example, using the __attribute__((section(“...”))) modi-
fier. See Section 2.8.5 for a detailed description.
Using .section and related directives in assembler code. See Section 2.8.6 for a
detailed description.
Using the –mrename–section flag to the XCC compiler (xt–xcc), or the equiva-
lent --rename-section flag to the assembler (xt-as). See Section 2.8.7 for de-
tails.
Using the --rename-section flag to xt-objcopy to rename sections in existing
libraries and object files. See Section 2.8.8 for details.
Editing the memory map to change the location of sections, and regenerate an LSP.
See Section 2.8.9 for details.
The first way to control the placement of code and data is to use C language extensions
provided by the compiler. They allow placing specific functions and variables.
Note: Avoid using this mechanism to assign a function or variable to a section already
output by the compiler, such as .text, .data, .rodata, .bss, or .literal (among
others). Doing so may give unpredictable results.
For more details, consult the Xtensa C and C++ Compiler User’s Guide.
For example, in order to place the func function in section .iram0.text, use the fol-
lowing statement prior to defining the function:
This causes the generated code for that function (once defined) to be directed to section
.iram0.text instead of .text. Literals used by this generated code are placed in a
section named by removing any .text suffix, and appending either .literal or
.lit4 according to whether the compiler is configured to use PC-relative or base-rela-
tive (extended L32R) literals respectively. In this example, PC-relative literals go in the
.iram0.literal section instead of the .literal section.
Compiling a function can generate contents in many other sections. These section
names are not affected by the section() attribute. In particular, compiler-generated
read-only data, such as constant jump tables, normally go to the .rodata section. To
place them in another section, use the rodata_section() attribute. For example, the
above example can be extended as follows:
Other section names are not affected by either the section() or rodata_section()
function attributes. Specifically:
Variables declared static within the function are not affected. They continue de-
faulting to the .bss or .rodata section depending on how they are declared, or to
a specific section where given their own section() attribute. Note: within a func-
tion, static variables never go in the common block, so the common block is not a
possibility here.
The names of special sections, such as those for C++ exception handling tables, are
unaffected by either attribute.
For more details, consult the Xtensa C and C++ Compiler User’s Guide.
Similarly, in order to place variable globvar in section .dram0.data, use the following
statement:
If you place a variable in an allocatable section with no contents, such as .bss or a sec-
tion name ending in .bss, any assigned initial value is ignored even if non-zero. These
sections are always cleared to zero at program startup. See Section 2.5 for details.
For more details, consult the Xtensa C and C++ Compiler User’s Guide.
The second way to control the placement of code and data is to use assembler direc-
tives that direct assembled code and data to specific sections. This serves the same
purpose as the first method, but applies to assembler source instead of C source.
The most common directives are .text and .data, which direct any following code or
data to the section of the same name, with default attributes. Other sections must be
named explicitly using the .section directive (or the related .pushsection,
.popsection, and .previous directives). Global variables are placed in the common
block using the .comm and .lcomm directives, independently of section directives.
Most assemblers maintain a single current section, that is, the section in which code and
data are directed at any given point in the assembly source, as controlled by the above
directives.
Xtensa assembly code has the special property of requiring two current sections: one for
the code itself (the current section), and another for any literals generated automatically
in the course of assembling instructions (the literal section). Thus, literals typically go in
a section separate from the code (unless the assembler --text-section-literals
option or the compiler driver -mtext-section-literals option was given when us-
ing PC-relative literals). In particular, the assembler may transform the MOVI instruction
into an L32R with associated literal if the constant is out of range of MOVI’s immediate
operand. Literals explicitly specified using the .literal directive are also placed in the
literal section.
Normally, the literal section name is derived from the current section name. Optionally,
the .begin literal_prefix and .end literal_prefix directives can be used
to override the name from which the literal section name is derived. Table 2–5 lists the
name derivation rules. Given the first matching name in the first column, the resulting lit-
eral section name is in the corresponding second or third column according to the L32R
mode being used. Here, * matches any series of characters, K matches any series of
characters not including a period, and G is the name of a section group. Thus in the de-
fault .text section, the literal section is .literal in the PC-relative mode of L32R,
and .lit4 when the base-relative mode of L32R is used (extended L32R).
Table 2–5. Derivation of Literal Section Name from Current Section Name (or Override)
Literal Section Name in Literal Section Name in
Current Section Name
PC-Relative L32R Mode Base-Relative L32R Mode
.text .literal .lit4
*
.literal.G .lit4.G
(if * is a member of section group G)
Table 2–5. Derivation of Literal Section Name from Current Section Name (or Override)
Literal Section Name in Literal Section Name in
Current Section Name
PC-Relative L32R Mode Base-Relative L32R Mode
.gnu.linkonce.K.* .gnu.linkonce.literal.* .gnu.linkonce.lit4.*
*.text *.literal *.lit4
* *.literal *.lit4
The .section directive directs all subsequent code and data to the section named
.UserExceptionVector.text. This first matches the *.text pattern in Table 2–5.
Thus, the literal generated by the MOVI instruction goes to the literal section named
.UserExceptionVector.literal when in PC-relative L32R mode (unless one of
the text-section-literals options is specified), or to the .UserExceptionVec-
tor.lit4 section when in base-relative L32R mode.
Thirdly, you can use the –mrename–section flag to xt–xcc. This flag allows directing
the contents of the file being compiled (or assembled) to sections different from the de-
faults. This flag causes the code, data, literals, or read-only data that would normally be
output to a certain section (whether by default or because of section attributes or other
options as described above) to be output to another section instead.
Note: To avoid unexpected results, be careful to redirect a section only to another with
similar attributes, e.g. redirect .bss to .dram0.bss but not to .dram0.data. Also
avoid “merging” sections, that is, redirecting to sections already output by the compiler.
7. Many existing vector sources redundantly specify the .begin literal_prefix directive, because it was required in Xtensa Tools version 6.
For example, consider an application being compiled for a system described by the
memory map shown in Section 2.7 on page 39. The application is composed of two files,
perf.c and control.c. The perf.c file contains the performance critical portions of
the application, which we want to place in the instruction RAM and data RAM, respec-
tively. We can do this by building the application as follows:
Assuming PC-relative literals, all code and data for control.c are placed into the de-
fault sections (.text, .data, .literal, .rodata, and .bss) in segment sram18.
However, the initialized data, literals, read-only data, and uninitialized data for perf.c
are placed in sections .dram0.data, .dram0.literal, .dram0.rodata, and
.dram0.bss respectively, all contained in segment dram0_0. The code generated for
perf.c is placed in section .iram0.text, contained in segment iram0_0.
When assembling code using xt-as instead of xt-xcc, use the --rename-section
flag instead.
For more details, consult the Xtensa C and C++ Compiler User’s Guide and the GNU
Assembler User’s Guide.
The fourth way to control the placement of code and data is to rename sections in exist-
ing object files and libraries using xt-objcopy. This is similar to the last method, but
may be more appropriate when dealing with existing libraries.
For example, suppose you want to place any code pulled from the C library into instruc-
tion RAM, place any associated literals (if using PC-relative literals) into data RAM, and
leave other sections in their default location. You can do this by renaming sections within
the C library as follows.
mkdir tmp
xt-objcopy -p --rename-section .text=.iram0.text \
--rename-section .literal=.dram0.literal \
<xtensa_root>/xtensa-elf/lib/libc.a tmp/libc.a
where <xtensa_root> is the location of your Xtensa core package8. The -p flag to
xt-objcopy is optional: it tells it to preserve timestamps of the library file itself and of
its archive members.
Telling the linker to use an alternate version of a library or object file specified by the
LSP specs file, such as the C library, is best done using the -L <searchdir> flag to
xt-xcc or xt-ld. This tells the linker to look in the specified directory ahead of its stan-
dard search path (see relevant compiler or linker documentation for more details). Place
your alternate library in a separate directory free of other unwanted files, and add that di-
rectory to the linker search path, e.g., -L tmp for the above example. Except when
carefully crafting very explicit linker invocations (e.g. using -nostdlib), extending the
linker search path is generally better than just adding the alternate library to the link line,
otherwise the LSP’s reference to the library still points to the default one.
For more details on the compiler driver and linker, consult the Xtensa C and C++ Com-
piler User’s Guide and the GNU Linker User’s Guide.
If you want to rename sections of only some object files within a library, one of the sim-
plest methods may be to extract all files from the library archive, run xt-objcopy on
relevant files, and put all files back in an updated library archive. For example:
rm -rf tmp
mkdir tmp
cd tmp
xt-ar x .../mylibrary.a
xt-objcopy -p --rename-section .text=.iram0.text file1.o
xt-objcopy -p --rename-section .text=.iram0.text file2.o
xt-objcopy -p --rename-section .text=.iram0.text file3.o
xt-ar crs .../newlibrary.a *.o
cd ..
where "..." are appropriate paths to the libraries, and file1.o through file3.o are
members of the mylibrary.a library archive.
For more details on xt-objcopy and xt-ar, consult the GNU Binary Utilities User’s
Guide.
8. Hint: Assuming your XTENSA_SYSTEM and XTENSA_CORE environment variables are set up appropriately, you can find
out the path to this directory using xt-xcc --show-config=config .
Finally, the fifth way to control the placement of code and data is to edit the memory
map. This allows changing the location and ordering of the various sections, perhaps
adding and removing sections, memory segments, and memories. By itself, this method
is very coarse, only allowing moving large sections such as all the application’s code or
all the application’s initialized data. It is often used in combination with one or more of
the first three methods, which allow placing specific functions, global variables, or sec-
tions of specific object files.
See Section 2.2 and Section 2.3 for details on creating an LSP and generating new
linker scripts after modifying a memory map, and Section 2.4 for memory map syntax.
For example, let us modify the memory map shown in Section 2.7 on page 39 to move
default sections to local memories9. The edited memory map might read as follows:
BEGIN dport0
0x3ffc0000: dataPort : dport0 : 0x20000 : writable ;
dport0_0:C: 0x3ffc0000-0x3ffdffff : .dport0.rodata .dport0.literal
.dport0.data .dport0.bss ;
END dport0
BEGIN dram0
0x3ffe0000: dataRam : dram0 : 0x20000 : writable ;
dram0_0:C: 0x3ffe0000-0x3fffffff : .dram0.rodata .rodata .lit4
.dram0.literal .iram0.literal
.literal .dram0.data .data
.dram0.bss .bss ;
END dram0
BEGIN iram0
0x40000000: instRam : iram0 : 0x20000 : executable, writable ;
iram0_0:C: 0x40000000-0x4001ffff : .iram0.text .text ;
END iram0
BEGIN srom
0x50000000: sysrom : srom : 0x1000000 : executable ;
srom0:F: 0x50000000-0x500002ff : .ResetVector.text ;
srom1:C: 0x50000300-0x50ffffff : .srom.rodata .srom.literal
.srom.text .rom.store ;
END srom
BEGIN sram
0x60000000: sysram : sram : 0x4000000 : executable, writable ;
sram0 :F: 0x60000000-0x60000177 : .WindowVectors.text;
9. The -mlocalmems option of xt-genldscripts or xt-regenlsps can also be used tor similar results. The example is for illustrative
purposes only.
The .rodata, .literal, .lit4, .text, .data, and .bss sections were moved from
segment sram19 of memory sram to memories iram0 and dram0. Thus, when using
this memory map’s LSP to build an application, the default location for the code is the in-
struction RAM, and the default location for all data and literals is the data RAM.
When program memory is scarce, one option is to partition the code into smaller chunks,
and move these chunks in and out of program memory as needed. Overlays provide the
mechanism to do this. Multiple overlay sections may be defined, and compiler directives
used to place code (no data) into specific overlay sections. The Automatic Xtensa Over-
lay Manager (AXOM) handles the mapping and unmapping of overlay sections automat-
ically. However, the placement of code into specific sections is a manual task.
#define MAIN_OVERLAY 0
DECLARE_OVERLAY(MAIN_OVERLAY);
The corresponding LSP changes are controlled by the OVERLAYS and OVERLAY_ALIGN
keywords. See the Xtensa System Software Reference Manual for more details.
Each cache attribute map is a simple 32-bit integer, where each 4-bit nibble from least to
most significant correspond to each of the eight regions from address 0 and up. These
32-bit values can be passed directly to a number of Xtensa HAL functions, such as
xthal_set_cacheattr(). See the Cache section of the HAL chapter in the Xtensa
System Software Reference Manual for more details on these and related functions.
Note that on cores with an RPU or MMU, each nibble corresponds to the 4-bit memory
attribute to be set; on cores with an MPU, each nibble takes one of the following values:
0 illegal access
1 cacheable, writeback
2 cacheable, writeback no-write-allocate
3 cacheable, write-through
4 bypass-cache (non-cacheable)
To compute the cache attributes, each of the eight regions are initially marked as un-
used. All memories defined in the memory map are then considered. Regions containing
local memories are marked non-cacheable. Then, any region containing non-local mem-
ories without the device attribute is marked cacheable. Then, any region containing a
memory that has the device attribute is marked non-cacheable. Thus, a region contain-
ing both device and non device memories is marked non-cacheable; although this re-
sults in lower performance accesses to a PIF-accessible memory that otherwise can be
cached, non-cached accesses are typically required for a device. A properly laid out
memory map avoids placing memories and devices with conflicting cache attribute re-
quirements in the same 512 MB region.
10. For Tensilica processors configured with an MPU (RG releases and later), or configured with a full MMU (RB releases and earlier), the processor
memory map is not organized as a set of eight 512 MB memory regions. In this case, the default cache attributes described in this section are not
applicable, and thus not generated.
These three values get mapped to the most appropriate cache attribute for the particular
attribute map variant and configured processor. Regions marked non-cacheable are put
in cache bypass mode. Regions marked cacheable are made writeback cacheable if a
writeback cache is available, writethrough cacheable otherwise, or cache bypass if no
cache is configured. Unused regions are set in one of three patterns:
allvalid All unused regions are put in cache bypass
mode (uncached).
strict All unused regions are made inaccessible
(illegal access mode).
trapnull All unused regions are put in cache bypass
mode, with one exception: if the first region
(at address zero) is unused, it is made inac-
cessible. This is to help catch NULL pointer
dereference bugs, yet leave most of the ad-
dress space open for access without having
to enable them explicitly.
The resulting 32-bit attribute maps are placed into the generated linker script as a series
of symbols, each of which is assigned a 32-bit value. Note that unlike most symbols that
refer to code, data, and such, these attribute map symbols do not correspond to ad-
dresses. The symbols are as follows:
_memmap_cacheattr_wb_<pat> These are the attribute maps described
above, where <pat> is one of the three pat-
terns (allvalid, strict, trapnull).
_memmap_cacheattr_wt_<pat> As above, except any writeback attribute is
made writethrough instead.
_memmap_cacheattr_bp_<pat> As above, except any cached (writeback or
writethrough) attribute is made uncached
(cache bypass) instead.
_memmap_cacheattr_wba_trapnull Like _memmap_cacheattr_wb_trap-
null, except that any writeback region is
made writeback write-allocate.
_memmap_cacheattr_wbna_trapnull Like _memmap_cacheattr_wb_trap-
null, except that any writeback region is
made writeback no-write-allocate if that at-
tribute is available (only on RC release or
later processors configured with Region
Protection, with or without Translation).
_memmap_cacheattr_reset This is by default assigned to match the
_memmap_cacheattr_wb_trapnull
symbol. See below.
PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);
This can be overridden on the linker command line to select a specific attribute map, or
one of the other generated symbols. For example, to force all region to remain uncached
on a processor configured with Region Protection (where bypass mode is attribute 2):
or
xt-xcc [...other options...] -Wl,--defsym,_memmap_cacheattr_reset=0x22222222
or
xt-xcc [...other options] \
-Wl,--defsym,_memmap_cacheattr_reset=0 \
-Wl,--defsym,_memmap_cacheattr_reset=_memmap_cacheattr_wt_trapnull
For details on available access modes, also known as memory attributes, refer to the
Memory-Management Model chapter of the relevant Xtensa Microprocessor Data Book,
or the Options for Memory Protection and Translation chapter of the Xtensa Instruction
Set Architecture (ISA) Reference Manual.
The ROMING Boolean parameter in memory maps (see Section 2.4 on page 26) enables
generation of special linker scripts used to construct a ROM image. Sections located in
RAM can be packed (stored) in a specific segment, such as in ROM. At system startup
time, reset code copies each of these sections from its packed locations to its proper lo-
cation in RAM. This is particularly useful, for example, for initialized data sections such
as .data that have initial content yet must be writable, and for sections containing code
for vectors located in RAM.
This feature takes advantage of ELF program headers which distinguish a section’s vir-
tual address (the address at which it was linked) from its load address (the address at
which it is loaded, or where it will usually be placed when converting an ELF binary to an
S-record file or simple binary file for eventual programming into ROM or Flash memory).
When this is done, all sections contained in writable memories (memories with the
writable attribute), except sections in the destination segment itself, are packed into
the destination segment at the point where the .rom.store pseudo-section is placed.
All other sections have matching virtual and load addresses, that is, they are not
packed.
ROMING=true
Here is an example taken from the example memory map of Section 2.7 on page 39:
This is the segment where sections will be packed. Ensure that the segment containing
the .rom.store pseudo-section is large enough to hold the application. As usual, this
range must not overlap with any other segment in the containing memory.
When these additions are made to the memory map, the linker scripts generated by
xt-genldscripts instantiate a table beginning at symbol _rom_store_table (this
symbol is at address zero for LSPs that don’t have the table, i.e., that don’t set the
ROMING parameter). This table describes the source and destination of each packed
section. Each entry in the table includes three fields: the start and end addresses at
which the code or data must reside during the execution of the application, as well as
the start address at which the code or data is initially located in ROM.
Most third-party RTOS reset vectors contain the correct unpacking code. (Some RTOS’,
such as ThreadX, use the startup code provided by the toolchain, in this case XTOS. In
this case, refer to the previous paragraph.) Otherwise, see below.
If you write your own reset vector code, make sure it unpacks sections to their appropri-
ate memory locations before they are used. Example working reset code is in Xtensa
Tools (in <xtensa_tools_root>/xtensa-elf/src/xtos/reset-vector.S near
the unpack label). Here is a similar example:
unpackdone:
If the processor is configured with writeback caches, unpacked code must be forced out
of the data cache (to external memory) to be visible to the processor’s instruction fetch:
#include <xtensa/coreasm.h>
#include <xtensa/cacheasm.h>
dcache_writeback_all a2, a3
icache_sync a2
If any code is unpacked in a region of memory close enough to code already executed
to have been cached in the instruction cache (in most reset handlers this does not hap-
pen), the instruction cache must be invalidated before running any unpacked code:
icache_invalidate_all a2, a3
Refer to the Xtensa Microprocessor Programmer’s Guide for more information on this
unpacking process.
This chapter provides examples of modifying components of an LSP other than the
memory map.
As mentioned earlier in Section 1.1.3, crt* is the C/C++ runtime initialization code. The
code first performs the necessary initialization and then it invokes main. The code also
provides _exit, a routine that terminates the execution of the program.
Three versions of crt* are provided: crt1-sim.S for the instruction set simulator,
crt1-boards.S for hardware environments such as the XTAV60 or XTAV200 emula-
tion board, and crt1-tiny.S which is used by the tiny LSP. Adding new functionality
to this code is fairly simple. This section describes how to change crt1-boards.S and
how to use the modified code with a custom LSP.
Note: The example as given only works with the windowed ABI, not with the call0 ABI.
You must modify register allocation accordingly to use this example with the call0 ABI.
In this example, we change the startup code so that it prints a message upon return from
main(). It displays “Test result: PASSED” if main returns 0, and “Test result:
FAILED” otherwise. The source file is located in <xtensa_tools_root>/xtensa-
elf/src/xtos/crt1-boards.S. Copy this file to another location, so as to leave the
original intact. Edit the copy as follows:
Find the line that calls exit(), just after the call to main(), near the end of the file:
CALL exit
Copy the output object file (crt1-boards.o) into the desired LSP’s directory. For ex-
ample, let us say an LSP was created in /home/user/myboard (e.g. by invoking
xt-regenlsps -mlsp=xtav60-rt -b /home/user/myboard, for a processor
configuration targeted to the XTAV60 board). In this case, copy crt1-boards.o into
/home/user/myboard. Finally, recompile the application program with that LSP:
The myapp application is now using the new crt1-boards.S, and thus will print the
appropriate message just before it terminates.
The libgloss library (see Section 1.1.1 on page 2), named as an acronym for GNU
Low-level Operating System Support library, implements simplified or stub versions of
system call layer functions such as open(), read(), write(), close(), sbrk() for
use in embedded targets. The libgloss library is typically a part of newlib, an open-
sourced implementation of the standard C library. However, Cadence provides its own
implementation of this library, shared by the supported C libraries: newlib and xclib.
The libgloss sources are located in the Xtensa Tools installation, in this directory:
<xtensa_tools_root>/xtensa-elf/src/libgloss.
To modify these sources, copy the entire libgloss source tree to another location, and
make your changes there. Modifying an installed Xtensa Tools is not recommended.
mkdir -p <objdir>
cd <objdir>
3. Rebuild libgloss; <libgloss_src> is the location of libgloss sources:
xt-make -f <libgloss_src>/Makefile.src
You can copy the resulting object files (for example, libgloss.a) to your LSP’s direc-
tory, thus limiting your changes to that specific LSP. Assuming the LSP’s specs file ref-
erences the libraries you copied to the LSP directory, they will automatically be picked
up when that LSP is used to link the application. (This can be disabled using the -nost-
dlib option).
Index