What goes into the Target?
When we compile an Embedded program, the code is transformed into a binary file, a format that can be downloaded into the target hardware for execution.
The transformed binary code usually contains 4 types of code items in it arranged together as specified by the developer.
The 4 different program sections in a binary file (or a program) are,
- .text - segment for executable instructions. Also known as Code segment.
- .bss - segment for uninitialized data . The stationery init code zeroes this area at startup.
- .data - segment for initialized data.
- .rodata - segment for constant data.
Note : The data referred in the .bss/.data/.rodata are the global variables. The local variables are "executable instructions" and they are part of .text section.
---------------------------------------------------------------------------------------------------------------
Where it goes in Target?
After the compilation is successfully completed, different code sections are still available as fragments.
The Linker binds these compiled fragments together and assigns them with the target hardware's address. This operation is called Linking. This is established with the help of the Linker Directives(.ld) file which instructs the linker on how to perform the linking operation.
Therefore the linker directives usually contain the different code segments and their respective memory addresses. The linker directives shall also include other information that is specific to the compiler or hardware architecture or the application.
In this blog, we will cover what is a linker directive file, its contents, and details about each directive based on the Green hills (GHS) toolchain and the memory models based on Renesas RH850.
--------------------------------------------------------------------------------------------------------------Linker Directives - GHS
Linker directives files (.ld) are used to define program sections,
and to assign them to specific addresses in memory. In this section, the structure and the contents of the GHS linker directive are explained.
These files may
contain the following directives (sections):
- OPTION - Specifies Linker options
- CONSTANTS - Sets constant values for use in memory and section maps.
- MEMORY - Defines a memory map by specifying the name, starting address, and size of memory regions.
- SECTIONS - Defines a section map by specifying the name, attributes, and address (memory locations) of program sections.
Below is an example of how the different sections in a linker directives file look. It also shows the default program sections that shall be present in a program. Custom linker directives shall be created based on the default linker directive file provided by the IDE.
Note: Comment lines are prefixed by a hash symbol (#).
# ==============================================================
OPTION ("-checksum -map")
CONSTANTS {
heap_reserve = 1M
stack_reserve = 512K
}
MEMORY {
dram_rsvd1 : ORIGIN = 0x80000000, LENGTH = 32K
dram_memory : ORIGIN = ., LENGTH = 10M-32K
dram_rsvd2 : ORIGIN = ., LENGTH = 0
flash_rsvd1 : ORIGIN = 0xbfc00000, LENGTH = 32K
flash_memory : ORIGIN = ., LENGTH = 10M - 32K
flash_rsvd2 : ORIGIN = ., LENGTH = 0
}
SECTIONS {
# Section for executable instructions from user code.
.text : > dram_memory
# These 5 symbols are necessary for internal GHS operation.
.syscall : > .
.secinfo : > .
.fixaddr : > .
.fixtype : > .
.profile : > .
# Sections for various data from user code.
.robase ALIGN(8) : > .
.rodata : > .
.data : > .
.bss : > .
.heap ALIGN(8) PAD(heap_reserve) : > .
.stack ALIGN(8) PAD(stack_reserve) : > .
# These special symbols mark the bounds of RAM and ROM memory.
# They are used by the MULTI debugger.
__ghs_ramstart = MEMADDR(dram_rsvd1);
__ghs_ramend = MEMENDADDR(dram_rsvd2);
__ghs_romstart = MEMADDR(flash_rsvd1);
__ghs_romend = MEMENDADDR(flash_rsvd2);
}
# ==============================================================
--------------------------------------------------------------------------------------------------------------Now the Linker Directives in detail.
The OPTION Directive
To include command-line options in a linker
directives file. The syntax is,
OPTION ("option")
Example 1. Using the OPTION Directive
To specify the -checksum and -map options in a linker directives file, add the following line:
OPTION
("-checksum -map")
To use the OPTION directive to specify files to be
linked, using the following syntax:
OPTION ("file_name")
--------------------------------------------------------------------------------------------------------------
The CONSTANTS Directive
To specify the constants for use in a linker directives file. The syntax is,
CONSTANTS {name=value}
Example 2. Using the CONSTANTS Directive
To set the constant foo to the value 0x2000 in a .ld file, add the following line:
CONSTANTS
{foo=0x2000}
Multiple constants can be specified, separated by a
semicolon,
CONSTANTS
{foo=0x2000; bar=0x4000}
Constants specified in this manner can be used in place
of absolute values in section and memory maps.
--------------------------------------------------------------------------------------------------------------
The MEMORY Directive (Memory Maps)
The linker uses a memory map to define regions of memory,
to which the sections of the executable can be assigned. A memory map
is formatted as follows:
MEMORY
{
...
memname: ORIGIN=origin_expression, LENGTH=length_expression
...
}
where:
memname - Specifies the name of a
memory region.
origin_expression - Specifies
the starting address of the memory region.
length_expression - Specifies
the length of the memory region.
All three of these elements must be specified for each
region to produce a valid memory map. If a memory map is passed to the linker, only the memory
regions named and defined in it can be referenced in an associated section
map.
Example 3. Format of a Memory Map
The linker directives file, memory.ld contains the following memory map:
MEMORY
{
dram_memory
: ORIGIN = 0, LENGTH = 4M
flash_memory
: ORIGIN = 0x40000000, LENGTH = 1024K
internal_memory
: ORIGIN = 0xffff8000, LENGTH = 0x2000
alt_reset
: ORIGIN = 0xfff00100, LENGTH = 256
}
Note: Use “M” (meaning megabyte) and “K” (meaning kilobyte ) in memory
maps, as shown in the first two lines of the example above.
--------------------------------------------------------------------------------------------------------------
The SECTIONS Directive (Section Maps)
The linker uses a section map to write program sections
in the executable to particular memory regions. A section map is formatted as
follows:
SECTIONS
{
...
secname [start_expression] [attributes] : [{ contents }] [> memname]
...
}
where,
secname -
Specifies the name of a section
start_expression -
Specifies
the starting address of the section.
If omitted, the section starts at the next
available address. Usually, this is the address immediately after the previous section. However, if a memory map has been specified and there is not enough space
to hold the section in the current memory region, the linker will search for the
next valid area of memory (specified in the memory map) into which the section
will fit.
The starting address may be further modified to fit the alignment constraints of the subsections included by contents.
attributes -
Specifies the attributes of the section. Any number of attributes shall be included. The list of attributes is detailed separately on this page.
contents -
Specifies
section inclusion commands and assignments. There is no limit to the number
of commands and assignments.
Section
inclusion commands are of the form filename(secname), which directs that the section secname
from filename should be included. To include the section secname from all files, use
{*(secname)}. Leaving the {contents} section empty is also equivalent to adding {*(secname)}.
The special variable dot (“.”), represents the current
offset within the section. You can
assign symbols to dot using the syntax “symbol=.;”. You can create holes in the section using the dot. For example, “.+=0x100;” would create a 0x100 byte hole or
a gap inside a section.
memname
Allocates
the section to memory region memname, which is pre-defined in the memory map.
If both
a start_expression and a memname memory region are specified
in a line in the section
map, then the start_expression takes precedence. If more
than one section is assigned to a memname memory region, the section that
appears first in the section map will be written to that region first.
All sections in input files that participate in memory the layout must be referenced in the section map.
Example 4. Format of a Section Map
The linker directives file, sections.ld contains the following section map,
which references certain of the named memory regions.
SECTIONS
{
#
RAM SECTIONS
.data
: > dram_memory
.bss
: >.
.heap
ALIGN(16) MIN_SIZE(stack_reserve) : >.
.stack
ALIGN(16) MIN_SIZE(heap_reserve) : >.
#
ROM SECTIONS
.ROM.data
ROM(.data) : > flash_memory
.text
: >.
.syscall
: >.
.rodata
: >.
}
In this example, .data is written to the memory region dram_memory. Since no memory region is specified for .bss, this section will be written to dram_memory, directly after .data.
Example 5. Including and Renaming Sections
The section map lines given in this example demonstrate
the syntax of the most commonly used forms of section inclusion. For the sake of
clarity, only the executable section name and the { contents } argument are given.
.data :{*(.data)}
.data :
The first line above includes the .data sections from all object files in the .data
section of the
executable. Since the executable section and the object file sections have the same name, it is not necessary to
specify a { contents } argument in this case, and the syntax given in the second
line is sufficient.
.newdata :{*(.data)}
The line above includes the .data sections from all object files in the .newdata
section of the
executable.
.newdata
:{foo.o(.data) bar.o(.data)}
The line above includes the .data sections from foo.o and then bar.o in the .newdata
section of the
executable. The .data sections from all other object files are included, by default, in the .data section of the executable.
.newtext
:{lib.a(foo.o(.text))}
The line above includes the .text section from the object file foo.o contained within lib.a in the .newtext section of the executable. The .text sections from all other object files are included, by default, in
the .text section of the executable.
.newbss
:{lib.a(*(.bss))}
The line above includes the .bss section from all object files contained within lib.a in the .newbss
section of the
executable. The .bss sections from all other object files are included, by default, in the .bss section of the executable.
Note: Library filenames are case-sensitive. You may give just
the library name, rather than a full path.
--------------------------------------------------------------------------------------------------------------
SECTION ATTRIBUTES
The following section attributes can be used to configure the section behavior:
ABS
Sets a
flag in the output file that indicates that this section has an absolute
address and
should not be moved. Program loaders and other utilities, that manipulate the output-image should not include this section in any movement related to position independent code or position independent data.
CLEAR / NOCLEAR
Sets or
removes the CLEAR attribute of the section. If CLEAR is present, an entry
is made in the run-time clear table, which is often used by startup code to initialize memory regions to a particular value.
The CLEAR attribute is set by default for.bss section or other such data sections (we will see other sections similar to .bss later).
PAD (value)
Places value bytes of padding at the
beginning of the section. This is equivalent to
specifying padding at the beginning of the section contents.
Example: The
following two definitions are equivalent:
.stack pad(0x10000)
: {}
.stack : { . +=
0x10000; }
ROM (sect_name)
CROM (sect_name)
These
attributes allocate the contents of a section, sect_name, to ROM at link time,
while reserving space for the data to be copied to RAM at startup.
MIN_SIZE (size)
Instructs
the linker to pad, if necessary, to ensure that the section is at least size bytes in length.
MIN_ENDADDRESS(address)
Instructs
the linker to pad, if necessary, to ensure that the section extends to at
least address.
MAX_SIZE(size)
Indicates
that an error should be generated if the section exceeds size bytes in
length.
MAX_ENDADDRESS(address)
Indicates
that an error should be generated if the section extends beyond address during
final layout.
Example 6. Using CLEAR and NOCLEAR
The section map is by default set to CLEAR:
.sbss NOCLEAR :
The line above overrides the default CLEAR attribute of .sbss.
.mysbss NOCLEAR
:{*(SMALLCOMMONS)}
The line above disables the default clearing that results for SMALLCOMMONS:
.heap CLEAR
PAD(0x10000):
The line above causes the heap, which is normally
uninitialized, to be cleared at startup.
Example 7. Using ROM
A section created with this attribute will
inherit the attributes and contents of the original section. The original section is
marked uninitialized; that is, it is modified to reserve address space only, as
if it were all padding with no contents.
To place the .data section in ROM with instructions to
have it copied to RAM at startup, you would include, as a minimum, the
following lines in your section map:
.data :
...
.ROM.data ROM(.data)
:
An entry is automatically made in the ROM copy table to
ensure that during program startup the ROM image of .ROM.data is copied into the space reserved for .data.
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
Memory Model - Renesas/RH850
The Renesas RH850 and the V850 architectures, support the following memory models,
- Normal data: The default memory model, where all data is placed within the data area and is accessed using normal load and store operations.
- Small data: Data is assigned either automatically by the compiler or manually by the user (or both) into a small data area and is referenced using a reserved register (r4) as a base pointer, allowing for smaller code for data accesses. The total size of the Small is limited to 64 Kbytes.
- Zero data: Similar to Small data, although the zero-register (r0) is used as the base register to access data within 16 bits of address 0. The total size of the Tiny Data Area is limited to 4 Kbytes.
- Tiny data: Data is assigned by the user into small sections accessed using the Tiny Data Area (TDA) base register (ep) and the V850 short load/store operations providing for the smallest possible code for data accesses. The total size of the Tiny Data Area is limited to 4 Kbytes.
The usage of Small Data Area (SDA), Zero Data Area (ZDA), and Tiny Data Area (TDA) improve the program size and speed because addressing objects in this area requires fewer instructions. The developer can assign different initialized, non-initialized, and constant data to each of these small/zero/tiny data areas.
To accommodate these memory models and assigning different data into these Data areas, the linker directive file is prepared with specific information for each data area.
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
GHS program sections for RH850 memory models
Based on the RH850 memory model, the various program sections for the data are given below,
Memory Allocation for Initialized Variables - data, sdata, tdata, zdata.
Memory Allocation for Un-initialized Variables - bss, sbss, zbss.
Memory Allocation for Constant Variables - rodata, rosdata, rozdata.
Only initialized data are placed in the TDA. Therefore only tdata section can be added in the linker directives file.
The developer shall include any or all these program sections in their linker directives file and assign them memory locations.
--------------------------------------------------------------------------------------------------------------The developer shall include any or all these program sections in their linker directives file and assign them memory locations.
uk0pr-46
EXAMPLE TO BE ADDED.
ADVANCED LD FEATURES TO BE ADDED.
Useful information in simple language...
ReplyDeleteThank you.
ReplyDeleteI got the basic and needed information thanks a lot
ReplyDeleteHello Author,
ReplyDeleteThe above information is really informative.
In case you have a manual/pdf to the same content, will it be possible to share it.
I need to explore on other fields as well.
Hi, I do not have the manual/pdf with me. But if you are using GHS compiler, the manual comes with the installation.
Delete