[PATCH v2 4/4] ARM: use single definition for vectors-to-stubs section offset
Ard Biesheuvel
ard.biesheuvel at linaro.org
Wed Feb 3 11:04:57 PST 2016
This replaces a couple of unannotated uses of the constant 0x1000 with
a single definition in the linker script, and updates the referring
code to use it.
Note that this involves explicitly emitting a relocation against the
literal in .stubs containing the address of vector_swi(), since the
assembler refuses to do so.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
---
arch/arm/kernel/entry-armv.S | 17 +++++++++++++----
arch/arm/kernel/traps.c | 4 +++-
arch/arm/kernel/vmlinux.lds.S | 9 ++++++++-
3 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 8575ff42c0d4..c19d3b82edb8 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -1064,8 +1064,7 @@ ENDPROC(vector_\name)
.endm
.section .stubs, "ax", %progbits
-__stubs_start:
- @ This must be the first word
+.Lvector_swi:
.word vector_swi
vector_rst:
@@ -1205,16 +1204,26 @@ vector_addrexcptn:
.globl vector_fiq
.section .vectors, "ax", %progbits
-.L__vectors_start:
W(b) vector_rst
W(b) vector_und
- W(ldr) pc, .L__vectors_start + 0x1000
+0: W(ldr) pc, . @ vector_swi
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
+ /*
+ * The assembler refuses to emit the correct relocation for the
+ * cross-section reference to .Lvector_swi inside the ldr instruction
+ * above, so we have to emit it manually. Note that the addend cannot
+ * be set by the .reloc directive, and the initial offset recorded in
+ * the instruction should compensate for the PC bias of the execution
+ * mode, hence the use of '.' as the label.
+ */
+ ARM( .reloc 0b, R_ARM_LDR_PC_G0, .Lvector_swi )
+ THUMB( .reloc 0b, R_ARM_THM_PC12, .Lvector_swi )
+
.data
.globl cr_alignment
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc698383e822..d90a5b2c02a3 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -792,6 +792,8 @@ void __init early_trap_init(void *vectors_base)
{
#ifndef CONFIG_CPU_V7M
unsigned long vectors = (unsigned long)vectors_base;
+ extern char __stubs_offset[];
+ unsigned long stubs = vectors + (unsigned long)&__stubs_offset;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
unsigned i;
@@ -813,7 +815,7 @@ void __init early_trap_init(void *vectors_base)
* are visible to the instruction stream.
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
- memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
+ memcpy((void *)stubs, __stubs_start, __stubs_end - __stubs_start);
kuser_init(vectors_base);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 9f96a54c7d90..8f270c8e9153 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -163,7 +163,14 @@ SECTIONS
/*
* The vectors and stubs are relocatable code, and the
* only thing that matters is their relative offsets
+ * The .stubs section is virtually placed exactly 4 KB after
+ * the .vectors section, so that it is in reach for indirect
+ * jumps from the vector table ('ldr pc, <label>', where the
+ * label itself is inside the .stubs section) but can still
+ * be mapped with different permissions.
*/
+ __stubs_offset = 0x1000;
+
.stubs : {
__stubs_start = .;
*(.stubs)
@@ -171,7 +178,7 @@ SECTIONS
}
__vectors_start = .;
- .vectors ADDR(.stubs) - 0x1000 : AT(__vectors_start) {
+ .vectors ADDR(.stubs) - __stubs_offset : AT(__vectors_start) {
*(.vectors)
}
. = __vectors_start + SIZEOF(.vectors);
--
2.5.0
More information about the linux-arm-kernel
mailing list