7.9.5. Linux Position-Independent Code
Every position-independent code (PIC) function which uses global data or global functions must load the value of the GOT pointer into a register. Any available register may be used. If a caller-saved register is used the function must save and restore it around calls. If a callee-saved register is used it must be saved and restored around the current function. Examples in this document use r22 for the GOT pointer.
The GOT pointer is loaded using a PC-relative offset to the _gp_got symbol, as shown below.
Loading the GOT Pointer
nextpc r22 1: orhi r1, %hiadj(_gp_got - 1b) # R_NIOS2_PCREL_HA _gp_got addi r1, r1, %lo(_gp_got - 1b) # R_NIOS2_PCREL_LO _gp_got - 4 add r22, r22, r1 # GOT pointer in r22
Data may be accessed by loading its location from the GOT. A single word GOT entry is generated for each referenced symbol.
Small GOT Model Entry for Global Symbols
addi r3, r22, %got(x) # R_NIOS2_GOT16 GOT[n] R_NIOS2_GLOB_DAT x
Large GOT Model Entry for Global Symbols
movhi r3, %got_hiadj(x) # R_NIOS2_GOT_HA addi r3, r3, %got_lo(x) # R_NIOS2_GOT_LO add r3, r3, r22 GOT[n] R_NIOS2_GLOB_DAT x
For local symbols, the symbolic reference to x is replaced by a relative relocation against symbol zero, with the link time address of x as an addend, as shown in the example below.
Local Symbols for small GOT Model
addi r3, r22, %got(x) # R_NIOS2_GOT16 GOT[n] R_NIOS2_RELATIVE +x
Local Symbols for large GOT Model
movhi r3, %got_hiadj(x) # R_NIOS2_GOT_HA addi r3, r3, %got_lo(x) # R_NIOS2_GOT_LO add r3, r3, r22 GOT[n] R_NIOS2_RELATIVE +x
The call and jmpi instructions are not available in position-independent code. Instead, all calls are made through the GOT. Function addresses may be loaded with %call, which allows lazy binding. To initialize a function pointer, load the address of the function with %got instead. If no input object requires the address of the function its GOT entry is placed in the PLT GOT for lazy binding, as shown in the example below.
For information about the PLT, refer to the "Procedure Linkage Table" section.
Small GOT Model entry in PLT GOT
ldw r3, %call(fun)(r22) # R_NIOS2_CALL16 fun callr r3 PLTGOT[n] R_NIOS_JUMP_SLOT fun
Large GOT Model entry in PLT GOT
movhi r3, %call_hiadj(x) # R_NIOS2_CALL_HA addi r3, r3, %call_lo(x) # R_NIOS2_CALL_LO add r3, r3, r22 ldw r3, 0(r3) callr r3 PLTGOT[n] R_NIOS_JUMP_SLOT fun
When a function or variable resides in the current shared object at compile time, it can be accessed via a PC-relative or GOT-relative offset, as shown below.
Accessing Function or Variable in Current Shared Object
orhi r3, %gotoff_hiadj(x) # R_NIOS2_GOTOFF_HA x addi r3, r3, %gotoff_lo(x) # R_NIOS2_GOTOFF_LO x add r3, r22, r3 # Address of x in r3
Multiway branches such as switch statements can be implemented with a table of GOT-relative offsets, as shown below.
Switch Statement Implemented with Table
# Scaled table offset in r4 orhi r3, %gotoff_hiadj(Ltable) # R_NIOS2_GOTOFF_HA Ltable addi r3, r3, %gotoff_lo(Ltable) # R_NIOS2_GOTOFF_LO Ltable add r3, r22, r3 # r3 == &Ltable add r3, r3, r4 ldw r4, 0(r3) # r3 == Ltable[index] add r4, r4, r22 # Convert offset into destination jmp r4 ... Ltable: .word %gotoff(Label1) .word %gotoff(Label2) .word %gotoff(Label3)
Did you find the information on this page useful?