How should I use relative (small) addressing?
An efficient method for quick data access is the so-called register-relative addressing. The linker must place all the variables that are addressed relatively to the same base within a 64-kilobyte area, a so-called Small Data Area (SDA). This must be guided by the user, who provides a linker script that places all those special small addressing sections within a 64K area. Additionally, the linker script must provide a special symbol that marks the middle of the SDA. This symbol has two purposes: first, the linker uses it as a reference when resolving the small addressing related relocations. Second, the startup code will use the symbol as the base address to initialize the corresponding System Global Address Register, which happens before any of the small data objects are accessed.
Linker script with .sdata/.sbbs output sections description
SECTIONS
{
/* Short-addresable data - non-initialized */
.sbss (NOLOAD) : ALIGN(4)
{
PROVIDE(__SMALL_DATA__ = . + 0x8000);
*(.sbss)
*(.sbss.*)
*(.bss_a0)
*(.bss_a0.*)
. = ALIGN(4);
} > DATA_SDA0
/* Short-addresable data - initialized */
.sdata : ALIGN(4)
{
*(.sdata)
*(.sdata.*)
*(.data_a0)
*(.data_a0.*)
. = ALIGN(4);
} > DATA_SDA0 AT > RODATA
}
The basic registers are A0, A1, A8, and A9; these are initialized during start-up. The assignment of the corresponding output section is as follows.
Name | Register |
---|---|
.sdata/.sbbs |
A0 |
.sdata2/.sbss2 |
A1 |
.sdata3/.sbss3 |
A8 |
.sdata4/.sbss4 |
A9 |
Within the start-up code, the corresponding address registers are initialized with the symbol _SMALL_DATA_
. The following snippet of the start-up code shows the initialization:
movh.a %a0,hi: _SMALL_DATA_ # %a0 addresses .sdata/.sbss
lea %a0,[%a0]lo: _SMALL_DATA_
movh.a %a1,hi: _SMALL_DATA2_ # %a1 addresses .sdata2/.sbss2
lea %a1,[%a1]lo: _SMALL_DATA2_
movh.a %a8,hi: _SMALL_DATA3_ # %a8 addresses .sdata3/.sbss3
lea %a8,[%a8]lo: _SMALL_DATA3_
movh.a %a9,hi: _SMALL_DATA4_ # %a9 addresses .sdata4/.sbss4
lea %a9,[%a9]lo: _SMALL_DATA4_
Address calculation is carried out by adding or subtracting an offset value to or from the corresponding basis address register. The -msmall=<size-limit>
compiler option allows a size limit for register relative (small) addressing to be controlled from the outside. For more details, please refer to the Small Addressing Mode chapter in [1].