Skip to content

Commit

Permalink
MIPS: relocatable: optimize the relocation process
Browse files Browse the repository at this point in the history
For now, vmlinux relocation functions for relocatable kernel are
implemented as an array of handlers of a particular type.

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];

and also mark do_relocations() and show_kernel_relocation() static
as they aren't used anywhere else.

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

scripts/bloat-o-meter -c arch/mips/kernel/__relocate.o arch/mips/kernel/relocate.o
add/remove: 0/6 grow/shrink: 1/0 up/down: 356/-640 (-284)
Function                                     old     new   delta
relocate_kernel                              852    1208    +356
apply_r_mips_32_rel                           20       -     -20
apply_r_mips_hi16_rel                         40       -     -40
apply_r_mips_64_rel                           44       -     -44
apply_r_mips_26_rel                          144       -    -144
show_kernel_relocation                       164       -    -164
do_relocations                               228       -    -228
Total: Before=1780, After=1496, chg -15.96%
add/remove: 0/1 grow/shrink: 0/0 up/down: 0/-76 (-76)
Data                                         old     new   delta
reloc_handlers_rel                            76       -     -76
Total: Before=92, After=16, chg -82.61%
add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0 (0)
RO Data                                      old     new   delta
Total: Before=0, After=0, chg +0.00%

All functions were collapsed into the main one, relocate_kernel().

Signed-off-by: Alexander Lobakin <alobakin@pm.me>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
  • Loading branch information
Alexander Lobakin authored and Thomas Bogendoerfer committed Jan 18, 2021
1 parent 049a68e commit d9e84fb
Showing 1 changed file with 30 additions and 24 deletions.
54 changes: 30 additions & 24 deletions arch/mips/kernel/relocate.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,14 @@ static void __init sync_icache(void *kbase, unsigned long kernel_length)
__sync();
}

static int __init apply_r_mips_64_rel(u32 *loc_orig, u32 *loc_new, long offset)
static void __init apply_r_mips_64_rel(u32 *loc_new, long offset)
{
*(u64 *)loc_new += offset;

return 0;
}

static int __init apply_r_mips_32_rel(u32 *loc_orig, u32 *loc_new, long offset)
static void __init apply_r_mips_32_rel(u32 *loc_new, long offset)
{
*loc_new += offset;

return 0;
}

static int __init apply_r_mips_26_rel(u32 *loc_orig, u32 *loc_new, long offset)
Expand Down Expand Up @@ -114,25 +110,42 @@ static int __init apply_r_mips_26_rel(u32 *loc_orig, u32 *loc_new, long offset)
}


static int __init apply_r_mips_hi16_rel(u32 *loc_orig, u32 *loc_new, long offset)
static void __init apply_r_mips_hi16_rel(u32 *loc_orig, u32 *loc_new,
long offset)
{
unsigned long insn = *loc_orig;
unsigned long target = (insn & 0xffff) << 16; /* high 16bits of target */

target += offset;

*loc_new = (insn & ~0xffff) | ((target >> 16) & 0xffff);
return 0;
}

static int (*reloc_handlers_rel[]) (u32 *, u32 *, long) __initdata = {
[R_MIPS_64] = apply_r_mips_64_rel,
[R_MIPS_32] = apply_r_mips_32_rel,
[R_MIPS_26] = apply_r_mips_26_rel,
[R_MIPS_HI16] = apply_r_mips_hi16_rel,
};
static int __init reloc_handler(u32 type, u32 *loc_orig, u32 *loc_new,
long offset)
{
switch (type) {
case R_MIPS_64:
apply_r_mips_64_rel(loc_new, offset);
break;
case R_MIPS_32:
apply_r_mips_32_rel(loc_new, offset);
break;
case R_MIPS_26:
return apply_r_mips_26_rel(loc_orig, loc_new, offset);
case R_MIPS_HI16:
apply_r_mips_hi16_rel(loc_orig, loc_new, offset);
break;
default:
pr_err("Unhandled relocation type %d at 0x%pK\n", type,
loc_orig);
return -ENOEXEC;
}

int __init do_relocations(void *kbase_old, void *kbase_new, long offset)
return 0;
}

static int __init do_relocations(void *kbase_old, void *kbase_new, long offset)
{
u32 *r;
u32 *loc_orig;
Expand All @@ -149,14 +162,7 @@ int __init do_relocations(void *kbase_old, void *kbase_new, long offset)
loc_orig = kbase_old + ((*r & 0x00ffffff) << 2);
loc_new = RELOCATED(loc_orig);

if (reloc_handlers_rel[type] == NULL) {
/* Unsupported relocation */
pr_err("Unhandled relocation type %d at 0x%pK\n",
type, loc_orig);
return -ENOEXEC;
}

res = reloc_handlers_rel[type](loc_orig, loc_new, offset);
res = reloc_handler(type, loc_orig, loc_new, offset);
if (res)
return res;
}
Expand Down Expand Up @@ -412,7 +418,7 @@ void *__init relocate_kernel(void)
/*
* Show relocation information on panic.
*/
void show_kernel_relocation(const char *level)
static void show_kernel_relocation(const char *level)
{
unsigned long offset;

Expand Down

0 comments on commit d9e84fb

Please sign in to comment.