Add relocation handling required for -zifunc-noplt to work on arm64.

Static relocations for the immediate operand of a branch instruction
must be applied.

In a patch which implements LSE-based atomic(9) operations using ifuncs,
-zifunc-noplt reduces system CPU usage during a buildkernel by several
percent.

Also fix elf_reloc_internal() to return an error if symbol lookup fails.

Reviewed by:	andrew
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D17392
This commit is contained in:
Mark Johnston 2020-01-21 17:45:49 +00:00
parent f01fe060e6
commit 9ddf3d342b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356947

View File

@ -124,6 +124,23 @@ elf_is_ifunc_reloc(Elf_Size r_info __unused)
return (ELF_R_TYPE(r_info) == R_AARCH64_IRELATIVE);
}
static int
reloc_instr_imm(Elf32_Addr *where, Elf_Addr val, u_int msb, u_int lsb)
{
/* Check bounds: upper bits must be all ones or all zeros. */
if ((uint64_t)((int64_t)val >> (msb + 1)) + 1 > 1)
return (-1);
val >>= lsb;
val &= (1 << (msb - lsb + 1)) - 1;
*where |= (Elf32_Addr)val;
return (0);
}
/*
* Process a relocation. Support for some static relocations is required
* in order for the -zifunc-noplt optimization to work.
*/
static int
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
int type, int local, elf_lookup_fn lookup)
@ -159,10 +176,33 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
return (0);
}
error = 0;
switch (rtype) {
case R_AARCH64_NONE:
case R_AARCH64_RELATIVE:
break;
case R_AARCH64_TSTBR14:
error = lookup(lf, symidx, 1, &addr);
if (error != 0)
return (-1);
error = reloc_instr_imm((Elf32_Addr *)where,
addr + addend - (Elf_Addr)where, 15, 2);
break;
case R_AARCH64_CONDBR19:
error = lookup(lf, symidx, 1, &addr);
if (error != 0)
return (-1);
error = reloc_instr_imm((Elf32_Addr *)where,
addr + addend - (Elf_Addr)where, 20, 2);
break;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
error = lookup(lf, symidx, 1, &addr);
if (error != 0)
return (-1);
error = reloc_instr_imm((Elf32_Addr *)where,
addr + addend - (Elf_Addr)where, 27, 2);
break;
case R_AARCH64_ABS64:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
@ -181,7 +221,7 @@ elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
printf("kldload: unexpected relocation type %d\n", rtype);
return (-1);
}
return (0);
return (error);
}
int