mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
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
This commit is contained in:
parent
b5c4f95351
commit
a8327be7b2
|
|
@ -235,7 +235,7 @@ static void handle_relocations(void *output, unsigned long output_len,
|
|||
|
||||
/*
|
||||
* Process relocations: 32 bit relocations first then 64 bit after.
|
||||
* Three sets of binary relocations are added to the end of the kernel
|
||||
* Two sets of binary relocations are added to the end of the kernel
|
||||
* before compression. Each relocation table entry is the kernel
|
||||
* address of the location which needs to be updated stored as a
|
||||
* 32-bit value which is sign extended to 64 bits.
|
||||
|
|
@ -245,8 +245,6 @@ static void handle_relocations(void *output, unsigned long output_len,
|
|||
* kernel bits...
|
||||
* 0 - zero terminator for 64 bit relocations
|
||||
* 64 bit relocation repeated
|
||||
* 0 - zero terminator for inverse 32 bit relocations
|
||||
* 32 bit inverse relocation repeated
|
||||
* 0 - zero terminator for 32 bit relocations
|
||||
* 32 bit relocation repeated
|
||||
*
|
||||
|
|
@ -263,16 +261,6 @@ static void handle_relocations(void *output, unsigned long output_len,
|
|||
*(uint32_t *)ptr += delta;
|
||||
}
|
||||
#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--) {
|
||||
long extended = *reloc;
|
||||
extended += map;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ static struct relocs relocs16;
|
|||
static struct relocs relocs32;
|
||||
|
||||
#if ELF_BITS == 64
|
||||
static struct relocs relocs32neg;
|
||||
static struct relocs relocs64;
|
||||
# define FMT PRIu64
|
||||
|
||||
|
|
@ -91,7 +90,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
|
|||
"__initramfs_start|"
|
||||
"(jiffies|jiffies_64)|"
|
||||
#if ELF_BITS == 64
|
||||
"__per_cpu_load|"
|
||||
"init_per_cpu__.*|"
|
||||
"__end_rodata_hpage_align|"
|
||||
#endif
|
||||
|
|
@ -290,34 +288,6 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
|
|||
return name;
|
||||
}
|
||||
|
||||
static Elf_Sym *sym_lookup(const char *symname)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < shnum; i++) {
|
||||
struct section *sec = &secs[i];
|
||||
long nsyms;
|
||||
char *strtab;
|
||||
Elf_Sym *symtab;
|
||||
Elf_Sym *sym;
|
||||
|
||||
if (sec->shdr.sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
|
||||
nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
|
||||
symtab = sec->symtab;
|
||||
strtab = sec->link->strtab;
|
||||
|
||||
for (sym = symtab; --nsyms >= 0; sym++) {
|
||||
if (!sym->st_name)
|
||||
continue;
|
||||
if (strcmp(symname, strtab + sym->st_name) == 0)
|
||||
return sym;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define le16_to_cpu(val) (val)
|
||||
# define le32_to_cpu(val) (val)
|
||||
|
|
@ -766,78 +736,8 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The .data..percpu section is a special case for x86_64 SMP kernels.
|
||||
* It is used to initialize the actual per_cpu areas and to provide
|
||||
* definitions for the per_cpu variables that correspond to their offsets
|
||||
* within the percpu area. Since the values of all of the symbols need
|
||||
* to be offsets from the start of the per_cpu area the virtual address
|
||||
* (sh_addr) of .data..percpu is 0 in SMP kernels.
|
||||
*
|
||||
* This means that:
|
||||
*
|
||||
* Relocations that reference symbols in the per_cpu area do not
|
||||
* need further relocation (since the value is an offset relative
|
||||
* to the start of the per_cpu area that does not change).
|
||||
*
|
||||
* Relocations that apply to the per_cpu area need to have their
|
||||
* offset adjusted by by the value of __per_cpu_load to make them
|
||||
* point to the correct place in the loaded image (because the
|
||||
* virtual address of .data..percpu is 0).
|
||||
*
|
||||
* For non SMP kernels .data..percpu is linked as part of the normal
|
||||
* kernel data and does not require special treatment.
|
||||
*
|
||||
*/
|
||||
static int per_cpu_shndx = -1;
|
||||
static Elf_Addr per_cpu_load_addr;
|
||||
|
||||
static void percpu_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < shnum; i++) {
|
||||
ElfW(Sym) *sym;
|
||||
|
||||
if (strcmp(sec_name(i), ".data..percpu"))
|
||||
continue;
|
||||
|
||||
if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */
|
||||
return;
|
||||
|
||||
sym = sym_lookup("__per_cpu_load");
|
||||
if (!sym)
|
||||
die("can't find __per_cpu_load\n");
|
||||
|
||||
per_cpu_shndx = i;
|
||||
per_cpu_load_addr = sym->st_value;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if ELF_BITS == 64
|
||||
|
||||
/*
|
||||
* Check to see if a symbol lies in the .data..percpu section.
|
||||
*
|
||||
* The linker incorrectly associates some symbols with the
|
||||
* .data..percpu section so we also need to check the symbol
|
||||
* name to make sure that we classify the symbol correctly.
|
||||
*
|
||||
* The GNU linker incorrectly associates:
|
||||
* __init_begin
|
||||
* __per_cpu_load
|
||||
*
|
||||
* The "gold" linker incorrectly associates:
|
||||
* init_per_cpu__gdt_page
|
||||
*/
|
||||
static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
|
||||
const char *symname)
|
||||
{
|
||||
|
|
@ -848,12 +748,6 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
|
|||
if (sym->st_shndx == SHN_UNDEF)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Adjust the offset if this reloc applies to the percpu section.
|
||||
*/
|
||||
if (sec->shdr.sh_info == per_cpu_shndx)
|
||||
offset += per_cpu_load_addr;
|
||||
|
||||
switch (r_type) {
|
||||
case R_X86_64_NONE:
|
||||
/* NONE can be ignored. */
|
||||
|
|
@ -863,32 +757,21 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
|
|||
case R_X86_64_PLT32:
|
||||
case R_X86_64_REX_GOTPCRELX:
|
||||
/*
|
||||
* PC relative relocations don't need to be adjusted unless
|
||||
* referencing a percpu symbol.
|
||||
* PC relative relocations don't need to be adjusted.
|
||||
*
|
||||
* NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
|
||||
*/
|
||||
if (is_percpu_sym(sym, symname))
|
||||
add_reloc(&relocs32neg, offset);
|
||||
break;
|
||||
|
||||
case R_X86_64_PC64:
|
||||
/*
|
||||
* Only used by jump labels
|
||||
*/
|
||||
if (is_percpu_sym(sym, symname))
|
||||
die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n", symname);
|
||||
break;
|
||||
|
||||
case R_X86_64_32:
|
||||
case R_X86_64_32S:
|
||||
case R_X86_64_64:
|
||||
/*
|
||||
* References to the percpu area don't need to be adjusted.
|
||||
*/
|
||||
if (is_percpu_sym(sym, symname))
|
||||
break;
|
||||
|
||||
if (shn_abs) {
|
||||
/*
|
||||
* Whitelisted absolute symbols do not require
|
||||
|
|
@ -1101,7 +984,6 @@ static void emit_relocs(int as_text, int use_real_mode)
|
|||
/* Order the relocations for more efficient processing */
|
||||
sort_relocs(&relocs32);
|
||||
#if ELF_BITS == 64
|
||||
sort_relocs(&relocs32neg);
|
||||
sort_relocs(&relocs64);
|
||||
#else
|
||||
sort_relocs(&relocs16);
|
||||
|
|
@ -1133,13 +1015,6 @@ static void emit_relocs(int as_text, int use_real_mode)
|
|||
/* Now print each relocation */
|
||||
for (i = 0; i < relocs64.count; i++)
|
||||
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 */
|
||||
|
|
@ -1192,9 +1067,6 @@ void process(FILE *fp, int use_real_mode, int as_text,
|
|||
read_symtabs(fp);
|
||||
read_relocs(fp);
|
||||
|
||||
if (ELF_BITS == 64)
|
||||
percpu_init();
|
||||
|
||||
if (show_absolute_syms) {
|
||||
print_absolute_symbols();
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user