Print this page
10908 Simplify SMAP relocations with krtld

@@ -21,13 +21,14 @@
 
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
 
-#pragma ident   "%Z%%M% %I%     %E% SMI"
-
 /*
  * x86 relocation code.
  */
 
 #include <sys/types.h>

@@ -117,12 +118,62 @@
                 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
-/* ARGSUSED2 */
 do_relocate(struct module *mp, char *reltbl, Word relshtype, int nreloc,
         int relocsize, Addr baseaddr)
 {
         unsigned long stndx;
         unsigned long off;      /* can't be register for tnf_reloc_resolve() */

@@ -219,10 +270,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) {