==== MIPS IFUNC ABI specification ==== Introduction ---- This document describes the working of GNU indirect functions(IFUNC) for MIPS. Terminology ---- Shared file or shared object refers to any object file with e_type ET_DYN. Unless otherwise distinguished, this includes dynamic shared libraries (PIC) and position-independent executables (PIE). Executable file or executable refers to any object file with e_type ET_EXEC. Unless otherwise distinguished, this includes statically linked and dynamically linked executables. Relocations for IFUNC resolution ---- The relocation table may now contain a new relocation type generated by the static linker: R_MIPS_IRELATIVE(128) This relocation marks the location of an IFUNC indirection that needs to be resolved by the dynamic linker at load time. The resolution step calls the IFUNC resolver function given at the relocation offset possibly with additional processor-specific (hardware capability) arguments and writes the address returned by the resolver back to the relocation offset. GOT and IGOT sections - the indirection table ---- An IRELATIVE fix-up will target the existing GOT entry of the symbol, except in the following cases: 1. Symbols defined in executable files have no GOT entries. 2. Symbols defined in a shared object, but not referenced within that object have no GOT entries. If the symbol has no GOT entry, an entry is allocated in the IGOT section and used by the fix-up. This GOT/IGOT entry is initialized to point to the resolver function at link time and modified to point to the resolved function by the IRELATIVE fix-up. IPLT section - indirection stubs ---- The IFUNC Procedure Linkage Table (IPLT) consists of a set of stubs generated by the static linker to stand in for IFUNC references that can not be resolved via a GOT/IGOT entry, for example: 1. Internal or external IFUNC references in an executable file where there is no GOT section. 2. External references in shared objects where the resolver function cannot be invoked at load time due to the specific order of loading. Executable files contain non-PIC stubs and shared objects contain PIC-style stubs. Non-PIC stubs can be called using absolute JAL instruction and then redirect the call to the actual function via an absolute pointer in to the GOT (or IGOT) section. PIC stubs provide the same functionality, but they must be called using the SVr4 PIC ABI [JALR $25]. The redirection is done via a full 32-bit (or 64-bit) relative offset from $25 in to the GOT (or IGOT) section. In either case, the actual position of the GOT/IGOT relative to the IPLT section or $gp is irrelevant. For executable files, IFUNC calls are always routed through IPLT stubs. Every IFUNC definition must have a corresponding stub irrespective of its declared visibility. For shared objects, the dynamic linker must decide whether or not to route through the stub for each external IFUNC references in each object. Only externally visible IFUNC definitions needs stubs; no stubs are generated for definitions with static or non-default (STV_HIDDEN/STV_INTERNAL) visibility. Issues specific to shared objects ==== External IFUNC resolution ---- If an external IFUNC reference binds to a resolver within another object which has not been relocated at the time when the caller object is loaded, it is not possible to invoke this IFUNC resolver to determine the resolved function. In this case, the dynamic linker must fall back to binding that reference to the appropriate IPLT stub. When the callee object is eventually loaded, its GOT entry would be updated to the resolved function. When the IPLT stub is executed, it will simply pick the resolved address from GOT and jump to it. This scheme requires the ability to map the dynamic symbol of an IFUNC to the address of its IPLT stub. This mapping is achieved by sorting all global IFUNC symbols to be contiguous within the dynamic symbol table and using a pair of dynamic tags: MIPS_IPLT: address of the first IPLT stub MIPS_IFUNC_INDX: index of the first dynamic IFUNC symbol. For any dynamic IFUNC symbol, the difference of its index and MIPS_IFUNC_INDEX, scaled by the size of an IPLT stub and added back to MIPS_IPLT address yields that symbol's corresponding IPLT stub. PIC stub size varies with architecture and ISA as follows: - mips16/micromips32: 16 bytes - mips32 o32: 20 bytes - mips64 n32: 20 bytes - mips64 n64: 36 bytes ** With further optimization, it may be possible to reduce the sizes of o32/n32 stubs to 16 bytes and n64 stubs to 32 bytes. dynsym table - dynamic symbol order ---- For mapping unresolvable IFUNC references to IPLT stubs, all IFUNC symbols must be sorted to appear contiguous within the dynamic symbol table. Entries in the dynamic symbol table are sorted as - unreferenced symbols - GOT referenced symbols - reloc-only symbols. To remain consistent with the internal order of symbols, the dynamic symbol table is sorted in to 2 contiguous IFUNC sequences, so that order is: - unreferenced regular symbols - unreferenced IFUNC symbols - GOT-referenced IFUNC symbols - GOT-referenced regular symbols - reloc-only regular symbols - reloc-only IFUNC symbols In this way, the relative meta-order of the 3 symbol categories is maintained. The first contiguous sequence of IFUNC symbols is marked by the tag MIPS_IFUNC_INDX, with MIPS_IPLT pointing to the start address of the corresponding IPLT stub sequence. The 2nd contiguous sequence is marked by the tag MIPS_IFUNCREL_INDX, with MIPS_IPLTREL pointing to the start address of the corresponding stub sequence. The 2nd sequence and its dynamic tags are only needed in the multi-GOT case, where a single primary GOT is insufficient. Dynamic Section ---- Dynamic section entries give information to the dynamic linker. The following new dynamic table entries are required for IFUNC resolution: MIPS_IPLT(36) Address of the first IPLT stub. This tag is needed for all shared objects with global IFUNC symbols. MIPS_IFUNC_INDX(37) Index of the first dynamic IFUNC symbol. This tag is needed for all shared objects with global IFUNC symbols. MIPS_IPLTREL(38) Address of the IPLT stub of the first IFUNC symbol with a reloc-only GOT entry. This tag is needed for all shared objects with global IFUNC symbols and multiple GOTs. MIPS_IFUNCREL_INDX(39) Index of the first dynamic IFUNC symbol with a reloc-only GOT entry. This tag is needed for all shared objects with global IFUNC symbols and multiple GOTs.