Commit 049a68ef authored by Alexander Lobakin's avatar Alexander Lobakin Committed by Thomas Bogendoerfer
Browse files

MIPS: module: optimize module relocations processing



For now, module relocation functions are implemented as an array
of handlers of type reloc_handler_t.

Convert that array into a single switch-case function to:
 - remove unused arguments;
 - change the return type of simple handlers to void;
 - remove the array and don't use any data at all;
 - avoid using indirect calls;
 - allow the compiler to inline and greatly optimize
   the relocation function[s].

The result on MIPS32 R2 with GCC 10.2 -O2 is:

scripts/bloat-o-meter -c arch/mips/kernel/__module.o arch/mips/kernel/module.o
add/remove: 1/11 grow/shrink: 1/0 up/down: 876/-1436 (-560)
Function                                     old     new   delta
apply_relocate                               456    1148    +692
apply_r_mips_pc                                -     184    +184
apply_r_mips_none                              8       -      -8
apply_r_mips_32                               16       -     -16
apply_r_mips_64                               76       -     -76
apply_r_mips_highest                          88       -     -88
apply_r_mips_higher                          108       -    -108
apply_r_mips_26                              132       -    -132
apply_r_mips_pc26                            160       -    -160
apply_r_mips_pc21                            160       -    -160
apply_r_mips_pc16                            160       -    -160
apply_r_mips_hi16                            172       -    -172
apply_r_mips_lo16                            356       -    -356
Total: Before=2608, After=2048, chg -21.47%
add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0 (0)
Data                                         old     new   delta
Total: Before=12, After=12, chg +0.00%
add/remove: 0/1 grow/shrink: 0/0 up/down: 0/-248 (-248)
RO Data                                      old     new   delta
reloc_handlers                               248       -    -248
Total: Before=248, After=0, chg -100.00%

All functions were collapsed into a single one that is called
directly by $(srctree)/kernel/module.c.

Signed-off-by: default avatarAlexander Lobakin <alobakin@pm.me>
Reviewed-by: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
parent 76d7fff2
Loading
Loading
Loading
Loading
+52 −57
Original line number Original line Diff line number Diff line
@@ -40,22 +40,13 @@ void *module_alloc(unsigned long size)
}
}
#endif
#endif


static int apply_r_mips_none(struct module *me, u32 *location,
static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v)
			     u32 base, Elf_Addr v, bool rela)
{
	return 0;
}

static int apply_r_mips_32(struct module *me, u32 *location,
			   u32 base, Elf_Addr v, bool rela)
{
{
	*location = base + v;
	*location = base + v;

	return 0;
}
}


static int apply_r_mips_26(struct module *me, u32 *location,
static int apply_r_mips_26(struct module *me, u32 *location, u32 base,
			   u32 base, Elf_Addr v, bool rela)
			   Elf_Addr v)
{
{
	if (v % 4) {
	if (v % 4) {
		pr_err("module %s: dangerous R_MIPS_26 relocation\n",
		pr_err("module %s: dangerous R_MIPS_26 relocation\n",
@@ -75,8 +66,8 @@ static int apply_r_mips_26(struct module *me, u32 *location,
	return 0;
	return 0;
}
}


static int apply_r_mips_hi16(struct module *me, u32 *location,
static int apply_r_mips_hi16(struct module *me, u32 *location, Elf_Addr v,
			     u32 base, Elf_Addr v, bool rela)
			     bool rela)
{
{
	struct mips_hi16 *n;
	struct mips_hi16 *n;


@@ -217,26 +208,25 @@ static int apply_r_mips_pc(struct module *me, u32 *location, u32 base,
	return 0;
	return 0;
}
}


static int apply_r_mips_pc16(struct module *me, u32 *location,
static int apply_r_mips_pc16(struct module *me, u32 *location, u32 base,
			     u32 base, Elf_Addr v, bool rela)
			     Elf_Addr v)
{
{
	return apply_r_mips_pc(me, location, base, v, 16);
	return apply_r_mips_pc(me, location, base, v, 16);
}
}


static int apply_r_mips_pc21(struct module *me, u32 *location,
static int apply_r_mips_pc21(struct module *me, u32 *location, u32 base,
			     u32 base, Elf_Addr v, bool rela)
			     Elf_Addr v)
{
{
	return apply_r_mips_pc(me, location, base, v, 21);
	return apply_r_mips_pc(me, location, base, v, 21);
}
}


static int apply_r_mips_pc26(struct module *me, u32 *location,
static int apply_r_mips_pc26(struct module *me, u32 *location, u32 base,
			     u32 base, Elf_Addr v, bool rela)
			     Elf_Addr v)
{
{
	return apply_r_mips_pc(me, location, base, v, 26);
	return apply_r_mips_pc(me, location, base, v, 26);
}
}


static int apply_r_mips_64(struct module *me, u32 *location,
static int apply_r_mips_64(u32 *location, Elf_Addr v, bool rela)
			   u32 base, Elf_Addr v, bool rela)
{
{
	if (WARN_ON(!rela))
	if (WARN_ON(!rela))
		return -EINVAL;
		return -EINVAL;
@@ -246,8 +236,7 @@ static int apply_r_mips_64(struct module *me, u32 *location,
	return 0;
	return 0;
}
}


static int apply_r_mips_higher(struct module *me, u32 *location,
static int apply_r_mips_higher(u32 *location, Elf_Addr v, bool rela)
			       u32 base, Elf_Addr v, bool rela)
{
{
	if (WARN_ON(!rela))
	if (WARN_ON(!rela))
		return -EINVAL;
		return -EINVAL;
@@ -258,8 +247,7 @@ static int apply_r_mips_higher(struct module *me, u32 *location,
	return 0;
	return 0;
}
}


static int apply_r_mips_highest(struct module *me, u32 *location,
static int apply_r_mips_highest(u32 *location, Elf_Addr v, bool rela)
				u32 base, Elf_Addr v, bool rela)
{
{
	if (WARN_ON(!rela))
	if (WARN_ON(!rela))
		return -EINVAL;
		return -EINVAL;
@@ -272,12 +260,14 @@ static int apply_r_mips_highest(struct module *me, u32 *location,


/**
/**
 * reloc_handler() - Apply a particular relocation to a module
 * reloc_handler() - Apply a particular relocation to a module
 * @type: type of the relocation to apply
 * @me: the module to apply the reloc to
 * @me: the module to apply the reloc to
 * @location: the address at which the reloc is to be applied
 * @location: the address at which the reloc is to be applied
 * @base: the existing value at location for REL-style; 0 for RELA-style
 * @base: the existing value at location for REL-style; 0 for RELA-style
 * @v: the value of the reloc, with addend for RELA-style
 * @v: the value of the reloc, with addend for RELA-style
 * @rela: indication of is this a RELA (true) or REL (false) relocation
 *
 *
 * Each implemented reloc_handler function applies a particular type of
 * Each implemented relocation function applies a particular type of
 * relocation to the module @me. Relocs that may be found in either REL or RELA
 * relocation to the module @me. Relocs that may be found in either REL or RELA
 * variants can be handled by making use of the @base & @v parameters which are
 * variants can be handled by making use of the @base & @v parameters which are
 * set to values which abstract the difference away from the particular reloc
 * set to values which abstract the difference away from the particular reloc
@@ -285,23 +275,40 @@ static int apply_r_mips_highest(struct module *me, u32 *location,
 *
 *
 * Return: 0 upon success, else -ERRNO
 * Return: 0 upon success, else -ERRNO
 */
 */
typedef int (*reloc_handler)(struct module *me, u32 *location,
static int reloc_handler(u32 type, struct module *me, u32 *location, u32 base,
			     u32 base, Elf_Addr v, bool rela);
			 Elf_Addr v, bool rela)

{
/* The handlers for known reloc types */
	switch (type) {
static reloc_handler reloc_handlers[] = {
	case R_MIPS_NONE:
	[R_MIPS_NONE]		= apply_r_mips_none,
		break;
	[R_MIPS_32]		= apply_r_mips_32,
	case R_MIPS_32:
	[R_MIPS_26]		= apply_r_mips_26,
		apply_r_mips_32(location, base, v);
	[R_MIPS_HI16]		= apply_r_mips_hi16,
		break;
	[R_MIPS_LO16]		= apply_r_mips_lo16,
	case R_MIPS_26:
	[R_MIPS_PC16]		= apply_r_mips_pc16,
		return apply_r_mips_26(me, location, base, v);
	[R_MIPS_64]		= apply_r_mips_64,
	case R_MIPS_HI16:
	[R_MIPS_HIGHER]		= apply_r_mips_higher,
		return apply_r_mips_hi16(me, location, v, rela);
	[R_MIPS_HIGHEST]	= apply_r_mips_highest,
	case R_MIPS_LO16:
	[R_MIPS_PC21_S2]	= apply_r_mips_pc21,
		return apply_r_mips_lo16(me, location, base, v, rela);
	[R_MIPS_PC26_S2]	= apply_r_mips_pc26,
	case R_MIPS_PC16:
};
		return apply_r_mips_pc16(me, location, base, v);
	case R_MIPS_PC21_S2:
		return apply_r_mips_pc21(me, location, base, v);
	case R_MIPS_PC26_S2:
		return apply_r_mips_pc26(me, location, base, v);
	case R_MIPS_64:
		return apply_r_mips_64(location, v, rela);
	case R_MIPS_HIGHER:
		return apply_r_mips_higher(location, v, rela);
	case R_MIPS_HIGHEST:
		return apply_r_mips_highest(location, v, rela);
	default:
		pr_err("%s: Unknown relocation type %u\n", me->name, type);
		return -EINVAL;
	}

	return 0;
}


static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
			    unsigned int symindex, unsigned int relsec,
			    unsigned int symindex, unsigned int relsec,
@@ -311,7 +318,6 @@ static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
		Elf_Mips_Rel *rel;
		Elf_Mips_Rel *rel;
		Elf_Mips_Rela *rela;
		Elf_Mips_Rela *rela;
	} r;
	} r;
	reloc_handler handler;
	Elf_Sym *sym;
	Elf_Sym *sym;
	u32 *location, base;
	u32 *location, base;
	unsigned int i, type;
	unsigned int i, type;
@@ -343,17 +349,6 @@ static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
		}
		}


		type = ELF_MIPS_R_TYPE(*r.rel);
		type = ELF_MIPS_R_TYPE(*r.rel);
		if (type < ARRAY_SIZE(reloc_handlers))
			handler = reloc_handlers[type];
		else
			handler = NULL;

		if (!handler) {
			pr_err("%s: Unknown relocation type %u\n",
			       me->name, type);
			err = -EINVAL;
			goto out;
		}


		if (rela) {
		if (rela) {
			v = sym->st_value + r.rela->r_addend;
			v = sym->st_value + r.rela->r_addend;
@@ -365,7 +360,7 @@ static int __apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
			r.rel = &r.rel[1];
			r.rel = &r.rel[1];
		}
		}


		err = handler(me, location, base, v, rela);
		err = reloc_handler(type, me, location, base, v, rela);
		if (err)
		if (err)
			goto out;
			goto out;
	}
	}