This is the minimum set of required changes to support a non-executable GOT and PLT segment and SELinux restrictions on never allowing writable areas to become executable nor executable areas to become writable. It leaves us backward compatible with old shared libraries. o GOT needs to be made non-exec. A non-exec GOT means we can't execute the blrl insn in the GOT to load the GOT pointer register for -fpic code. Instead of using "bl got-4; mflr 30", use bcl 20,31,1f 1: mflr 30 addis 30,30,(got-1b)@ha addi 30,30,(got-1b)@l This example assumes r30 is being used as the GOT pointer. "got" is shorthand for the value of the symbol _GLOBAL_OFFSET_TABLE_. This will require addition of R_PPC_REL16_HA and R_PPC_REL16_LO relocs, support for them in ld, and of course gcc changes to generate the new code to load the GOT register. -fPIC GOT pointer code can also benefit from the new relocs. The .got section will be placed before .data so that it may be made read-only after relocatation. This placement is incompatible with the use of the GOT pointer to address .sdata using short offsets in shared libraries, so this feature of the SYSV ABI is no longer supported. With the new GOT layout, three locations are reserved. got[0] will be initialised to the link-time address of .dynamic by ld, got[1] will be initialised to the address of dl_runtime_resolve by ld.so, and got[2] will be initialised to the map address by ld.so. got[-1] will no longer be reserved. o PLT should be split into two sections, one containing code which we'll call .glink, the other containing just data, which we'll call .plt. .glink will be generated by ld somewhere in the text segment, and contains a special symbol resolver stub, and a number of PLT call code stubs. The symbol resolver stub will call the dl_runtime_resolve function specified by got[1] with r11 set to the plt reloc offset, and r12 set to the value of got[2]. These stubs need not be adjacent to one another or unique, and can be scattered throughout the text segment so as to be reachable with a branch and link instruction. A possible implementation is: # Enter with .plt entry address in r11, got pointer in r30 PLTresolve: addis 11,11,(got-plt)@ha addi 11,11,(got-plt)@l sub 11,11,30 # r11 = index * 4 add 0,11,11 add 11,0,11 # r11 = index * 12 = reloc offset. lwz 0,4(30) # got[1] address of dl_runtime_resolve mtctr 0 lwz 12,8(30) # got[2] contains the map address bctr # ith PLT code stub. addis 11,30,(plt+(i-1)*4-got)@ha lwzu 0,(plt+(i-1)*4-got)@l(11) mtctr 0 bctr .plt will be a loaded section located after .got, and consists of an array of addresses. There will also be an array of R_PPC_JMP_SLOT relocs in .rela.plt, with a one-one correspondence between elements of each array. Each R_PPC_JMP_SLOT reloc will have r_offset pointing at the .plt word it relocates. To support lazy linking, ld will set each .plt word to point to the symbol resolver stub in .glink. On loading a shared library, ld.so should relocate the contents of .plt by adding the load address to each word in .plt. Note that this ABI does not specify a fixed GOT register, or even one register used throughout a binary. If a function uses a register other than r30 for the GOT register, it will be specified as r_addend = reg*4+2 on each R_PPC_PLTREL24 reloc used by calls. This of course will require the linker to generate different .glink code than the example implementation given here. To allow ld.so to support old shared libs, we need to flag a new got and plt layout, so we'll define a new dynamic tag, DT_PPC_GLINK which will be set to the link-time address of PLTresolve. The PLT change requires support in ld and ld.so, and gcc changes to ensure that the got pointer register is set properly whenever a call via the PLT may be necessary. The linker will detect the difference between old and new object files by looking at relocs. A new object file will always have R_PPC_REL16* relocs if it uses the GOT or makes calls that might need to go via the plt. An old file won't have these (new) relocs.