aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/boot/compressed/misc.c14
-rw-r--r--arch/x86/tools/relocs.c36
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
21static struct relocs relocs16; 21static struct relocs relocs16;
22static struct relocs relocs32; 22static struct relocs relocs32;
23#if ELF_BITS == 64
24static struct relocs relocs32neg;
23static struct relocs relocs64; 25static struct relocs relocs64;
26#endif
24 27
25struct section { 28struct 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);