]> git.karo-electronics.de Git - linux-beck.git/commitdiff
powerpc: Fix up TOC. for modules.
authorRusty Russell <rusty@rustcorp.com.au>
Tue, 18 Mar 2014 09:29:26 +0000 (19:59 +1030)
committerAnton Blanchard <anton@samba.org>
Wed, 23 Apr 2014 00:05:29 +0000 (10:05 +1000)
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>
arch/powerpc/include/asm/module.h
arch/powerpc/kernel/module_64.c

index 49fa55bfbac4fba38f26368cbbdcdf1513aa590c..c9c7aaaf95f5f83e3afd892183e9b18d38ceb0af 100644 (file)
@@ -35,6 +35,7 @@ struct mod_arch_specific {
 #ifdef __powerpc64__
        unsigned int stubs_section;     /* Index of stubs section in module */
        unsigned int toc_section;       /* What section is the TOC? */
+       bool toc_fixed;                 /* Have we fixed up .TOC.? */
 #ifdef CONFIG_DYNAMIC_FTRACE
        unsigned long toc;
        unsigned long tramp;
index a8694d4620790551cd51fe78fda5984ff622858a..f6544d7071d6b2a086bab27960f10f4cda65d99a 100644 (file)
@@ -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