mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-04 09:59:32 +00:00
s390/module: fix loading modules with a lot of relocations
commitf3b7e73b2c
upstream. If the size of the PLT entries generated by apply_rela() exceeds 64KiB, the first ones can no longer reach __jump_r1 with brc. Fix by using brcl. An alternative solution is to add a __jump_r1 copy after every 64KiB, however, the space savings are quite small and do not justify the additional complexity. Fixes:f19fbd5ed6
("s390: introduce execute-trampolines for branches") Cc: stable@vger.kernel.org Reported-by: Andrea Righi <andrea.righi@canonical.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Cc: Vasily Gorbik <gor@linux.ibm.com> Cc: Christian Borntraeger <borntraeger@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a3aa4850b3
commit
2025d5cb38
1 changed files with 17 additions and 18 deletions
|
@ -33,7 +33,7 @@
|
|||
#define DEBUGP(fmt , ...)
|
||||
#endif
|
||||
|
||||
#define PLT_ENTRY_SIZE 20
|
||||
#define PLT_ENTRY_SIZE 22
|
||||
|
||||
void *module_alloc(unsigned long size)
|
||||
{
|
||||
|
@ -340,27 +340,26 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
|||
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
|
||||
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
|
||||
if (info->plt_initialized == 0) {
|
||||
unsigned int insn[5];
|
||||
unsigned int *ip = me->core_layout.base +
|
||||
me->arch.plt_offset +
|
||||
info->plt_offset;
|
||||
unsigned char insn[PLT_ENTRY_SIZE];
|
||||
char *plt_base;
|
||||
char *ip;
|
||||
|
||||
insn[0] = 0x0d10e310; /* basr 1,0 */
|
||||
insn[1] = 0x100a0004; /* lg 1,10(1) */
|
||||
plt_base = me->core_layout.base + me->arch.plt_offset;
|
||||
ip = plt_base + info->plt_offset;
|
||||
*(int *)insn = 0x0d10e310; /* basr 1,0 */
|
||||
*(int *)&insn[4] = 0x100c0004; /* lg 1,12(1) */
|
||||
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
|
||||
unsigned int *ij;
|
||||
ij = me->core_layout.base +
|
||||
me->arch.plt_offset +
|
||||
me->arch.plt_size - PLT_ENTRY_SIZE;
|
||||
insn[2] = 0xa7f40000 + /* j __jump_r1 */
|
||||
(unsigned int)(u16)
|
||||
(((unsigned long) ij - 8 -
|
||||
(unsigned long) ip) / 2);
|
||||
char *jump_r1;
|
||||
|
||||
jump_r1 = plt_base + me->arch.plt_size -
|
||||
PLT_ENTRY_SIZE;
|
||||
/* brcl 0xf,__jump_r1 */
|
||||
*(short *)&insn[8] = 0xc0f4;
|
||||
*(int *)&insn[10] = (jump_r1 - (ip + 8)) / 2;
|
||||
} else {
|
||||
insn[2] = 0x07f10000; /* br %r1 */
|
||||
*(int *)&insn[8] = 0x07f10000; /* br %r1 */
|
||||
}
|
||||
insn[3] = (unsigned int) (val >> 32);
|
||||
insn[4] = (unsigned int) val;
|
||||
*(long *)&insn[14] = val;
|
||||
|
||||
write(ip, insn, sizeof(insn));
|
||||
info->plt_initialized = 1;
|
||||
|
|
Loading…
Reference in a new issue