[newlib-cygwin] Cygwin: factor out find_fast_cwd_pointer to arch-specific file.

Jeremy Drake via Cygwin-cvs <[email protected]>
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=3754840d7fc71e8d973ee40c2d1d101f826864ed

commit 3754840d7fc71e8d973ee40c2d1d101f826864ed
Author: Jeremy Drake <[email protected]>
Date:   Fri Mar 21 13:45:22 2025 -0700

    Cygwin: factor out find_fast_cwd_pointer to arch-specific file.
    
    This is in preparation for rewriting it using udis86, and adding an
    implementation for aarch64 hosts.
    
    Signed-off-by: Jeremy Drake <[email protected]>

Diff:
---
 winsup/cygwin/Makefile.am       |   1 +
 winsup/cygwin/path.cc           | 122 ++------------------------------------
 winsup/cygwin/x86_64/fastcwd.cc | 128 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+), 117 deletions(-)

diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am
index d47a1a2d1..a0e839701 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.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 d2aaed314..3a5e2ee07 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.cc b/winsup/cygwin/x86_64/fastcwd.cc
new file mode 100644
index 000000000..6bb8c2265
--- /dev/null
+++ b/winsup/cygwin/x86_64/fastcwd.cc
@@ -0,0 +1,128 @@
+/* x86_64/fastcwd.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));
+}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.