summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/module_64.c
diff options
context:
space:
mode:
authorRusty Russell2014-03-18 10:29:26 +0100
committerAnton Blanchard2014-04-23 02:05:29 +0200
commit4edebbeae3085e71f75584b6582495459e2e6cb2 (patch)
treebd272a73d1150e63bf3a1e86489f81d267dabbc7 /arch/powerpc/kernel/module_64.c
parentpowerpc: module: handle MODVERSION for .TOC. (diff)
downloadkernel-qcow2-linux-4edebbeae3085e71f75584b6582495459e2e6cb2.tar.gz
kernel-qcow2-linux-4edebbeae3085e71f75584b6582495459e2e6cb2.tar.xz
kernel-qcow2-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/module_64.c')
-rw-r--r--arch/powerpc/kernel/module_64.c29
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