Print this page
9059 Simplify SMAP relocations with krtld
Portions contributed by: John Levon <john.levon@joyent.com>

@@ -117,10 +117,61 @@
                 instr[i - 1] = SDT_NOP;
 
         return (0);
 }
 
+
+/*
+ * We're relying on the fact that the call we're replacing is
+ * call (e8) plus 4 bytes of address, making a 5 byte instruction
+ */
+#define NOP_INSTR       0x90
+#define SMAP_NOPS       5
+
+/*
+ * Currently the only call replaced as a hot inline
+ * is smap_enable() and smap_disable(). If more are needed
+ * we should probably come up with an sdt probe like prefix
+ * and look for those instead of exact call names.
+ */
+static int
+smap_reloc_resolve(struct module *mp, char *symname, uint8_t *instr)
+{
+        uint_t symlen;
+        hotinline_desc_t *hid;
+
+        if (strcmp(symname, "smap_enable") == 0 ||
+            strcmp(symname, "smap_disable") == 0) {
+
+#ifdef  KOBJ_DEBUG
+                if (kobj_debug & D_RELOCATIONS) {
+                        _kobj_printf(ops, "smap_reloc_resolve: %s relocating "
+                            "enable/disable_smap\n", mp->filename);
+                }
+#endif
+
+                hid = kobj_alloc(sizeof (hotinline_desc_t), KM_WAIT);
+                symlen = strlen(symname) + 1;
+                hid->hid_symname = kobj_alloc(symlen, KM_WAIT);
+                bcopy(symname, hid->hid_symname, symlen);
+
+                /*
+                 * We backtrack one byte here to consume the call
+                 * instruction itself.
+                 */
+                hid->hid_instr_offset = (uintptr_t)instr - 1;
+                hid->hid_next = mp->hi_calls;
+                mp->hi_calls = hid;
+
+                memset((void *)hid->hid_instr_offset, NOP_INSTR, SMAP_NOPS);
+
+                return (0);
+        }
+
+        return (1);
+}
+
 int
 do_relocate(struct module *mp, char *reltbl, int nreloc, int relocsize,
     Addr baseaddr)
 {
         unsigned long stndx;

@@ -218,10 +269,15 @@
                                  */
                                 if (symref->st_shndx == SHN_UNDEF &&
                                     sdt_reloc_resolve(mp, mp->strings +
                                     symref->st_name, (uint8_t *)off) == 0)
                                         continue;
+
+                                if (symref->st_shndx == SHN_UNDEF &&
+                                    smap_reloc_resolve(mp, mp->strings +
+                                    symref->st_name, (uint8_t *)off) == 0)
+                                        continue;
 
                                 if (symref->st_shndx == SHN_UNDEF &&
                                     tnf_reloc_resolve(mp->strings +
                                     symref->st_name, &symref->st_value,
                                     &addend, off, &probelist, &taglist) != 0) {