From: Jeremy Drake <cyg...@jdrake.com>

This is in preparation for rewriting it using udis86, and adding an
implementation for aarch64 hosts.

Signed-off-by: Jeremy Drake <cyg...@jdrake.com>
---
 winsup/cygwin/Makefile.am              |   1 +
 winsup/cygwin/path.cc                  | 122 +----------------------
 winsup/cygwin/x86_64/fastcwd_x86_64.cc | 128 +++++++++++++++++++++++++
 3 files changed, 134 insertions(+), 117 deletions(-)
 create mode 100644 winsup/cygwin/x86_64/fastcwd_x86_64.cc

diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am
index d47a1a2d11..9ede4249e3 100644
--- a/winsup/cygwin/Makefile.am
+++ b/winsup/cygwin/Makefile.am
@@ -52,6 +52,7 @@ LIB_NAME=libcygwin.a
 if TARGET_X86_64
 TARGET_FILES= \
        x86_64/bcopy.S \
+       x86_64/fastcwd_x86_64.cc \
        x86_64/memchr.S \
        x86_64/memcpy.S \
        x86_64/memmove.S \
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index d2aaed3143..3a5e2ee07e 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -4490,122 +4490,10 @@ fcwd_access_t::SetDirHandleFromBufferPointer (PWCHAR 
buf_p, HANDLE dir)
   f_cwd->DirectoryHandle = dir;
 }

-/* This function scans the code in ntdll.dll to find the address of the
-   global variable used to access the CWD.  While the pointer is global,
-   it's not exported from the DLL, unfortunately.  Therefore we have to
-   use some knowledge to figure out the address. */
-
-#define peek32(x)      (*(int32_t *)(x))
-
-static fcwd_access_t **
-find_fast_cwd_pointer ()
-{
-  /* Fetch entry points of relevant functions in ntdll.dll. */
-  HMODULE ntdll = GetModuleHandle ("ntdll.dll");
-  if (!ntdll)
-    return NULL;
-  const uint8_t *get_dir = (const uint8_t *)
-                          GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
-  const uint8_t *ent_crit = (const uint8_t *)
-                           GetProcAddress (ntdll, "RtlEnterCriticalSection");
-  if (!get_dir || !ent_crit)
-    return NULL;
-  /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
-  const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 80);
-  if (!rcall)
-    return NULL;
-  /* Fetch offset from instruction and compute address of called function.
-     This function actually fetches the current FAST_CWD instance and
-     performs some other actions, not important to us. */
-  const uint8_t *use_cwd = rcall + 5 + peek32 (rcall + 1);
-  /* Next we search for the locking mechanism and perform a sanity check.
-     On Pre-Windows 8 we basically look for the RtlEnterCriticalSection call.
-     Windows 8 does not call RtlEnterCriticalSection.  The code manipulates
-     the FastPebLock manually, probably because RtlEnterCriticalSection has
-     been converted to an inline function.  Either way, we test if the code
-     uses the FastPebLock. */
-  const uint8_t *movrbx;
-  const uint8_t *lock = (const uint8_t *)
-                        memmem ((const char *) use_cwd, 80,
-                                "\xf0\x0f\xba\x35", 4);
-  if (lock)
-    {
-      /* The lock instruction tweaks the LockCount member, which is not at
-        the start of the PRTL_CRITICAL_SECTION structure.  So we have to
-        subtract the offset of LockCount to get the real address. */
-      PRTL_CRITICAL_SECTION lockaddr =
-        (PRTL_CRITICAL_SECTION) (lock + 9 + peek32 (lock + 4)
-                                 - offsetof (RTL_CRITICAL_SECTION, LockCount));
-      /* Test if lock address is FastPebLock. */
-      if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
-        return NULL;
-      /* Search `mov rel(%rip),%rbx'.  This is the instruction fetching the
-         address of the current fcwd_access_t pointer, and it should be pretty
-        near to the locking stuff. */
-      movrbx = (const uint8_t *) memmem ((const char *) lock, 40,
-                                         "\x48\x8b\x1d", 3);
-    }
-  else
-    {
-      /* Usually the callq RtlEnterCriticalSection follows right after
-        fetching the lock address. */
-      int call_rtl_offset = 7;
-      /* Search `lea rel(%rip),%rcx'.  This loads the address of the lock into
-         %rcx for the subsequent RtlEnterCriticalSection call. */
-      lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
-                                       "\x48\x8d\x0d", 3);
-      if (!lock)
-       {
-         /* Windows 8.1 Preview calls `lea rel(rip),%r12' then some unrelated
-            ops, then `mov %r12,%rcx', then `callq RtlEnterCriticalSection'. */
-         lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
-                                          "\x4c\x8d\x25", 3);
-         call_rtl_offset = 14;
-       }
-
-      if (!lock)
-       {
-         /* A recent Windows 11 Preview calls `lea rel(rip),%r13' then
-            some unrelated instructions, then `callq RtlEnterCriticalSection'.
-            */
-         lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
-                                          "\x4c\x8d\x2d", 3);
-         call_rtl_offset = 24;
-       }
-
-      if (!lock)
-       {
-         return NULL;
-       }
-
-      PRTL_CRITICAL_SECTION lockaddr =
-        (PRTL_CRITICAL_SECTION) (lock + 7 + peek32 (lock + 3));
-      /* Test if lock address is FastPebLock. */
-      if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
-        return NULL;
-      /* Next is the `callq RtlEnterCriticalSection'. */
-      lock += call_rtl_offset;
-      if (lock[0] != 0xe8)
-        return NULL;
-      const uint8_t *call_addr = (const uint8_t *)
-                                 (lock + 5 + peek32 (lock + 1));
-      if (call_addr != ent_crit)
-        return NULL;
-      /* In contrast to the above Windows 8 code, we don't have to search
-        for the `mov rel(%rip),%rbx' instruction.  It follows right after
-        the call to RtlEnterCriticalSection. */
-      movrbx = lock + 5;
-    }
-  if (!movrbx)
-    return NULL;
-  /* Check that the next instruction tests if the fetched value is NULL. */
-  const uint8_t *testrbx = (const uint8_t *)
-                          memmem (movrbx + 7, 3, "\x48\x85\xdb", 3);
-  if (!testrbx)
-    return NULL;
-  /* Compute address of the fcwd_access_t ** pointer. */
-  return (fcwd_access_t **) (testrbx + peek32 (movrbx + 3));
-}
+#ifdef __x86_64__
+fcwd_access_t **
+find_fast_cwd_pointer_x86_64 ();
+#endif

 static fcwd_access_t **
 find_fast_cwd ()
@@ -4621,7 +4509,7 @@ find_fast_cwd ()
   /* Fetch the pointer but don't set the global fast_cwd_ptr yet.  First
      we have to make sure we know the version of the FAST_CWD structure
      used on the system. */
-  f_cwd_ptr = find_fast_cwd_pointer ();
+  f_cwd_ptr = find_fast_cwd_pointer_x86_64 ();
   if (!f_cwd_ptr)
     small_printf ("Cygwin WARNING:\n"
 "  Couldn't compute FAST_CWD pointer.  This typically occurs if you're using\n"
diff --git a/winsup/cygwin/x86_64/fastcwd_x86_64.cc 
b/winsup/cygwin/x86_64/fastcwd_x86_64.cc
new file mode 100644
index 0000000000..7765812f00
--- /dev/null
+++ b/winsup/cygwin/x86_64/fastcwd_x86_64.cc
@@ -0,0 +1,128 @@
+/* fastcwd_x86_64.cc: find fast cwd pointer on x86_64 hosts.
+
+  This file is part of Cygwin.
+
+  This software is a copyrighted work licensed under the terms of the
+  Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+  details. */
+
+#include "winsup.h"
+
+class fcwd_access_t;
+
+#define peek32(x)      (*(int32_t *)(x))
+
+/* This function scans the code in ntdll.dll to find the address of the
+   global variable used to access the CWD.  While the pointer is global,
+   it's not exported from the DLL, unfortunately.  Therefore we have to
+   use some knowledge to figure out the address. */
+
+fcwd_access_t **
+find_fast_cwd_pointer_x86_64 ()
+{
+  /* Fetch entry points of relevant functions in ntdll.dll. */
+  HMODULE ntdll = GetModuleHandle ("ntdll.dll");
+  if (!ntdll)
+    return NULL;
+  const uint8_t *get_dir = (const uint8_t *)
+                          GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
+  const uint8_t *ent_crit = (const uint8_t *)
+                           GetProcAddress (ntdll, "RtlEnterCriticalSection");
+  if (!get_dir || !ent_crit)
+    return NULL;
+  /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
+  const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 80);
+  if (!rcall)
+    return NULL;
+  /* Fetch offset from instruction and compute address of called function.
+     This function actually fetches the current FAST_CWD instance and
+     performs some other actions, not important to us. */
+  const uint8_t *use_cwd = rcall + 5 + peek32 (rcall + 1);
+  /* Next we search for the locking mechanism and perform a sanity check.
+     On Pre-Windows 8 we basically look for the RtlEnterCriticalSection call.
+     Windows 8 does not call RtlEnterCriticalSection.  The code manipulates
+     the FastPebLock manually, probably because RtlEnterCriticalSection has
+     been converted to an inline function.  Either way, we test if the code
+     uses the FastPebLock. */
+  const uint8_t *movrbx;
+  const uint8_t *lock = (const uint8_t *)
+                        memmem ((const char *) use_cwd, 80,
+                                "\xf0\x0f\xba\x35", 4);
+  if (lock)
+    {
+      /* The lock instruction tweaks the LockCount member, which is not at
+        the start of the PRTL_CRITICAL_SECTION structure.  So we have to
+        subtract the offset of LockCount to get the real address. */
+      PRTL_CRITICAL_SECTION lockaddr =
+        (PRTL_CRITICAL_SECTION) (lock + 9 + peek32 (lock + 4)
+                                 - offsetof (RTL_CRITICAL_SECTION, LockCount));
+      /* Test if lock address is FastPebLock. */
+      if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
+        return NULL;
+      /* Search `mov rel(%rip),%rbx'.  This is the instruction fetching the
+         address of the current fcwd_access_t pointer, and it should be pretty
+        near to the locking stuff. */
+      movrbx = (const uint8_t *) memmem ((const char *) lock, 40,
+                                         "\x48\x8b\x1d", 3);
+    }
+  else
+    {
+      /* Usually the callq RtlEnterCriticalSection follows right after
+        fetching the lock address. */
+      int call_rtl_offset = 7;
+      /* Search `lea rel(%rip),%rcx'.  This loads the address of the lock into
+         %rcx for the subsequent RtlEnterCriticalSection call. */
+      lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
+                                       "\x48\x8d\x0d", 3);
+      if (!lock)
+       {
+         /* Windows 8.1 Preview calls `lea rel(rip),%r12' then some unrelated
+            ops, then `mov %r12,%rcx', then `callq RtlEnterCriticalSection'. */
+         lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
+                                          "\x4c\x8d\x25", 3);
+         call_rtl_offset = 14;
+       }
+
+      if (!lock)
+       {
+         /* A recent Windows 11 Preview calls `lea rel(rip),%r13' then
+            some unrelated instructions, then `callq RtlEnterCriticalSection'.
+            */
+         lock = (const uint8_t *) memmem ((const char *) use_cwd, 80,
+                                          "\x4c\x8d\x2d", 3);
+         call_rtl_offset = 24;
+       }
+
+      if (!lock)
+       {
+         return NULL;
+       }
+
+      PRTL_CRITICAL_SECTION lockaddr =
+        (PRTL_CRITICAL_SECTION) (lock + 7 + peek32 (lock + 3));
+      /* Test if lock address is FastPebLock. */
+      if (lockaddr != NtCurrentTeb ()->Peb->FastPebLock)
+        return NULL;
+      /* Next is the `callq RtlEnterCriticalSection'. */
+      lock += call_rtl_offset;
+      if (lock[0] != 0xe8)
+        return NULL;
+      const uint8_t *call_addr = (const uint8_t *)
+                                 (lock + 5 + peek32 (lock + 1));
+      if (call_addr != ent_crit)
+        return NULL;
+      /* In contrast to the above Windows 8 code, we don't have to search
+        for the `mov rel(%rip),%rbx' instruction.  It follows right after
+        the call to RtlEnterCriticalSection. */
+      movrbx = lock + 5;
+    }
+  if (!movrbx)
+    return NULL;
+  /* Check that the next instruction tests if the fetched value is NULL. */
+  const uint8_t *testrbx = (const uint8_t *)
+                          memmem (movrbx + 7, 3, "\x48\x85\xdb", 3);
+  if (!testrbx)
+    return NULL;
+  /* Compute address of the fcwd_access_t ** pointer. */
+  return (fcwd_access_t **) (testrbx + peek32 (movrbx + 3));
+}
-- 
2.48.1.windows.1

Reply via email to