First, a bit of background on why these registers are needed. PPC is a RISC-like ISA, in that all instructions are of the same size (32 bits) and there is limited space for immediate values (usually 16 bits at most) that you would use for things like addresses. So how do you address more that 16 bits?
One option is to build addresses by 16-bit slices, e.g. something like:
lis r4,msg@ha # load top 16 bits of &msg
addi r4,r4,msg@l # add bottom 16 bits
Another is to use PIC (position-independent code) to address things relative to current address:
bcl 20, 4*cr7+so, loc_picbase #branch and link to next location
loc_picbase:
mflr r31 # load link register (lr) into r31. It will be equal to loc_picbase
addis r2, r31, (_NXArgc - loc_picbase)@ha
stw r28, (_NXArgc - loc_picbase)@l(r2)
<and so on>
However, using either of these requires multiple instructions per data access and is not always feasible (e.g. first variant would require patching instructions if binary needs to be relocated which can't be done when running read-only code). So on some platforms they came up with the concept of TOC (Table of Contents), which is a fixed register having the same value for the whole module and from which all data is addressed using an offset. The register r2
was reserved for this purpose and AFAIK is supposed to be set by the OS loader. Since offsets in PPC instructions are limited to 16 bits (-32768 to +32767), you can address about 64K of data around r2
(which is usually placed in the middle of the data area for maximum coverage). If the module needs more data, offsets bigger than 16 bits are constructed in several steps, or multiple TOCs may be used (in this case different functions may use different TOCs).
In PPC64 ABI, the latter is achieved by so-called function descriptors which is pairs of pointers where one is the address of the function's code and the other is the TOC value expected by the function. Any time a function is called, the TOC is loaded from the descriptor before jumping to the function's code (unless the compiler knows that the target function uses the same TOC value, in which case the TOC reload can be skipped).
In embedded environment, there is usually no OS but a monolithic firmware, and this concept is applied to the whole firmware by using register r13
for SDA (Small Data Area) and, if necessary, r2
for an additional data region (SDA2 -Small Data Area 2). A so-called Zero data area (ZDA) may be also used for data placed near the address 0 (using special addressing modes from register r0
).
Some compilers (notably Green Hills) support additional data pointers (r14
, r15
etc.).
In embedded environment, the data registers (r2
, r13
etc.) should be initialized in the startup code, shortly after reset, as the rest of the firmware usually expects them to have proper values.
P.S. usage of r2
depends on the environment. It's quite possible that the target environment you're compiling for does not use TOC so you don't see it used (stack pointer on PowerPC is r1
, not r2
).
Some references: