diff --git a/arch/arm/include/asm/pie.h b/arch/arm/include/asm/pie.h new file mode 100644 index 000000000000..977f11db3a87 --- /dev/null +++ b/arch/arm/include/asm/pie.h @@ -0,0 +1,42 @@ +/* + * arch/arm/include/asm/pie.h + * + * Copyright 2013 Texas Instruments, Inc + * Russ Dill + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ASMARM_PIE_H +#define _ASMARM_PIE_H + +#include + +#ifdef CONFIG_PIE +extern void __pie_relocate(void); +extern void __pie___pie_relocate(void); + +#define pie_relocate_from_pie() \ + __asm__ __volatile__("bl __pie_relocate\n" \ + : : : "cc", "memory", "lr", "r4", "r5", "r6", "r7", "r8", "r9"); + +static inline void pie_relocate_from_kern(struct pie_chunk *chunk) +{ + void (*fn)(void) = fn_to_pie(chunk, &__pie___pie_relocate); + __asm__ __volatile__("" : : : "cc", "memory", "r4", "r5", "r6", + "r7", "r8", "r9"); + fn(); +} +#else + +#define pie_relocate_from_pie() do {} while(0) + +static inline void pie_relocate_from_kern(struct pie_chunk *chunk) +{ +} + +#endif + +#endif diff --git a/arch/arm/kernel/pie.c b/arch/arm/kernel/pie.c index 5dff5d671f1a..598562fd12ea 100644 --- a/arch/arm/kernel/pie.c +++ b/arch/arm/kernel/pie.c @@ -12,10 +12,12 @@ #include #include +#include extern char __pie_rel_dyn_start[]; extern char __pie_rel_dyn_end[]; extern char __pie_tail_offset[]; +extern char __pie_reloc_offset[]; struct arm_pie_tail { int count; @@ -72,12 +74,19 @@ int pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail, unsigned long offset) { struct arm_pie_tail *pie_tail = tail; + void *reloc; int i; /* Perform relocation fixups for given offset */ for (i = 0; i < pie_tail->count; i++) *((uintptr_t *) (pie_tail->offset[i] + base)) += offset; + /* Store the PIE offset to tail and recol func */ + *kern_to_pie(chunk, (uintptr_t *) __pie_tail_offset) = tail - base; + reloc = kern_to_pie(chunk, + (void *) fnptr_to_addr(&__pie___pie_relocate)); + *kern_to_pie(chunk, (uintptr_t *) __pie_reloc_offset) = reloc - base; + return 0; } EXPORT_SYMBOL_GPL(pie_arch_fixup); diff --git a/arch/arm/libpie/Makefile b/arch/arm/libpie/Makefile index 5662e996881a..b1ac52ab38da 100644 --- a/arch/arm/libpie/Makefile +++ b/arch/arm/libpie/Makefile @@ -3,7 +3,7 @@ # ccflags-y := -fpic -mno-single-pic-base -fno-builtin -obj-y := empty.o +obj-y := relocate.o empty.o obj-y += lib1funcs.o ashldi3.o string.o # string library code (-Os is enforced to keep it much smaller) diff --git a/arch/arm/libpie/relocate.S b/arch/arm/libpie/relocate.S new file mode 100644 index 000000000000..70cc36e00ed1 --- /dev/null +++ b/arch/arm/libpie/relocate.S @@ -0,0 +1,76 @@ +/* + * arch/arm/libpie/relocate.S - Relocation updating for PIEs + * + * Copyright 2013 Texas Instruments, Inc. + * Russ Dill + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include + +/* + * Update relocations based on current pc + * + * On exit: + * r4-r9 corrupted + */ + +ENTRY(__pie_relocate) + /* Calculate offset of our code compared to existing relocations */ + ldr r4, pie_relocate_address + adr r5, __pie_relocate + subs r6, r5, r4 + moveq pc, lr /* 0 offset, no need to do anything */ + + /* Base of PIE group */ + ldr r7, reloc_offset + sub r5, r5, r7 + + /* Calculate address of tail */ + ldr r7, tail_offset + add r7, r7, r5 + + /* First byte of tail is number of entries */ + ldr r8, [r7], #4 + add r8, r7, r8, lsl #2 + + /* + * r5 - current base address of PIE group + * r6 - fixup offset needed for relocs + * r7 - relocs start + * r8 - relocs end + */ + +1: + cmp r7, r8 + ldrne r4, [r7], #4 /* Load next reloc offset */ + + addne r4, r4, r5 /* Calculate address of reloc entry */ + ldrne r9, [r4] + addne r9, r9, r6 /* Fixup reloc entry */ + strne r9, [r4] + + bne 1b + + mov pc, lr +ENDPROC(__pie_relocate) + +/* + * This ends up in the .rel.dyn section and can be used to read the current + * relocation offset + */ +pie_relocate_address: + .long __pie_relocate + +/* Offset from PIE section start to reloc function */ +.global reloc_offset +reloc_offset: + .space 4 + +/* Offset from PIE section start to tail */ +.globl tail_offset +tail_offset: + .space 4