reprocess libc/ldso RELA relocations in stage 3 of dynamic linking
authorRich Felker <dalias@aerifal.cx>
Mon, 18 May 2015 20:51:54 +0000 (16:51 -0400)
committerRich Felker <dalias@aerifal.cx>
Mon, 18 May 2015 20:51:54 +0000 (16:51 -0400)
this fixes a regression on powerpc that was introduced in commit
f3ddd173806fd5c60b3f034528ca24542aecc5b9. global data accesses on
powerpc seem to be using a translation-unit-local GOT filled via
R_PPC_ADDR32 relocations rather than R_PPC_GLOB_DAT. being a non-GOT
relocation type, these were not reprocessed after adding the main
application and its libraries to the chain, causing libc code not to
see copy relocations in the main program, and therefore to use the
pre-copy-relocation addresses for global data objects (like environ).

the motivation for the dynamic linker only reprocessing GOT/PLT
relocation types in stage 3 is that these types always have a zero
addend, making them safe to process again even if the storage for the
addend has been clobbered. other relocation types which can be used
for address constants in initialized data objects may have non-zero
addends which will be clobbered during the first pass of relocation
processing if they're stored inline (REL form) rather than out-of-line
(RELA form).

powerpc generally uses only RELA, so this patch is sufficient to fix
the regression in practice, but is not fully general, and would not
suffice if an alternate toolchain generated REL for powerpc.

src/ldso/dynlink.c

index 7c92ef6cd28f6e8d80383c356e1210c35a4b7595..93595a0f62e58c2a7df7ddcdfa377800f0a50266 100644 (file)
@@ -281,7 +281,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                }
 
                int gotplt = (type == REL_GOT || type == REL_PLT);
-               if (dso->rel_update_got && !gotplt) continue;
+               if (dso->rel_update_got && !gotplt && stride==2) continue;
 
                addend = stride>2 ? rel[2]
                        : gotplt || type==REL_COPY ? 0