aboutsummaryrefslogtreecommitdiffstats
path: root/win32/win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/win32.c')
-rw-r--r--win32/win32.c69
1 files changed, 67 insertions, 2 deletions
diff --git a/win32/win32.c b/win32/win32.c
index 80fb30de43..c51d53595f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -2615,9 +2615,73 @@ set_pioinfo_extra(void)
* * https://bugs.ruby-lang.org/issues/18605
*/
char *p = (char*)get_proc_address(UCRTBASE, "_isatty", NULL);
- char *pend = p;
/* _osfile(fh) & FDEV */
+#ifdef _M_ARM64
+#define IS_INSN(pc, name) ((*(pc) & name##_mask) == name##_id)
+ const int max_num_inst = 500;
+ uint32_t *start = (uint32_t*)p;
+ uint32_t *end_limit = (start + max_num_inst);
+ uint32_t *pc = start;
+
+ if (!p) {
+ fprintf(stderr, "_isatty proc not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* end of function */
+ const uint32_t ret_id = 0xd65f0000;
+ const uint32_t ret_mask = 0xfffffc1f;
+ for(; pc < end_limit; pc++) {
+ if (IS_INSN(pc, ret)) {
+ break;
+ }
+ }
+ if (pc == end_limit) {
+ fprintf(stderr, "end of _isatty not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* pioinfo instruction mark */
+ const uint32_t adrp_id = 0x90000000;
+ const uint32_t adrp_mask = 0x9f000000;
+ const uint32_t add_id = 0x11000000;
+ const uint32_t add_mask = 0x3fc00000;
+ for(; pc > start; pc--) {
+ if (IS_INSN(pc, adrp) && IS_INSN(pc + 1, add)) {
+ break;
+ }
+ }
+ if(pc == start) {
+ fprintf(stderr, "pioinfo mark not found in " UCRTBASE "\n");
+ _exit(1);
+ }
+
+ /* We now point to instructions that load address of __pioinfo:
+ * adrp x8, 0x1801d8000
+ * add x8, x8, #0xdb0
+ * https://devblogs.microsoft.com/oldnewthing/20220809-00/?p=106955
+ * The last adrp/add sequence before ret is what we are looking for.
+ */
+ const uint32_t adrp_insn = *pc;
+ const uint32_t adrp_immhi = (adrp_insn & 0x00ffffe0) >> 5;
+ const uint32_t adrp_immlo = (adrp_insn & 0x60000000) >> (5 + 19 + 5);
+ /* imm = immhi:immlo:Zeros(12), 64 */
+ const uint64_t adrp_imm = ((adrp_immhi << 2) | adrp_immlo) << 12;
+ /* base = PC64<63:12>:Zeros(12) */
+ const uint64_t adrp_base = (uint64_t)pc & 0xfffffffffffff000;
+
+ const uint32_t add_insn = *(pc + 1);
+ const uint32_t add_sh = (add_insn & 0x400000) >> (12 + 5 + 5);
+ /* case sh of
+ when '0' imm = ZeroExtend(imm12, datasize);
+ when '1' imm = ZeroExtend(imm12:Zeros(12), datasize); */
+ const uint64_t add_imm = ((add_insn & 0x3ffc00) >> (5 + 5)) << (add_sh ? 12 : 0);
+
+ __pioinfo = (ioinfo**)(adrp_base + adrp_imm + add_imm);
+#else /* _M_ARM64 */
+ char *pend = p;
+
# ifdef _WIN64
int32_t rel;
char *rip;
@@ -2667,7 +2731,8 @@ set_pioinfo_extra(void)
#else
__pioinfo = *(ioinfo***)(p);
#endif
-#endif
+#endif /* _M_ARM64 */
+#endif /* RUBY_MSVCRT_VERSION */
int fd;
fd = _open("NUL", O_RDONLY);