Monday, 6 August 2018

Linker Directives Basics - Based on the GHS/RH850 Toolchain

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_memorySince 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.
ExampleThe 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. 
--------------------------------------------------------------------------------------------------------------
uk0pr-46
EXAMPLE TO BE ADDED.

ADVANCED LD FEATURES TO BE ADDED.

5 comments:

  1. Useful information in simple language...

    ReplyDelete
  2. I got the basic and needed information thanks a lot

    ReplyDelete
  3. Hello Author,
    The 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.

    ReplyDelete
    Replies
    1. Hi, I do not have the manual/pdf with me. But if you are using GHS compiler, the manual comes with the installation.

      Delete

BREAKPOINTS

What is a Breakpoint.?           A  breakpoint   makes your program stop whenever a certain point in the program is reached. For each br...