diff options
| author | Jan Beulich <JBeulich@suse.com> | 2014-11-04 03:50:18 -0500 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2014-11-04 14:43:14 -0500 |
| commit | 6d24c5f72dfb26e5fa7f02fa9266dfdbae41adba (patch) | |
| tree | 02a65c8228a6a6bfc0e0c89c6c749e491b2bda8b | |
| parent | 2c773dd31fbacbbb6425f8a9d3f97e0010272368 (diff) | |
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: Jan Beulich <jbeulich@suse.com>
Link: http://lkml.kernel.org/r/5458A15A0200007800044A9A@mail.emea.novell.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | arch/x86/boot/compressed/misc.c | 14 | ||||
| -rw-r--r-- | arch/x86/tools/relocs.c | 36 |
2 files changed, 40 insertions, 10 deletions
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 57ab74df7eea..644abd767c12 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c | |||
| @@ -260,7 +260,7 @@ static void handle_relocations(void *output, unsigned long output_len) | |||
| 260 | 260 | ||
| 261 | /* | 261 | /* |
| 262 | * Process relocations: 32 bit relocations first then 64 bit after. | 262 | * Process relocations: 32 bit relocations first then 64 bit after. |
| 263 | * Two sets of binary relocations are added to the end of the kernel | 263 | * Three sets of binary relocations are added to the end of the kernel |
| 264 | * before compression. Each relocation table entry is the kernel | 264 | * before compression. Each relocation table entry is the kernel |
| 265 | * address of the location which needs to be updated stored as a | 265 | * address of the location which needs to be updated stored as a |
| 266 | * 32-bit value which is sign extended to 64 bits. | 266 | * 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 | * kernel bits... | 270 | * kernel bits... |
| 271 | * 0 - zero terminator for 64 bit relocations | 271 | * 0 - zero terminator for 64 bit relocations |
| 272 | * 64 bit relocation repeated | 272 | * 64 bit relocation repeated |
| 273 | * 0 - zero terminator for inverse 32 bit relocations | ||
| 274 | * 32 bit inverse relocation repeated | ||
| 273 | * 0 - zero terminator for 32 bit relocations | 275 | * 0 - zero terminator for 32 bit relocations |
| 274 | * 32 bit relocation repeated | 276 | * 32 bit relocation repeated |
| 275 | * | 277 | * |
| @@ -286,6 +288,16 @@ static void handle_relocations(void *output, unsigned long output_len) | |||
| 286 | *(uint32_t *)ptr += delta; | 288 | *(uint32_t *)ptr += delta; |
| 287 | } | 289 | } |
| 288 | #ifdef CONFIG_X86_64 | 290 | #ifdef CONFIG_X86_64 |
| 291 | while (*--reloc) { | ||
| 292 | long extended = *reloc; | ||
| 293 | extended += map; | ||
| 294 | |||
| 295 | ptr = (unsigned long)extended; | ||
| 296 | if (ptr < min_addr || ptr > max_addr) | ||
| 297 | error("inverse 32-bit relocation outside of kernel!\n"); | ||
| 298 | |||
| 299 | *(int32_t *)ptr -= delta; | ||
| 300 | } | ||
| 289 | for (reloc--; *reloc; reloc--) { | 301 | for (reloc--; *reloc; reloc--) { |
| 290 | long extended = *reloc; | 302 | long extended = *reloc; |
| 291 | extended += map; | 303 | extended += map; |
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index a5efb21d5228..0c2fae8d929d 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c | |||
| @@ -20,7 +20,10 @@ struct relocs { | |||
| 20 | 20 | ||
| 21 | static struct relocs relocs16; | 21 | static struct relocs relocs16; |
| 22 | static struct relocs relocs32; | 22 | static struct relocs relocs32; |
| 23 | #if ELF_BITS == 64 | ||
| 24 | static struct relocs relocs32neg; | ||
| 23 | static struct relocs relocs64; | 25 | static struct relocs relocs64; |
| 26 | #endif | ||
| 24 | 27 | ||
| 25 | struct section { | 28 | struct section { |
| 26 | Elf_Shdr shdr; | 29 | Elf_Shdr shdr; |
| @@ -762,11 +765,16 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, | |||
| 762 | 765 | ||
| 763 | switch (r_type) { | 766 | switch (r_type) { |
| 764 | case R_X86_64_NONE: | 767 | case R_X86_64_NONE: |
| 768 | /* NONE can be ignored. */ | ||
| 769 | break; | ||
| 770 | |||
| 765 | case R_X86_64_PC32: | 771 | case R_X86_64_PC32: |
| 766 | /* | 772 | /* |
| 767 | * NONE can be ignored and PC relative relocations don't | 773 | * PC relative relocations don't need to be adjusted unless |
| 768 | * need to be adjusted. | 774 | * referencing a percpu symbol. |
| 769 | */ | 775 | */ |
| 776 | if (is_percpu_sym(sym, symname)) | ||
| 777 | add_reloc(&relocs32neg, offset); | ||
| 770 | break; | 778 | break; |
| 771 | 779 | ||
| 772 | case R_X86_64_32: | 780 | case R_X86_64_32: |
| @@ -986,7 +994,10 @@ static void emit_relocs(int as_text, int use_real_mode) | |||
| 986 | /* Order the relocations for more efficient processing */ | 994 | /* Order the relocations for more efficient processing */ |
| 987 | sort_relocs(&relocs16); | 995 | sort_relocs(&relocs16); |
| 988 | sort_relocs(&relocs32); | 996 | sort_relocs(&relocs32); |
| 997 | #if ELF_BITS == 64 | ||
| 998 | sort_relocs(&relocs32neg); | ||
| 989 | sort_relocs(&relocs64); | 999 | sort_relocs(&relocs64); |
| 1000 | #endif | ||
| 990 | 1001 | ||
| 991 | /* Print the relocations */ | 1002 | /* Print the relocations */ |
| 992 | if (as_text) { | 1003 | if (as_text) { |
| @@ -1007,14 +1018,21 @@ static void emit_relocs(int as_text, int use_real_mode) | |||
| 1007 | for (i = 0; i < relocs32.count; i++) | 1018 | for (i = 0; i < relocs32.count; i++) |
| 1008 | write_reloc(relocs32.offset[i], stdout); | 1019 | write_reloc(relocs32.offset[i], stdout); |
| 1009 | } else { | 1020 | } else { |
| 1010 | if (ELF_BITS == 64) { | 1021 | #if ELF_BITS == 64 |
| 1011 | /* Print a stop */ | 1022 | /* Print a stop */ |
| 1012 | write_reloc(0, stdout); | 1023 | write_reloc(0, stdout); |
| 1013 | 1024 | ||
| 1014 | /* Now print each relocation */ | 1025 | /* Now print each relocation */ |
| 1015 | for (i = 0; i < relocs64.count; i++) | 1026 | for (i = 0; i < relocs64.count; i++) |
| 1016 | write_reloc(relocs64.offset[i], stdout); | 1027 | write_reloc(relocs64.offset[i], stdout); |
| 1017 | } | 1028 | |
| 1029 | /* Print a stop */ | ||
| 1030 | write_reloc(0, stdout); | ||
| 1031 | |||
| 1032 | /* Now print each inverse 32-bit relocation */ | ||
| 1033 | for (i = 0; i < relocs32neg.count; i++) | ||
| 1034 | write_reloc(relocs32neg.offset[i], stdout); | ||
| 1035 | #endif | ||
| 1018 | 1036 | ||
| 1019 | /* Print a stop */ | 1037 | /* Print a stop */ |
| 1020 | write_reloc(0, stdout); | 1038 | write_reloc(0, stdout); |
