# Dynamic linking Dynamic linking involves loading objects into an application program (and linking them) at runtime rather than compile time. The mechanics of shared object loading are specific to the target operating system. Hexagon object files use the same data structures for dynamic linking that are used in the System V ABI. Shared objects are often intended to be referenced by more than one client object, which requires that their code be executable in a reentrant manner. Reentrant objects are commonly implemented by maintaining separate instances of the object data section for each reference to the shared object. The mechanism used for creating multiple data section instances is implementation-defined. Here are two examples of how the data sections can be implemented: 1. The object loader marks all pages for a data section as read-only, and relies on the virtual memory manager to create write-able copies of the pages, which are written to privately from the calling-process context (a policy known as *copy-on-write*). 2. The object loader creates a new instance of the shared object for each reference. ## Dynamic section In addition to supporting the standard ELF dynamic array tags, Hexagon object files can also include processor-specific dynamic array tags to support dynamic linking. The following table lists the processor-specific dynamic array tags (along with the standard ELF dynamic array tag DT\_PLTGOT): - Name – Specifies the name of the tag. - Value – Specifies the numeric identifier of the tag. - d\_un – Specifies whether the tag represents an integer or program virtual address. (d\_un is the name of a union that is used to store elements in a dynamic section.) - Executable – Specifies whether or not the dynamic linking array for an executable object file must contain a tag entry of the specified type. Optional indicates that an entry can appear in the array, but is not required. - Shared object – Specifies whether or not the dynamic linking array for a shared object file must contain a tag entry of the specified type. **Dynamic array tags** | **Name** | **Value** | **d\_un** | **Executable** | **Shared object** | | --- | --- | --- | --- | --- | | DT\_PLTGOT | 0x00000003 | d\_ptr | Optional | Optional | | DT\_HEXAGON\_SYMSZ | 0x70000000 | d\_val | Optional | Optional | | DT\_HEXAGON\_VER | 0x70000001 | d\_val | Mandatory | Mandatory | | DT\_HEXAGON\_PLT | 0x70000002 | d\_val | Optional | Optional | These tags have the following descriptions: - DT\_PLTGOT – Image offset of the GOT ([Global offset table](https://docs.qualcomm.com/doc/80-N2040-23/topic/dynamic-linking.html#global-offset-table)). - DT\_HEXAGON\_SYMSZ – Size (in bytes) of the symbol table pointed by DT\_SYMTAB. This value is equivalent to the value of DT\_SYMENT multiplied by the value of field nchain in the hash table pointed by DT\_HASH. - DT\_HEXAGON\_VER – Version of interface with dynamic linker ([Procedure linkage table](https://docs.qualcomm.com/doc/80-N2040-23/topic/dynamic-linking.html#linkage-table)). Currently, it can be set to the integer value 2 or 3. For the object to be compatible with the Hexagon ABI, it must be set to 3. The default is 2. - DT\_HEXAGON\_PLT – Image offset of the PLT ([Procedure linkage table](https://docs.qualcomm.com/doc/80-N2040-23/topic/dynamic-linking.html#linkage-table)). ## Global offset table The global offset table (GOT) is an array of absolute addresses which enables an object to use position-independent code. At load-time, the relocations related to GOT-relative dynamic symbols are resolved, and the GOT is populated with their absolute addresses. The zero’th GOT entry (index = 0) is reserved for holding the address of the dynamic structure, which is referenced through the symbol \_DYNAMIC. The three subsequent entries are reserved for use by the dynamic linker. The GOT is referenced through the symbol \_GLOBAL\_OFFSET\_TABLE\_. It can reside anywhere in the section, .got, and it can accept positive and negative indexes given its declaration as: extern Elf32_Addr \_GLOBAL_OFFSET_TABLE\_ []; Copy to clipboard Note Any change to the format of the GOT will be reflected in DT\_HEXAGON\_VER ([Dynamic section](https://docs.qualcomm.com/doc/80-N2040-23/topic/dynamic-linking.html#dynamic-section)). ## Procedure linkage table The procedure linkage table (PLT) enables execution transfers from one object to another, with the resolution of function symbols performed at runtime. Each object that references external functions has a PLT, which is composed of an array of stubs for each of the external functions. The dynamic linker determines the absolute addresses of the destinations and stores them in the GOT, from which they are loaded by the stub code in the PLT entry. A relocation table is associated with the PLT. The DT\_JMPREL tag in the \_DYNAMIC array indicates the location of the first relocation entry. The relocation table entries, after any reserved entry, match the PLT entries in a one-to-one correspondence – for example, relocation table entry 16 applies to the 16th PLT entry after the reserved PLT entries. The relocation type associated with each non-reserved PLT entry must be R\_HEX\_JMP\_SLOT. The relocation offset must specify the address of a GOT entry containing the address of the function, and the symbol table index must reference the appropriate symbol. The resolution of external function symbols is beyond the scope of this specification; however, the PLT is designed to allow on-demand resolution of such symbols. In other words, the external function symbols need not be resolved before execution begins: each symbol is resolved only when it is called (a policy known as *lazy binding*, which avoids the overhead of resolving and relocating symbols that are never called). The interface between the PLT and dynamic linker is performed via registers R14 and R15, which respectively contain the PLT relocation table entry index and the object identification. Additionally, R28 is available for use as a scratch register by the PLT stub code. The details of the PLT are implementation-defined. For example, the following code example presents a possible PLT design, with the first four entries reserved for interfacing with the dynamic linker to perform lazy binding. .PLT0: // entry reserved for dyn linker r15 = pc // address of .PLT0 r28.h = #hi (.PLT0@GOT) // offset of .PLT0 from GOT r28.l = #lo (.PLT0@GOT) r28 = sub (r15, r28) // address of GOT r15 = memw (r28 + #8) // object ID at GOT [2] r14 = sub (r14, r28) // offset of @GOT from GOT .PLT1: // entry reserved for dyn linker r14 = add (r14, #-16) // subtract reserved PLT entries r14 = asr (r14, #2) // index of PLT relocation r28 = memw (r28 + #4) // dynamic linker at GOT [1] jumpr r28 // call dynamic linker nop nop .PLT2: // entry reserved for dyn linker ... .PLT3: // entry reserved for dyn linker ... .PLT4: // entry for name1 r15 = pc // address of .PLT4 r14.h = #hi (name1’s GOT - .PLT4) // offset of name1 GOT from entry r14.l = #lo (name1’s GOT - .PLT4) r14 = add (r15, r14) // address of name1 GOT r28 = memw (r14) // contents of name1 GOT jumpr r28 // call it .PLT5: // entry for name2 r15 = pc r14.h = #hi (name2’s GOT - .PLT5) r14.l = #lo (name2’s GOT - .PLT5) r14 = add (r15, r14) r28 = memw (r14) jumpr r28 .PLT6: ... Copy to clipboard Note For details on the @GOT suffix see [Assembler symbols](https://docs.qualcomm.com/doc/80-N2040-23/topic/coding-examples.html#assembler-symbols). The following steps are assumed in resolving external function symbols. This procedure uses 24- byte long PLT entries. 1. The program loader sets the second entry of the GOT to the address of the dynamic linker (in order to resolve external function symbols), and the third entry of the GOT to some identifying information unique to the object. 2. The linker initializes the first few PLT entries reserved to it with code that will marshal arguments to the dynamic linker. In this example, the code at the beginning of the first PLT entry finds the offset from it to the GOT (as set by the linker). The offset is then used to calculate the absolute address of the GOT. Register R14 is set to index into the PLT relocation table for function name1, and R15 is set to the object ID. The address of the dynamic linker is loaded from a GOT entry and called. 3. When the function name1 is called, execution is transferred to its assigned PLT entry (in this example, .PLT4). 4. The PLT entry contains a stub that sets R15 to its address and then calculates the address of the GOT entry for the symbol, name1. Control is then transferred indirectly to the contents of this GOT entry, which initially contains the address of the first PLT entry (.PLT0). 5. The preceding PLT code example is executed, starting at label .PLT0. With the PLT entry index for name1 and its corresponding GOT entry offset, the dynamic linker can find the associated relocation entry for the symbol, whose offset points to the GOT entry for the symbol, and whose symbol index points to the function symbol (name1 in this example). 6. When the dynamic linker resolves the symbol name1, it modifies the GOT entry associated with its PLT entry with its actual address, and then transfers control to it. Subsequent calls to name1 land immediately at its address (after a stop at its PLT entry), but without calling the dynamic linker again. Note Any change to the interface with the dynamic linker will be reflected in DT\_HEXAGON\_VER ([Dynamic section](https://docs.qualcomm.com/doc/80-N2040-23/topic/dynamic-linking.html#dynamic-section)). Last Published: Oct 06, 2026 [Previous Topic Program headers](https://docs.qualcomm.com/bundle/publicresource/80-N2040-23/topics/program-headers.md) [Next Topic Thread-local storage](https://docs.qualcomm.com/bundle/publicresource/80-N2040-23/topics/thread-local-storage.md)