diff options
| -rw-r--r-- | tools/objtool/include/objtool/klp.h | 5 | ||||
| -rw-r--r-- | tools/objtool/klp-diff.c | 31 |
2 files changed, 23 insertions, 13 deletions
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h index 646d8e1f12ef..c57775d78c71 100644 --- a/tools/objtool/include/objtool/klp.h +++ b/tools/objtool/include/objtool/klp.h @@ -20,8 +20,9 @@ * SHF_RELA_LIVEPATCH, nor does it support having two RELA sections for a * single PROGBITS section. * - * "objname" is the name of the object being patched ("vmlinux" or a module - * name). post-link uses it to name the resulting + * "objname" is the object whose loading gates the relocation: "vmlinux" for + * references to vmlinux symbols, otherwise the name of the module being + * patched. post-link uses it to name the resulting * .klp.rela.objname.section_name sections. */ #define KLP_RELOCS_SEC "__klp_relocs" diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index a66049e0726a..16681a76f13d 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -1344,13 +1344,14 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, struct section *sec, unsigned long offset, struct export *export) { + const char *sym_modname, *sym_orig_name, *sec_objname; struct symbol *patched_sym = patched_reloc->sym; s64 addend = reloc_addend(patched_reloc); - const char *sym_modname, *sym_orig_name; - static struct section *klp_relocs; char tombstone_name[SYM_NAME_LEN]; struct symbol *sym, *klp_sym; unsigned long klp_reloc_off; + struct section *klp_relocs; + char sec_name[SEC_NAME_LEN]; char sym_name[SYM_NAME_LEN]; struct klp_reloc klp_reloc; unsigned long sympos; @@ -1441,20 +1442,28 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, * This intermediate step is necessary to prevent corruption by the * linker, which doesn't know how to properly handle two rela sections * applying to the same base section. + * + * The objname decides when the reloc gets applied. A reference to a + * vmlinux symbol goes in the vmlinux section so it gets applied when + * the patch module loads. Everything else goes in the patched + * object's section, applied when the patched module is loaded. */ - if (!klp_relocs) { - const char *objname = find_modname(e); - char sec_name[SEC_NAME_LEN]; - - if (!objname) + if (!strcmp(sym_modname, "vmlinux")) { + sec_objname = "vmlinux"; + } else { + sec_objname = find_modname(e); + if (!sec_objname) return -1; + } - /* section format: __klp_relocs.objname */ - if (snprintf_check(sec_name, SEC_NAME_LEN, - KLP_RELOCS_SEC ".%s", objname)) - return -1; + /* section format: __klp_relocs.objname */ + if (snprintf_check(sec_name, SEC_NAME_LEN, + KLP_RELOCS_SEC ".%s", sec_objname)) + return -1; + klp_relocs = find_section_by_name(e->out, sec_name); + if (!klp_relocs) { klp_relocs = elf_create_section(e->out, sec_name, 0, 0, SHT_PROGBITS, 8, SHF_ALLOC); if (!klp_relocs) |
