diff options
authorRich Felker <>2015-05-18 16:51:54 -0400
committerRich Felker <>2015-05-18 16:51:54 -0400
commitc093e2e8201524db0d638920e76bcb6b1d925f3a (patch)
parent43e9f652bf4b2195b04fc14c93db591b30a7b790 (diff)
reprocess libc/ldso RELA relocations in stage 3 of dynamic linking
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.
1 files changed, 1 insertions, 1 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 7c92ef6c..93595a0f 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -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