Skip to content

Commit f3b7e73

Browse files
iii-ihcahca
authored andcommitted
s390/module: fix loading modules with a lot of relocations
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: f19fbd5 ("s390: introduce execute-trampolines for branches") Cc: [email protected] Reported-by: Andrea Righi <[email protected]> Signed-off-by: Ilya Leoshkevich <[email protected]> Reviewed-by: Heiko Carstens <[email protected]> Cc: Vasily Gorbik <[email protected]> Cc: Christian Borntraeger <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent 3d787b3 commit f3b7e73

File tree

1 file changed

+18
-19
lines changed

1 file changed

+18
-19
lines changed

arch/s390/kernel/module.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
#define DEBUGP(fmt , ...)
3434
#endif
3535

36-
#define PLT_ENTRY_SIZE 20
36+
#define PLT_ENTRY_SIZE 22
3737

3838
void *module_alloc(unsigned long size)
3939
{
@@ -341,27 +341,26 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
341341
case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
342342
case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
343343
if (info->plt_initialized == 0) {
344-
unsigned int insn[5];
345-
unsigned int *ip = me->core_layout.base +
346-
me->arch.plt_offset +
347-
info->plt_offset;
348-
349-
insn[0] = 0x0d10e310; /* basr 1,0 */
350-
insn[1] = 0x100a0004; /* lg 1,10(1) */
344+
unsigned char insn[PLT_ENTRY_SIZE];
345+
char *plt_base;
346+
char *ip;
347+
348+
plt_base = me->core_layout.base + me->arch.plt_offset;
349+
ip = plt_base + info->plt_offset;
350+
*(int *)insn = 0x0d10e310; /* basr 1,0 */
351+
*(int *)&insn[4] = 0x100c0004; /* lg 1,12(1) */
351352
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_disable) {
352-
unsigned int *ij;
353-
ij = me->core_layout.base +
354-
me->arch.plt_offset +
355-
me->arch.plt_size - PLT_ENTRY_SIZE;
356-
insn[2] = 0xa7f40000 + /* j __jump_r1 */
357-
(unsigned int)(u16)
358-
(((unsigned long) ij - 8 -
359-
(unsigned long) ip) / 2);
353+
char *jump_r1;
354+
355+
jump_r1 = plt_base + me->arch.plt_size -
356+
PLT_ENTRY_SIZE;
357+
/* brcl 0xf,__jump_r1 */
358+
*(short *)&insn[8] = 0xc0f4;
359+
*(int *)&insn[10] = (jump_r1 - (ip + 8)) / 2;
360360
} else {
361-
insn[2] = 0x07f10000; /* br %r1 */
361+
*(int *)&insn[8] = 0x07f10000; /* br %r1 */
362362
}
363-
insn[3] = (unsigned int) (val >> 32);
364-
insn[4] = (unsigned int) val;
363+
*(long *)&insn[14] = val;
365364

366365
write(ip, insn, sizeof(insn));
367366
info->plt_initialized = 1;

0 commit comments

Comments
 (0)