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

Configure Feed

Select the types of activity you want to include in your feed.

x86/boot/64: Remove inverse relocations

Inverse relocations were needed to offset the effects of relocation for
RIP-relative accesses to zero-based percpu data. Now that the percpu
section is linked normally as part of the kernel image, they are no
longer needed.

Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/20250123190747.745588-11-brgerst@gmail.com

authored by

Brian Gerst and committed by
Ingo Molnar
a8327be7 b5c4f953

+2 -142
+1 -13
arch/x86/boot/compressed/misc.c
··· 235 235 236 236 /* 237 237 * Process relocations: 32 bit relocations first then 64 bit after. 238 - * Three sets of binary relocations are added to the end of the kernel 238 + * Two sets of binary relocations are added to the end of the kernel 239 239 * before compression. Each relocation table entry is the kernel 240 240 * address of the location which needs to be updated stored as a 241 241 * 32-bit value which is sign extended to 64 bits. ··· 245 245 * kernel bits... 246 246 * 0 - zero terminator for 64 bit relocations 247 247 * 64 bit relocation repeated 248 - * 0 - zero terminator for inverse 32 bit relocations 249 - * 32 bit inverse relocation repeated 250 248 * 0 - zero terminator for 32 bit relocations 251 249 * 32 bit relocation repeated 252 250 * ··· 261 263 *(uint32_t *)ptr += delta; 262 264 } 263 265 #ifdef CONFIG_X86_64 264 - while (*--reloc) { 265 - long extended = *reloc; 266 - extended += map; 267 - 268 - ptr = (unsigned long)extended; 269 - if (ptr < min_addr || ptr > max_addr) 270 - error("inverse 32-bit relocation outside of kernel!\n"); 271 - 272 - *(int32_t *)ptr -= delta; 273 - } 274 266 for (reloc--; *reloc; reloc--) { 275 267 long extended = *reloc; 276 268 extended += map;
+1 -129
arch/x86/tools/relocs.c
··· 29 29 static struct relocs relocs32; 30 30 31 31 #if ELF_BITS == 64 32 - static struct relocs relocs32neg; 33 32 static struct relocs relocs64; 34 33 # define FMT PRIu64 35 34 ··· 90 91 "__initramfs_start|" 91 92 "(jiffies|jiffies_64)|" 92 93 #if ELF_BITS == 64 93 - "__per_cpu_load|" 94 94 "init_per_cpu__.*|" 95 95 "__end_rodata_hpage_align|" 96 96 #endif ··· 286 288 name = sec_name(sym_index(sym)); 287 289 288 290 return name; 289 - } 290 - 291 - static Elf_Sym *sym_lookup(const char *symname) 292 - { 293 - int i; 294 - 295 - for (i = 0; i < shnum; i++) { 296 - struct section *sec = &secs[i]; 297 - long nsyms; 298 - char *strtab; 299 - Elf_Sym *symtab; 300 - Elf_Sym *sym; 301 - 302 - if (sec->shdr.sh_type != SHT_SYMTAB) 303 - continue; 304 - 305 - nsyms = sec->shdr.sh_size/sizeof(Elf_Sym); 306 - symtab = sec->symtab; 307 - strtab = sec->link->strtab; 308 - 309 - for (sym = symtab; --nsyms >= 0; sym++) { 310 - if (!sym->st_name) 311 - continue; 312 - if (strcmp(symname, strtab + sym->st_name) == 0) 313 - return sym; 314 - } 315 - } 316 - return 0; 317 291 } 318 292 319 293 #if BYTE_ORDER == LITTLE_ENDIAN ··· 736 766 } 737 767 } 738 768 739 - /* 740 - * The .data..percpu section is a special case for x86_64 SMP kernels. 741 - * It is used to initialize the actual per_cpu areas and to provide 742 - * definitions for the per_cpu variables that correspond to their offsets 743 - * within the percpu area. Since the values of all of the symbols need 744 - * to be offsets from the start of the per_cpu area the virtual address 745 - * (sh_addr) of .data..percpu is 0 in SMP kernels. 746 - * 747 - * This means that: 748 - * 749 - * Relocations that reference symbols in the per_cpu area do not 750 - * need further relocation (since the value is an offset relative 751 - * to the start of the per_cpu area that does not change). 752 - * 753 - * Relocations that apply to the per_cpu area need to have their 754 - * offset adjusted by by the value of __per_cpu_load to make them 755 - * point to the correct place in the loaded image (because the 756 - * virtual address of .data..percpu is 0). 757 - * 758 - * For non SMP kernels .data..percpu is linked as part of the normal 759 - * kernel data and does not require special treatment. 760 - * 761 - */ 762 - static int per_cpu_shndx = -1; 763 - static Elf_Addr per_cpu_load_addr; 764 - 765 - static void percpu_init(void) 766 - { 767 - int i; 768 - 769 - for (i = 0; i < shnum; i++) { 770 - ElfW(Sym) *sym; 771 - 772 - if (strcmp(sec_name(i), ".data..percpu")) 773 - continue; 774 - 775 - if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */ 776 - return; 777 - 778 - sym = sym_lookup("__per_cpu_load"); 779 - if (!sym) 780 - die("can't find __per_cpu_load\n"); 781 - 782 - per_cpu_shndx = i; 783 - per_cpu_load_addr = sym->st_value; 784 - 785 - return; 786 - } 787 - } 788 - 789 769 #if ELF_BITS == 64 790 - 791 - /* 792 - * Check to see if a symbol lies in the .data..percpu section. 793 - * 794 - * The linker incorrectly associates some symbols with the 795 - * .data..percpu section so we also need to check the symbol 796 - * name to make sure that we classify the symbol correctly. 797 - * 798 - * The GNU linker incorrectly associates: 799 - * __init_begin 800 - * __per_cpu_load 801 - * 802 - * The "gold" linker incorrectly associates: 803 - * init_per_cpu__gdt_page 804 - */ 805 - static int is_percpu_sym(ElfW(Sym) *sym, const char *symname) 806 - { 807 - return 0; 808 - } 809 - 810 770 811 771 static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, 812 772 const char *symname) ··· 748 848 if (sym->st_shndx == SHN_UNDEF) 749 849 return 0; 750 850 751 - /* 752 - * Adjust the offset if this reloc applies to the percpu section. 753 - */ 754 - if (sec->shdr.sh_info == per_cpu_shndx) 755 - offset += per_cpu_load_addr; 756 - 757 851 switch (r_type) { 758 852 case R_X86_64_NONE: 759 853 /* NONE can be ignored. */ ··· 757 863 case R_X86_64_PLT32: 758 864 case R_X86_64_REX_GOTPCRELX: 759 865 /* 760 - * PC relative relocations don't need to be adjusted unless 761 - * referencing a percpu symbol. 866 + * PC relative relocations don't need to be adjusted. 762 867 * 763 868 * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. 764 869 */ 765 - if (is_percpu_sym(sym, symname)) 766 - add_reloc(&relocs32neg, offset); 767 870 break; 768 871 769 872 case R_X86_64_PC64: 770 873 /* 771 874 * Only used by jump labels 772 875 */ 773 - if (is_percpu_sym(sym, symname)) 774 - die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n", symname); 775 876 break; 776 877 777 878 case R_X86_64_32: 778 879 case R_X86_64_32S: 779 880 case R_X86_64_64: 780 - /* 781 - * References to the percpu area don't need to be adjusted. 782 - */ 783 - if (is_percpu_sym(sym, symname)) 784 - break; 785 - 786 881 if (shn_abs) { 787 882 /* 788 883 * Whitelisted absolute symbols do not require ··· 984 1101 /* Order the relocations for more efficient processing */ 985 1102 sort_relocs(&relocs32); 986 1103 #if ELF_BITS == 64 987 - sort_relocs(&relocs32neg); 988 1104 sort_relocs(&relocs64); 989 1105 #else 990 1106 sort_relocs(&relocs16); ··· 1015 1133 /* Now print each relocation */ 1016 1134 for (i = 0; i < relocs64.count; i++) 1017 1135 write_reloc(relocs64.offset[i], stdout); 1018 - 1019 - /* Print a stop */ 1020 - write_reloc(0, stdout); 1021 - 1022 - /* Now print each inverse 32-bit relocation */ 1023 - for (i = 0; i < relocs32neg.count; i++) 1024 - write_reloc(relocs32neg.offset[i], stdout); 1025 1136 #endif 1026 1137 1027 1138 /* Print a stop */ ··· 1066 1191 read_strtabs(fp); 1067 1192 read_symtabs(fp); 1068 1193 read_relocs(fp); 1069 - 1070 - if (ELF_BITS == 64) 1071 - percpu_init(); 1072 1194 1073 1195 if (show_absolute_syms) { 1074 1196 print_absolute_symbols();