lkml.org 
[lkml]   [2021]   [Oct]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 1/9] objtool,x86: Replace alternatives with .retpoline_sites
    Instead of writing complete alternatives, simply provide a list of all
    the retpoline thunk calls. Then the kernel is free to do with them as
    it pleases. Simpler code all-round.

    Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    ---
    arch/x86/kernel/vmlinux.lds.S | 12 +++
    arch/x86/lib/retpoline.S | 42 ------------
    tools/objtool/arch/x86/decode.c | 126 +++++++-----------------------------
    tools/objtool/elf.c | 84 ------------------------
    tools/objtool/include/objtool/elf.h | 1
    5 files changed, 38 insertions(+), 227 deletions(-)

    --- a/arch/x86/kernel/vmlinux.lds.S
    +++ b/arch/x86/kernel/vmlinux.lds.S
    @@ -273,6 +273,18 @@ SECTIONS
    }

    /*
    + * List of instructions that call/jmp/jcc to retpoline thunks
    + * __x86_indirect_thunk_*(). These instructions can be patched along
    + * with alternatives, after which the section can be freed.
    + */
    + . = ALIGN(8);
    + .retpoline_sites : AT(ADDR(.retpoline_sites) - LOAD_OFFSET) {
    + __retpoline_sites = .;
    + *(.retpoline_sites)
    + __retpoline_sites_end = .;
    + }
    +
    + /*
    * struct alt_inst entries. From the header (alternative.h):
    * "Alternative instructions for different CPU types or capabilities"
    * Think locking instructions on spinlocks.
    --- a/tools/objtool/arch/x86/decode.c
    +++ b/tools/objtool/arch/x86/decode.c
    @@ -711,121 +711,47 @@ const char *arch_ret_insn(int len)
    return ret[len-1];
    }

    -/* asm/alternative.h ? */
    -
    -#define ALTINSTR_FLAG_INV (1 << 15)
    -#define ALT_NOT(feat) ((feat) | ALTINSTR_FLAG_INV)
    -
    -struct alt_instr {
    - s32 instr_offset; /* original instruction */
    - s32 repl_offset; /* offset to replacement instruction */
    - u16 cpuid; /* cpuid bit set for replacement */
    - u8 instrlen; /* length of original instruction */
    - u8 replacementlen; /* length of new instruction */
    -} __packed;
    -
    -static int elf_add_alternative(struct elf *elf,
    - struct instruction *orig, struct symbol *sym,
    - int cpuid, u8 orig_len, u8 repl_len)
    +int arch_rewrite_retpolines(struct objtool_file *file)
    {
    - const int size = sizeof(struct alt_instr);
    - struct alt_instr *alt;
    + struct instruction *insn;
    struct section *sec;
    - Elf_Scn *s;
    -
    - sec = find_section_by_name(elf, ".altinstructions");
    - if (!sec) {
    - sec = elf_create_section(elf, ".altinstructions",
    - SHF_ALLOC, 0, 0);
    -
    - if (!sec) {
    - WARN_ELF("elf_create_section");
    - return -1;
    - }
    - }
    -
    - s = elf_getscn(elf->elf, sec->idx);
    - if (!s) {
    - WARN_ELF("elf_getscn");
    - return -1;
    - }
    + int idx;

    - sec->data = elf_newdata(s);
    - if (!sec->data) {
    - WARN_ELF("elf_newdata");
    - return -1;
    + sec = find_section_by_name(file->elf, ".retpoline_sites");
    + if (sec) {
    + WARN("file already has .retpoline_sites, skipping");
    + return 0;
    }

    - sec->data->d_size = size;
    - sec->data->d_align = 1;
    -
    - alt = sec->data->d_buf = malloc(size);
    - if (!sec->data->d_buf) {
    - perror("malloc");
    - return -1;
    - }
    - memset(sec->data->d_buf, 0, size);
    + idx = 0;
    + list_for_each_entry(insn, &file->retpoline_call_list, call_node)
    + idx++;

    - if (elf_add_reloc_to_insn(elf, sec, sec->sh.sh_size,
    - R_X86_64_PC32, orig->sec, orig->offset)) {
    - WARN("elf_create_reloc: alt_instr::instr_offset");
    - return -1;
    - }
    + if (!idx)
    + return 0;

    - if (elf_add_reloc(elf, sec, sec->sh.sh_size + 4,
    - R_X86_64_PC32, sym, 0)) {
    - WARN("elf_create_reloc: alt_instr::repl_offset");
    + sec = elf_create_section(file->elf, ".retpoline_sites", 0,
    + sizeof(int), idx);
    + if (!sec) {
    + WARN("elf_create_section: .retpoline_sites");
    return -1;
    }

    - alt->cpuid = bswap_if_needed(cpuid);
    - alt->instrlen = orig_len;
    - alt->replacementlen = repl_len;
    -
    - sec->sh.sh_size += size;
    - sec->changed = true;
    -
    - return 0;
    -}
    -
    -#define X86_FEATURE_RETPOLINE ( 7*32+12)
    -
    -int arch_rewrite_retpolines(struct objtool_file *file)
    -{
    - struct instruction *insn;
    - struct reloc *reloc;
    - struct symbol *sym;
    - char name[32] = "";
    -
    + idx = 0;
    list_for_each_entry(insn, &file->retpoline_call_list, call_node) {

    - if (insn->type != INSN_JUMP_DYNAMIC &&
    - insn->type != INSN_CALL_DYNAMIC)
    - continue;
    -
    - if (!strcmp(insn->sec->name, ".text.__x86.indirect_thunk"))
    - continue;
    -
    - reloc = insn->reloc;
    -
    - sprintf(name, "__x86_indirect_alt_%s_%s",
    - insn->type == INSN_JUMP_DYNAMIC ? "jmp" : "call",
    - reloc->sym->name + 21);
    -
    - sym = find_symbol_by_name(file->elf, name);
    - if (!sym) {
    - sym = elf_create_undef_symbol(file->elf, name);
    - if (!sym) {
    - WARN("elf_create_undef_symbol");
    - return -1;
    - }
    - }
    + int *site = (int *)sec->data->d_buf + idx;
    + *site = 0;

    - if (elf_add_alternative(file->elf, insn, sym,
    - ALT_NOT(X86_FEATURE_RETPOLINE), 5, 5)) {
    - WARN("elf_add_alternative");
    + if (elf_add_reloc_to_insn(file->elf, sec,
    + idx * sizeof(int),
    + R_X86_64_PC32,
    + insn->sec, insn->offset)) {
    + WARN("elf_add_reloc_to_insn: .retpoline_sites");
    return -1;
    }
    +
    + idx++;
    }

    return 0;
    --- a/tools/objtool/elf.c
    +++ b/tools/objtool/elf.c
    @@ -740,90 +740,6 @@ static int elf_add_string(struct elf *el
    return len;
    }

    -struct symbol *elf_create_undef_symbol(struct elf *elf, const char *name)
    -{
    - struct section *symtab, *symtab_shndx;
    - struct symbol *sym;
    - Elf_Data *data;
    - Elf_Scn *s;
    -
    - sym = malloc(sizeof(*sym));
    - if (!sym) {
    - perror("malloc");
    - return NULL;
    - }
    - memset(sym, 0, sizeof(*sym));
    -
    - sym->name = strdup(name);
    -
    - sym->sym.st_name = elf_add_string(elf, NULL, sym->name);
    - if (sym->sym.st_name == -1)
    - return NULL;
    -
    - sym->sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
    - // st_other 0
    - // st_shndx 0
    - // st_value 0
    - // st_size 0
    -
    - symtab = find_section_by_name(elf, ".symtab");
    - if (!symtab) {
    - WARN("can't find .symtab");
    - return NULL;
    - }
    -
    - s = elf_getscn(elf->elf, symtab->idx);
    - if (!s) {
    - WARN_ELF("elf_getscn");
    - return NULL;
    - }
    -
    - data = elf_newdata(s);
    - if (!data) {
    - WARN_ELF("elf_newdata");
    - return NULL;
    - }
    -
    - data->d_buf = &sym->sym;
    - data->d_size = sizeof(sym->sym);
    - data->d_align = 1;
    - data->d_type = ELF_T_SYM;
    -
    - sym->idx = symtab->sh.sh_size / sizeof(sym->sym);
    -
    - symtab->sh.sh_size += data->d_size;
    - symtab->changed = true;
    -
    - symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
    - if (symtab_shndx) {
    - s = elf_getscn(elf->elf, symtab_shndx->idx);
    - if (!s) {
    - WARN_ELF("elf_getscn");
    - return NULL;
    - }
    -
    - data = elf_newdata(s);
    - if (!data) {
    - WARN_ELF("elf_newdata");
    - return NULL;
    - }
    -
    - data->d_buf = &sym->sym.st_size; /* conveniently 0 */
    - data->d_size = sizeof(Elf32_Word);
    - data->d_align = 4;
    - data->d_type = ELF_T_WORD;
    -
    - symtab_shndx->sh.sh_size += 4;
    - symtab_shndx->changed = true;
    - }
    -
    - sym->sec = find_section_by_index(elf, 0);
    -
    - elf_add_symbol(elf, sym);
    -
    - return sym;
    -}
    -
    struct section *elf_create_section(struct elf *elf, const char *name,
    unsigned int sh_flags, size_t entsize, int nr)
    {
    --- a/tools/objtool/include/objtool/elf.h
    +++ b/tools/objtool/include/objtool/elf.h
    @@ -141,7 +141,6 @@ int elf_write_insn(struct elf *elf, stru
    unsigned long offset, unsigned int len,
    const char *insn);
    int elf_write_reloc(struct elf *elf, struct reloc *reloc);
    -struct symbol *elf_create_undef_symbol(struct elf *elf, const char *name);
    int elf_write(struct elf *elf);
    void elf_close(struct elf *elf);


    \
     
     \ /
      Last update: 2021-10-13 14:43    [W:4.170 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site