Skip to content

Commit 5c45b52

Browse files
amodrampe
authored andcommitted
powerpc/modules: Fix alignment of .toc section in kernel modules
powerpc64 gcc can generate code that offsets an address, to access part of an object in memory. If the address is a -mcmodel=medium toc pointer relative address then code like the following is possible. addis r9,r2,var@toc@ha ld r3,var@toc@l(r9) ld r4,(var+8)@toc@l(r9) This works fine so long as var is naturally aligned, *and* r2 is sufficiently aligned. If not, there is a possibility that the offset added to access var+8 wraps over a n*64k+32k boundary. Modules don't have any guarantee that r2 is sufficiently aligned. Moreover, code generated by older compilers generates a .toc section with 2**0 alignment, which can result in relocation failures at module load time even without the wrap problem. Thus, this patch links modules with an aligned .toc section (Makefile and module.lds changes), and forces alignment for out of tree modules or those without a .toc section (module_64.c changes). Signed-off-by: Alan Modra <[email protected]> [desnesn: updated patch to apply to powerpc-next kernel v4.15 ] Signed-off-by: Desnes A. Nunes do Rosario <[email protected]> [mpe: Fix out-of-tree build, swap -256 for ~0xff, reflow comment] Signed-off-by: Michael Ellerman <[email protected]>
1 parent acb1fea commit 5c45b52

File tree

3 files changed

+20
-5
lines changed

3 files changed

+20
-5
lines changed

arch/powerpc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ UTS_MACHINE := $(subst $(space),,$(machine-y))
6363
ifdef CONFIG_PPC32
6464
KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
6565
else
66+
KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/powerpc/kernel/module.lds
6667
ifeq ($(call ld-ifversion, -ge, 225000000, y),y)
6768
# Have the linker provide sfpr if possible.
6869
# There is a corresponding test in arch/powerpc/lib/Makefile

arch/powerpc/kernel/module.lds

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* Force alignment of .toc section. */
2+
SECTIONS
3+
{
4+
.toc 0 : ALIGN(256)
5+
{
6+
*(.got .toc)
7+
}
8+
}

arch/powerpc/kernel/module_64.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,11 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
339339
char *p;
340340
if (strcmp(secstrings + sechdrs[i].sh_name, ".stubs") == 0)
341341
me->arch.stubs_section = i;
342-
else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0)
342+
else if (strcmp(secstrings + sechdrs[i].sh_name, ".toc") == 0) {
343343
me->arch.toc_section = i;
344+
if (sechdrs[i].sh_addralign < 8)
345+
sechdrs[i].sh_addralign = 8;
346+
}
344347
else if (strcmp(secstrings+sechdrs[i].sh_name,"__versions")==0)
345348
dedotify_versions((void *)hdr + sechdrs[i].sh_offset,
346349
sechdrs[i].sh_size);
@@ -373,12 +376,15 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
373376
return 0;
374377
}
375378

376-
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
377-
gives the value maximum span in an instruction which uses a signed
378-
offset) */
379+
/*
380+
* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this gives the
381+
* value maximum span in an instruction which uses a signed offset). Round down
382+
* to a 256 byte boundary for the odd case where we are setting up r2 without a
383+
* .toc section.
384+
*/
379385
static inline unsigned long my_r2(const Elf64_Shdr *sechdrs, struct module *me)
380386
{
381-
return sechdrs[me->arch.toc_section].sh_addr + 0x8000;
387+
return (sechdrs[me->arch.toc_section].sh_addr & ~0xfful) + 0x8000;
382388
}
383389

384390
/* Both low and high 16 bits are added as SIGNED additions, so if low

0 commit comments

Comments
 (0)