[PATCH 1/2] x86-64: handle PC-relative relocations on per-CPU data

From: Jan Beulich
Date: Tue Nov 04 2014 - 03:50:32 EST


This is in preparation of using RIP-relative addressing in many of the
per-CPU accesses.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
arch/x86/boot/compressed/misc.c | 14 +++++++++++++-
arch/x86/tools/relocs.c | 38 ++++++++++++++++++++++++++++----------
2 files changed, 41 insertions(+), 11 deletions(-)

--- 3.18-rc3-x86_64-PCrel-per-CPU.orig/arch/x86/boot/compressed/misc.c
+++ 3.18-rc3-x86_64-PCrel-per-CPU/arch/x86/boot/compressed/misc.c
@@ -260,7 +260,7 @@ static void handle_relocations(void *out

/*
* Process relocations: 32 bit relocations first then 64 bit after.
- * Two sets of binary relocations are added to the end of the kernel
+ * Three sets of binary relocations are added to the end of the kernel
* before compression. Each relocation table entry is the kernel
* address of the location which needs to be updated stored as a
* 32-bit value which is sign extended to 64 bits.
@@ -270,6 +270,8 @@ static void handle_relocations(void *out
* kernel bits...
* 0 - zero terminator for 64 bit relocations
* 64 bit relocation repeated
+ * 0 - zero terminator for inverse 32 bit relocations
+ * 32 bit inverse relocation repeated
* 0 - zero terminator for 32 bit relocations
* 32 bit relocation repeated
*
@@ -286,6 +288,16 @@ static void handle_relocations(void *out
*(uint32_t *)ptr += delta;
}
#ifdef CONFIG_X86_64
+ while (*--reloc) {
+ long extended = *reloc;
+ extended += map;
+
+ ptr = (unsigned long)extended;
+ if (ptr < min_addr || ptr > max_addr)
+ error("inverse 32-bit relocation outside of kernel!\n");
+
+ *(int32_t *)ptr -= delta;
+ }
for (reloc--; *reloc; reloc--) {
long extended = *reloc;
extended += map;
--- 3.18-rc3-x86_64-PCrel-per-CPU.orig/arch/x86/tools/relocs.c
+++ 3.18-rc3-x86_64-PCrel-per-CPU/arch/x86/tools/relocs.c
@@ -20,7 +20,10 @@ struct relocs {

static struct relocs relocs16;
static struct relocs relocs32;
+#if ELF_BITS == 64
+static struct relocs relocs32neg;
static struct relocs relocs64;
+#endif

struct section {
Elf_Shdr shdr;
@@ -762,11 +765,16 @@ static int do_reloc64(struct section *se

switch (r_type) {
case R_X86_64_NONE:
+ /* NONE can be ignored. */
+ break;
+
case R_X86_64_PC32:
/*
- * NONE can be ignored and PC relative relocations don't
- * need to be adjusted.
+ * PC relative relocations don't need to be adjusted unless
+ * referencing a percpu symbol.
*/
+ if (is_percpu_sym(sym, symname))
+ add_reloc(&relocs32neg, offset);
break;

case R_X86_64_32:
@@ -986,7 +994,10 @@ static void emit_relocs(int as_text, int
/* Order the relocations for more efficient processing */
sort_relocs(&relocs16);
sort_relocs(&relocs32);
+#if ELF_BITS == 64
+ sort_relocs(&relocs32neg);
sort_relocs(&relocs64);
+#endif

/* Print the relocations */
if (as_text) {
@@ -1007,14 +1018,21 @@ static void emit_relocs(int as_text, int
for (i = 0; i < relocs32.count; i++)
write_reloc(relocs32.offset[i], stdout);
} else {
- if (ELF_BITS == 64) {
- /* Print a stop */
- write_reloc(0, stdout);
-
- /* Now print each relocation */
- for (i = 0; i < relocs64.count; i++)
- write_reloc(relocs64.offset[i], stdout);
- }
+#if ELF_BITS == 64
+ /* Print a stop */
+ write_reloc(0, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < relocs64.count; i++)
+ write_reloc(relocs64.offset[i], stdout);
+
+ /* Print a stop */
+ write_reloc(0, stdout);
+
+ /* Now print each inverse 32-bit relocation */
+ for (i = 0; i < relocs32neg.count; i++)
+ write_reloc(relocs32neg.offset[i], stdout);
+#endif

/* Print a stop */
write_reloc(0, stdout);



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/