Commit 6d24c5f7 authored by Jan Beulich's avatar Jan Beulich Committed by Thomas Gleixner

x86-64: Handle PC-relative relocations on per-CPU data

This is in preparation of using RIP-relative addressing in many of the
per-CPU accesses.
Signed-off-by: default avatarJan Beulich <jbeulich@suse.com>
Link: http://lkml.kernel.org/r/5458A15A0200007800044A9A@mail.emea.novell.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 2c773dd3
...@@ -260,7 +260,7 @@ static void handle_relocations(void *output, unsigned long output_len) ...@@ -260,7 +260,7 @@ static void handle_relocations(void *output, unsigned long output_len)
/* /*
* Process relocations: 32 bit relocations first then 64 bit after. * 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 * before compression. Each relocation table entry is the kernel
* address of the location which needs to be updated stored as a * address of the location which needs to be updated stored as a
* 32-bit value which is sign extended to 64 bits. * 32-bit value which is sign extended to 64 bits.
...@@ -270,6 +270,8 @@ static void handle_relocations(void *output, unsigned long output_len) ...@@ -270,6 +270,8 @@ static void handle_relocations(void *output, unsigned long output_len)
* kernel bits... * kernel bits...
* 0 - zero terminator for 64 bit relocations * 0 - zero terminator for 64 bit relocations
* 64 bit relocation repeated * 64 bit relocation repeated
* 0 - zero terminator for inverse 32 bit relocations
* 32 bit inverse relocation repeated
* 0 - zero terminator for 32 bit relocations * 0 - zero terminator for 32 bit relocations
* 32 bit relocation repeated * 32 bit relocation repeated
* *
...@@ -286,6 +288,16 @@ static void handle_relocations(void *output, unsigned long output_len) ...@@ -286,6 +288,16 @@ static void handle_relocations(void *output, unsigned long output_len)
*(uint32_t *)ptr += delta; *(uint32_t *)ptr += delta;
} }
#ifdef CONFIG_X86_64 #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--) { for (reloc--; *reloc; reloc--) {
long extended = *reloc; long extended = *reloc;
extended += map; extended += map;
......
...@@ -20,7 +20,10 @@ struct relocs { ...@@ -20,7 +20,10 @@ struct relocs {
static struct relocs relocs16; static struct relocs relocs16;
static struct relocs relocs32; static struct relocs relocs32;
#if ELF_BITS == 64
static struct relocs relocs32neg;
static struct relocs relocs64; static struct relocs relocs64;
#endif
struct section { struct section {
Elf_Shdr shdr; Elf_Shdr shdr;
...@@ -762,11 +765,16 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, ...@@ -762,11 +765,16 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
switch (r_type) { switch (r_type) {
case R_X86_64_NONE: case R_X86_64_NONE:
/* NONE can be ignored. */
break;
case R_X86_64_PC32: case R_X86_64_PC32:
/* /*
* NONE can be ignored and PC relative relocations don't * PC relative relocations don't need to be adjusted unless
* need to be adjusted. * referencing a percpu symbol.
*/ */
if (is_percpu_sym(sym, symname))
add_reloc(&relocs32neg, offset);
break; break;
case R_X86_64_32: case R_X86_64_32:
...@@ -986,7 +994,10 @@ static void emit_relocs(int as_text, int use_real_mode) ...@@ -986,7 +994,10 @@ static void emit_relocs(int as_text, int use_real_mode)
/* Order the relocations for more efficient processing */ /* Order the relocations for more efficient processing */
sort_relocs(&relocs16); sort_relocs(&relocs16);
sort_relocs(&relocs32); sort_relocs(&relocs32);
#if ELF_BITS == 64
sort_relocs(&relocs32neg);
sort_relocs(&relocs64); sort_relocs(&relocs64);
#endif
/* Print the relocations */ /* Print the relocations */
if (as_text) { if (as_text) {
...@@ -1007,14 +1018,21 @@ static void emit_relocs(int as_text, int use_real_mode) ...@@ -1007,14 +1018,21 @@ static void emit_relocs(int as_text, int use_real_mode)
for (i = 0; i < relocs32.count; i++) for (i = 0; i < relocs32.count; i++)
write_reloc(relocs32.offset[i], stdout); write_reloc(relocs32.offset[i], stdout);
} else { } else {
if (ELF_BITS == 64) { #if ELF_BITS == 64
/* Print a stop */ /* Print a stop */
write_reloc(0, stdout); write_reloc(0, stdout);
/* Now print each relocation */ /* Now print each relocation */
for (i = 0; i < relocs64.count; i++) for (i = 0; i < relocs64.count; i++)
write_reloc(relocs64.offset[i], stdout); 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 */ /* Print a stop */
write_reloc(0, stdout); write_reloc(0, stdout);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment