return -EINVAL;
 }
 
-static int klp_resolve_symbols(Elf_Shdr *relasec, struct module *pmod)
+static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab,
+                              unsigned int symndx, Elf_Shdr *relasec)
 {
        int i, cnt, vmlinux, ret;
        char objname[MODULE_NAME_LEN];
        char symname[KSYM_NAME_LEN];
-       char *strtab = pmod->core_kallsyms.strtab;
        Elf_Rela *relas;
        Elf_Sym *sym;
        unsigned long sympos, addr;
        relas = (Elf_Rela *) relasec->sh_addr;
        /* For each rela in this klp relocation section */
        for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) {
-               sym = pmod->core_kallsyms.symtab + ELF_R_SYM(relas[i].r_info);
+               sym = (Elf64_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info);
                if (sym->st_shndx != SHN_LIVEPATCH) {
                        pr_err("symbol %s is not marked as a livepatch symbol\n",
                               strtab + sym->st_name);
        return 0;
 }
 
-static int klp_write_object_relocations(struct module *pmod,
-                                       struct klp_object *obj)
+/*
+ * At a high-level, there are two types of klp relocation sections: those which
+ * reference symbols which live in vmlinux; and those which reference symbols
+ * which live in other modules.  This function is called for both types:
+ *
+ * 1) When a klp module itself loads, the module code calls this function to
+ *    write vmlinux-specific klp relocations (.klp.rela.vmlinux.* sections).
+ *    These relocations are written to the klp module text to allow the patched
+ *    code/data to reference unexported vmlinux symbols.  They're written as
+ *    early as possible to ensure that other module init code (.e.g.,
+ *    jump_label_apply_nops) can access any unexported vmlinux symbols which
+ *    might be referenced by the klp module's special sections.
+ *
+ * 2) When a to-be-patched module loads -- or is already loaded when a
+ *    corresponding klp module loads -- klp code calls this function to write
+ *    module-specific klp relocations (.klp.rela.{module}.* sections).  These
+ *    are written to the klp module text to allow the patched code/data to
+ *    reference symbols which live in the to-be-patched module or one of its
+ *    module dependencies.  Exported symbols are supported, in addition to
+ *    unexported symbols, in order to enable late module patching, which allows
+ *    the to-be-patched module to be loaded and patched sometime *after* the
+ *    klp module is loaded.
+ */
+int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
+                            const char *shstrtab, const char *strtab,
+                            unsigned int symndx, unsigned int secndx,
+                            const char *objname)
 {
-       int i, cnt, ret = 0;
-       const char *objname, *secname;
+       int cnt, ret;
        char sec_objname[MODULE_NAME_LEN];
-       Elf_Shdr *sec;
+       Elf_Shdr *sec = sechdrs + secndx;
 
-       if (WARN_ON(!klp_is_object_loaded(obj)))
+       /*
+        * Format: .klp.rela.sec_objname.section_name
+        * See comment in klp_resolve_symbols() for an explanation
+        * of the selected field width value.
+        */
+       cnt = sscanf(shstrtab + sec->sh_name, ".klp.rela.%55[^.]",
+                    sec_objname);
+       if (cnt != 1) {
+               pr_err("section %s has an incorrectly formatted name\n",
+                      shstrtab + sec->sh_name);
                return -EINVAL;
+       }
 
-       objname = klp_is_module(obj) ? obj->name : "vmlinux";
-
-       /* For each klp relocation section */
-       for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
-               sec = pmod->klp_info->sechdrs + i;
-               secname = pmod->klp_info->secstrings + sec->sh_name;
-               if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
-                       continue;
-
-               /*
-                * Format: .klp.rela.sec_objname.section_name
-                * See comment in klp_resolve_symbols() for an explanation
-                * of the selected field width value.
-                */
-               cnt = sscanf(secname, ".klp.rela.%55[^.]", sec_objname);
-               if (cnt != 1) {
-                       pr_err("section %s has an incorrectly formatted name\n",
-                              secname);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               if (strcmp(objname, sec_objname))
-                       continue;
-
-               ret = klp_resolve_symbols(sec, pmod);
-               if (ret)
-                       break;
+       if (strcmp(objname ? objname : "vmlinux", sec_objname))
+               return 0;
 
-               ret = apply_relocate_add(pmod->klp_info->sechdrs,
-                                        pmod->core_kallsyms.strtab,
-                                        pmod->klp_info->symndx, i, pmod);
-               if (ret)
-                       break;
-       }
+       ret = klp_resolve_symbols(sechdrs, strtab, symndx, sec);
+       if (ret)
+               return ret;
 
-       return ret;
+       return apply_relocate_add(sechdrs, strtab, symndx, secndx, pmod);
 }
 
 /*
 {
 }
 
+int klp_apply_object_relocs(struct klp_patch *patch, struct klp_object *obj)
+{
+       int i, ret;
+       struct klp_modinfo *info = patch->mod->klp_info;
+
+       for (i = 1; i < info->hdr.e_shnum; i++) {
+               Elf_Shdr *sec = info->sechdrs + i;
+
+               if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
+                       continue;
+
+               ret = klp_apply_section_relocs(patch->mod, info->sechdrs,
+                                              info->secstrings,
+                                              patch->mod->core_kallsyms.strtab,
+                                              info->symndx, i, obj->name);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 /* parts of the initialization that is done only when the object is loaded */
 static int klp_init_object_loaded(struct klp_patch *patch,
                                  struct klp_object *obj)
        int ret;
 
        mutex_lock(&text_mutex);
-
        module_disable_ro(patch->mod);
-       ret = klp_write_object_relocations(patch->mod, obj);
-       if (ret) {
-               module_enable_ro(patch->mod, true);
-               mutex_unlock(&text_mutex);
-               return ret;
+
+       if (klp_is_module(obj)) {
+               /*
+                * Only write module-specific relocations here
+                * (.klp.rela.{module}.*).  vmlinux-specific relocations were
+                * written earlier during the initialization of the klp module
+                * itself.
+                */
+               ret = klp_apply_object_relocs(patch, obj);
+               if (ret) {
+                       module_enable_ro(patch->mod, true);
+                       mutex_unlock(&text_mutex);
+                       return ret;
+               }
        }
 
        arch_klp_init_object_loaded(patch, obj);
-       module_enable_ro(patch->mod, true);
 
+       module_enable_ro(patch->mod, true);
        mutex_unlock(&text_mutex);
 
        klp_for_each_func(obj, func) {