t.Fatalf("Program exited with error: %v\n%s", err, &stderr)
        }
 }
+
+func TestIssue59213(t *testing.T) {
+       if runtime.GOOS != "windows" {
+               t.Skip("skipping windows only test")
+       }
+       if *flagQuick {
+               t.Skip("-quick")
+       }
+       testenv.MustHaveGoBuild(t)
+       testenv.MustHaveCGO(t)
+
+       goEnv := func(arg string) string {
+               cmd := testenv.Command(t, testenv.GoToolPath(t), "env", arg)
+               cmd.Stderr = new(bytes.Buffer)
+
+               line, err := cmd.Output()
+               if err != nil {
+                       t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr)
+               }
+               out := string(bytes.TrimSpace(line))
+               t.Logf("%v: %q", cmd, out)
+               return out
+       }
+
+       cc := goEnv("CC")
+       cgoCflags := goEnv("CGO_CFLAGS")
+
+       t.Parallel()
+
+       tmpdir := t.TempDir()
+       dllfile := filepath.Join(tmpdir, "test.dll")
+       exefile := filepath.Join(tmpdir, "gotest.exe")
+
+       // build go dll
+       cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", dllfile, "-buildmode", "c-shared", "testdata/testwintls/main.go")
+       out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
+       if err != nil {
+               t.Fatalf("failed to build go library: %s\n%s", err, out)
+       }
+
+       // build c program
+       cmd = testenv.Command(t, cc, "-o", exefile, "testdata/testwintls/main.c")
+       testenv.CleanCmdEnv(cmd)
+       cmd.Env = append(cmd.Env, "CGO_CFLAGS="+cgoCflags)
+       out, err = cmd.CombinedOutput()
+       if err != nil {
+               t.Fatalf("failed to build c exe: %s\n%s", err, out)
+       }
+
+       // run test program
+       cmd = testenv.Command(t, exefile, dllfile, "GoFunc")
+       out, err = testenv.CleanCmdEnv(cmd).CombinedOutput()
+       if err != nil {
+               t.Fatalf("failed: %s\n%s", err, out)
+       }
+}
 
 
 // Offsets into Thread Environment Block (pointer in FS)
 #define TEB_TlsSlots 0xE10
+#define TEB_ArbitraryPtr 0x14
 
 // void runtime·asmstdcall(void *c);
 TEXT runtime·asmstdcall(SB),NOSPLIT,$0
        // Assert that slot is less than 64 so we can use _TEB->TlsSlots
        CMPL    CX, $64
        JB      ok
-       CALL    runtime·abort(SB)
+       // Fallback to the TEB arbitrary pointer.
+       // TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
+       MOVL    $TEB_ArbitraryPtr, CX
+       JMP     settls
 ok:
        // Convert the TLS index at CX into
        // an offset from TEB_TlsSlots.
 
        // Save offset from TLS into tls_g.
        ADDL    $TEB_TlsSlots, CX
+settls:
        MOVL    CX, runtime·tls_g(SB)
        RET
 
 
 // Offsets into Thread Environment Block (pointer in GS)
 #define TEB_TlsSlots 0x1480
+#define TEB_ArbitraryPtr 0x28
 
 // void runtime·asmstdcall(void *c);
 TEXT runtime·asmstdcall(SB),NOSPLIT,$16
        // Assert that slot is less than 64 so we can use _TEB->TlsSlots
        CMPQ    CX, $64
        JB      ok
-       CALL    runtime·abort(SB)
+
+       // Fallback to the TEB arbitrary pointer.
+       // TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
+       MOVQ    $TEB_ArbitraryPtr, CX
+       JMP     settls
 ok:
        // Convert the TLS index at CX into
        // an offset from TEB_TlsSlots.
 
        // Save offset from TLS into tls_g.
        ADDQ    $TEB_TlsSlots, CX
+settls:
        MOVQ    CX, runtime·tls_g(SB)
        RET
 
 // Offsets into Thread Environment Block (pointer in R18)
 #define TEB_error 0x68
 #define TEB_TlsSlots 0x1480
+#define TEB_ArbitraryPtr 0x28
 
 // Note: R0-R7 are args, R8 is indirect return value address,
 // R9-R15 are caller-save, R19-R29 are callee-save.
        // Assert that slot is less than 64 so we can use _TEB->TlsSlots
        CMP     $64, R0
        BLT     ok
-       MOVD    $runtime·abort(SB), R1
-       BL      (R1)
+       // Fallback to the TEB arbitrary pointer.
+       // TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
+       MOVD    $TEB_ArbitraryPtr, R0
+       B       settls
 ok:
 
        // Save offset from R18 into tls_g.
        LSL     $3, R0
        ADD     $TEB_TlsSlots, R0
+settls:
        MOVD    R0, runtime·tls_g(SB)
        RET
 
--- /dev/null
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <windows.h>
+
+int main(int argc, char **argv) {
+    if (argc < 3) {
+        return 1;
+    }
+    // Allocate more than 64 TLS indices
+    // so the Go runtime doesn't find
+    // enough space in the TEB TLS slots.
+    for (int i = 0; i < 65; i++) {
+        TlsAlloc();
+    }
+    HMODULE hlib = LoadLibrary(argv[1]);
+    if (hlib == NULL) {
+        return 2;
+    }
+    FARPROC proc = GetProcAddress(hlib, argv[2]);
+    if (proc == NULL) {
+        return 3;
+    }
+    if (proc() != 42) {
+        return 4;
+    }
+    return 0;
+}
\ No newline at end of file
 
--- /dev/null
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "C"
+
+//export GoFunc
+func GoFunc() int { return 42 }
+
+func main() {}