With the linker script generation mechanism, it is possible to specify these placements at the component level within ESP-IDF. The component presents
information on how it would like to place its symbols, objects or the entire archive. During build the information presented by the components are collected,
parsed and processed; and the placement rules generated is used to link the app.
- a component named ``my_component`` that is archived as library ``libmy_component.a`` during build
- three source files archived under the library, ``my_src1.c``, ``my_src2.c`` and ``my_src3.c`` which are compiled as ``my_src1.o``, ``my_src2.o`` and ``my_src3.o``, respectively
- under ``my_src1.o``, the function ``my_function1`` is defined; under ``my_src2.o``, the function ``my_function2`` is defined
- there exist bool-type config ``PERFORMANCE_MODE`` (y/n) and int type config ``PERFORMANCE_LEVEL`` (with range 0-3) in my_component's Kconfig
Creating and Specifying a Linker Fragment File
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Before anything else, a linker fragment file needs to be created. A linker fragment file
is simply a text file with a ``.lf`` extension upon which the desired placements will be written.
After creating the file, it is then necessary to present it to the build system. The instructions for the build systems
Continuing our example, suppose that among functions defined under ``object1.o``, only ``my_function1`` is performance-critical; and under ``object2.o``,
only ``my_function2`` needs to execute after the chip comes out of deep sleep. This could be accomplished by writing:
There are :ref:`limitations<ldgen-symbol-granularity-placements>` in placing code/data at symbol granularity. In order to ensure proper placements, an alternative would be to group
relevant code and data into source files, and :ref:`use object-granularity placements<ldgen-placing-object-files>`.
Suppose that the entire component library should only have special placement when a certain condition is true; for example, when ``CONFIG_PERFORMANCE_MODE == y``.
For a more complex config-dependent placement, suppose the following requirements: when ``CONFIG_PERFORMANCE_LEVEL == 1``, only ``object1.o`` is put in RAM;
Up until this point, the term 'default placements' has been mentioned as fallback placements for when the
placement rules ``rtc`` and ``noflash`` are not specified. It is important to note that the tokens ``noflash`` or ``rtc`` are not merely keywords, but are actually
entities called fragments, specifically :ref:`schemes<ldgen-scheme-fragment>`.
Linking is the last step in the process of turning C/C++ source files into an executable. It is performed by the toolchain's linker, and accepts
linker scripts which specify code/data placements, among other things. With the linker script generation mechanism, this process is no different, except
that the linker script passed to the linker is dynamically generated from: (1) the collected :ref:`linker fragment files<ldgen-linker-fragment-files>` and
As mentioned in the quick start guide, fragment files are simple text files with the ``.lf`` extension containing the desired placements. This is a simplified
description of what fragment files contain, however. What fragment files actually contain are 'fragments'. Fragments are entities which contain pieces of information which, when put together, form
placement rules that tell where to place sections of object files in the output binary. There are three types of fragments: :ref:`sections<ldgen-sections-fragment>`,
:ref:`scheme<ldgen-scheme-fragment>` and :ref:`mapping<ldgen-mapping-fragment>`.
Condition checking enable the linker script generation to be configuration-aware. Depending on whether expressions involving configuration values
are true or not, a particular set of values for a key can be used. The evaluation uses ``eval_string`` from :idf_file:`tools/kconfig_new/kconfiglib.py`
and adheres to its required syntax and limitations. Supported operators are as follows:
- comparison
- LessThan ``<``
- LessThanOrEqualTo ``<=``
- MoreThan ``>``
- MoreThanOrEqualTo ``>=``
- Equal ``=``
- NotEqual ``!=``
- logical
- Or ``||``
- And ``&&``
- Negation ``!``
- grouping
- Parenthesis ``()``
Condition checking behaves as you would expect an ``if...elseif/elif...else`` block in other languages. Condition-checking is possible
for both key values and entire fragments. The two sample fragments below are equivalent:
..code-block:: none
# Value for keys is dependent on config
[type:name]
key_1:
if CONDITION = y:
value_1
else:
value_2
key_2:
if CONDITION = y:
value_a
else:
value_b
..code-block:: none
# Entire fragment definition is dependent on config
if CONDITION = y:
[type:name]
key_1:
value_1
key_2:
value_b
else:
[type:name]
key_1:
value_2
key_2:
value_b
**Comments**
Comment in linker fragment files begin with ``#``. Like in other languages, comment are used to provide helpful descriptions and documentation
and are ignored during processing.
Compatibility with ESP-IDF v3.x Linker Script Fragment Files
ESP-IDF v4.0 brings some changes to the linker script fragment file grammar:
- indentation is enforced and improperly indented fragment files generate a parse exception; this was not enforced in the old version but previous documentation
and examples demonstrates properly indented grammar
- move to ``if...elif...else`` structure for conditionals, with the ability to nest checks and place entire fragments themselves inside conditionals
- mapping fragments now requires a name like other fragment types
Linker script generator should be able to parse ESP-IDF v3.x linker fragment files that are indented properly (as demonstrated by
the ESP-IDF v3.x version of this document). Backward compatibility with the previous mapping fragment grammar (optional
name and the old grammar for conditionals) has also been retained but with a deprecation warning. Users should switch to the newer grammar discussed
in this document as support for the old grammar is planned to be removed in the future.
Note that linker fragment files using the new ESP-IDF v4.0 grammar is not supported on ESP-IDF v3.x, however.
Types
"""""
.._ldgen-sections-fragment :
**Sections**
Sections fragments defines a list of object file sections that the GCC compiler emits. It may be a default section (e.g. ``.text``, ``.data``) or
it may be user defined section through the ``__attribute__`` keyword.
The use of an optional '+' indicates the inclusion of the section in the list, as well as sections that start with it. This is the preferred method over listing both explicitly.
Symbol granularity placements is possible due to compiler flags ``-ffunction-sections`` and ``-ffdata-sections``. ESP-IDF compiles with these flags by default.
If the user opts to remove these flags, then the symbol-granularity placements will not work. Furthermore, even with the presence of these flags, there are still other limitations to keep in mind
due to the dependence on the compiler's emitted output sections.
For example, with ``-ffunction-sections``, separate sections are emitted for each function; with section names predictably constructed i.e. ``.text.{func_name}``
and ``.literal.{func_name}``. This is not the case for string literals within the function, as they go to pooled or generated section names.
With ``-fdata-sections``, for global scope data the compiler predictably emits either ``.data.{var_name}``, ``.rodata.{var_name}`` or ``.bss.{var_name}``; and so ``Type I`` mapping entry works for these.
However, this is not the case for static data declared in function scope, as the generated section name is a result of mangling the variable name with some other information.
The linker script template is the skeleton in which the generated placement rules are put into. It is an otherwise ordinary linker script, with a specific marker syntax
that indicates where the generated placement rules are placed.
To reference the placement rules collected under a ``target`` token, the following syntax is used:
The example below is an excerpt from a possible linker script template. It defines an output section ``.iram0.text``, and inside is a marker referencing
the target ``iram0_text``.
..code-block:: none
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
/* Marker referencing iram0_text */
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
Suppose the generator collected the fragment definitions below:
..code-block:: none
[sections:text]
.text+
.literal+
[sections:iram]
.iram1+
[scheme:default]
entries:
text -> flash_text
iram -> iram0_text
[scheme:noflash]
entries:
text -> iram0_text
[mapping:freertos]
archive: libfreertos.a
entries:
* (noflash)
Then the corresponding excerpt from the generated linker script will be as follows:
..code-block:: c
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
/* Placement rules generated from the processed fragments, placed where the marker was in the template */