diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2014-03-18 19:59:26 +1030 |
---|---|---|
committer | Anton Blanchard <anton@samba.org> | 2014-04-23 10:05:29 +1000 |
commit | 4edebbeae3085e71f75584b6582495459e2e6cb2 (patch) | |
tree | bd272a73d1150e63bf3a1e86489f81d267dabbc7 /arch/powerpc/kernel | |
parent | 71ec7c55ed91e2352c00d51d171fccaa7cef5a00 (diff) | |
download | linux-4edebbeae3085e71f75584b6582495459e2e6cb2.tar.gz linux-4edebbeae3085e71f75584b6582495459e2e6cb2.tar.bz2 linux-4edebbeae3085e71f75584b6582495459e2e6cb2.zip |
powerpc: Fix up TOC. for modules.
The kernel resolved the '.TOC.' to a fake symbol, so we need to fix it up
to point to our .toc section plus 0x8000.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/module_64.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index a8694d462079..f6544d7071d6 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -196,6 +196,24 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) } } +static Elf64_Sym *find_dot_toc(Elf64_Shdr *sechdrs, + const char *strtab, + unsigned int symindex) +{ + unsigned int i, numsyms; + Elf64_Sym *syms; + + syms = (Elf64_Sym *)sechdrs[symindex].sh_addr; + numsyms = sechdrs[symindex].sh_size / sizeof(Elf64_Sym); + + for (i = 1; i < numsyms; i++) { + if (syms[i].st_shndx == SHN_UNDEF + && strcmp(strtab + syms[i].st_name, ".TOC.") == 0) + return &syms[i]; + } + return NULL; +} + int module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs, char *secstrings, @@ -337,6 +355,17 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, DEBUGP("Applying ADD relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); + + /* First time we're called, we can fix up .TOC. */ + if (!me->arch.toc_fixed) { + sym = find_dot_toc(sechdrs, strtab, symindex); + /* It's theoretically possible that a module doesn't want a + * .TOC. so don't fail it just for that. */ + if (sym) + sym->st_value = my_r2(sechdrs, me); + me->arch.toc_fixed = true; + } + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr |