18.2.4 Initialize Global Pointer

The compiler toolchain supports Global Pointer (gp) relative addressing. Loads and stores to data residing within 32KB of either side of the address stored in the gp register can be performed in a single instruction using the gp register as the base register. Without the Global Pointer, loading data from a static memory area takes two instructions – one to load the Most Significant bits of the 32-bit constant address computed by the compiler/linker and one to do the data load.

To utilize gp-relative addressing, the compiler and assembler must group all of the “small” variables and constants into one of the following sections:

.lit4. lit8
.sdata. sbss
.sdata.* sbss.*
.gnu.linkonce.s.* .gnu.linkonce.sb.*

The linker must then group all of the above input sections together. This grouping is handled by the default linker script. The run-time start-up code must initialize the gp register to point to the “middle” of this output section. To enable the start-up code to initialize the gp register, the linker script must initialize a variable which is 32 KB from the start of the output section containing the “small” variables and constants. This variable is named _gp (to match core linker scripts).

Some PIC32 MCUs have more than one register set. The additional register sets can be used as interrupt shadow register sets. The Global Pointer must be initialized in each of the register sets. The default start-up code does this by looping through each of the register sets.

In the loop, the CP0 SRSCtl register's PSS field must be set to the shadow set in which to initialize the global pointer. In the source code, we start with the highest register set, as defined by the PIC32_SRS_SET_COUNT macro, and work down to zero. By initializing the global pointer in the previous set as iterate through the register sets, we initialize the register in each of the sets on the device.