Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jan Beulich and committed by
Thomas Gleixner
6d24c5f7 2c773dd3

+40 -10
+13 -1
arch/x86/boot/compressed/misc.c
··· 260 260 261 261 /* 262 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 264 * before compression. Each relocation table entry is the kernel 265 265 * address of the location which needs to be updated stored as a 266 266 * 32-bit value which is sign extended to 64 bits. ··· 270 270 * kernel bits... 271 271 * 0 - zero terminator for 64 bit relocations 272 272 * 64 bit relocation repeated 273 + * 0 - zero terminator for inverse 32 bit relocations 274 + * 32 bit inverse relocation repeated 273 275 * 0 - zero terminator for 32 bit relocations 274 276 * 32 bit relocation repeated 275 277 * ··· 288 286 *(uint32_t *)ptr += delta; 289 287 } 290 288 #ifdef CONFIG_X86_64 289 + while (*--reloc) { 290 + long extended = *reloc; 291 + extended += map; 292 + 293 + ptr = (unsigned long)extended; 294 + if (ptr < min_addr || ptr > max_addr) 295 + error("inverse 32-bit relocation outside of kernel!\n"); 296 + 297 + *(int32_t *)ptr -= delta; 298 + } 291 299 for (reloc--; *reloc; reloc--) { 292 300 long extended = *reloc; 293 301 extended += map;
+27 -9
arch/x86/tools/relocs.c
··· 20 20 21 21 static struct relocs relocs16; 22 22 static struct relocs relocs32; 23 + #if ELF_BITS == 64 24 + static struct relocs relocs32neg; 23 25 static struct relocs relocs64; 26 + #endif 24 27 25 28 struct section { 26 29 Elf_Shdr shdr; ··· 765 762 766 763 switch (r_type) { 767 764 case R_X86_64_NONE: 765 + /* NONE can be ignored. */ 766 + break; 767 + 768 768 case R_X86_64_PC32: 769 769 /* 770 - * NONE can be ignored and PC relative relocations don't 771 - * need to be adjusted. 770 + * PC relative relocations don't need to be adjusted unless 771 + * referencing a percpu symbol. 772 772 */ 773 + if (is_percpu_sym(sym, symname)) 774 + add_reloc(&relocs32neg, offset); 773 775 break; 774 776 775 777 case R_X86_64_32: ··· 994 986 /* Order the relocations for more efficient processing */ 995 987 sort_relocs(&relocs16); 996 988 sort_relocs(&relocs32); 989 + #if ELF_BITS == 64 990 + sort_relocs(&relocs32neg); 997 991 sort_relocs(&relocs64); 992 + #endif 998 993 999 994 /* Print the relocations */ 1000 995 if (as_text) { ··· 1018 1007 for (i = 0; i < relocs32.count; i++) 1019 1008 write_reloc(relocs32.offset[i], stdout); 1020 1009 } else { 1021 - if (ELF_BITS == 64) { 1022 - /* Print a stop */ 1023 - write_reloc(0, stdout); 1010 + #if ELF_BITS == 64 1011 + /* Print a stop */ 1012 + write_reloc(0, stdout); 1024 1013 1025 - /* Now print each relocation */ 1026 - for (i = 0; i < relocs64.count; i++) 1027 - write_reloc(relocs64.offset[i], stdout); 1028 - } 1014 + /* Now print each relocation */ 1015 + for (i = 0; i < relocs64.count; i++) 1016 + write_reloc(relocs64.offset[i], stdout); 1017 + 1018 + /* Print a stop */ 1019 + write_reloc(0, stdout); 1020 + 1021 + /* Now print each inverse 32-bit relocation */ 1022 + for (i = 0; i < relocs32neg.count; i++) 1023 + write_reloc(relocs32neg.offset[i], stdout); 1024 + #endif 1029 1025 1030 1026 /* Print a stop */ 1031 1027 write_reloc(0, stdout);