1 | #include <cinttypes> |
2 | #include <cstdint> |
3 | #include <cstdio> |
4 | #include <mutex> |
5 | #include <thread> |
6 | |
7 | std::mutex t1_mutex, t2_mutex; |
8 | |
9 | struct test_data { |
10 | uint32_t eax; |
11 | uint32_t ebx; |
12 | |
13 | struct alignas(16) { |
14 | uint8_t data[10]; |
15 | } st0; |
16 | }; |
17 | |
18 | constexpr test_data filler = { |
19 | .eax = 0xffffffff, |
20 | .ebx = 0xffffffff, |
21 | .st0 = {.data: {0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f, 0x8f, 0x80, 0x40}}, |
22 | }; |
23 | |
24 | void t_func(std::mutex &t_mutex) { |
25 | std::lock_guard<std::mutex> t_lock(t_mutex); |
26 | test_data out = filler; |
27 | |
28 | asm volatile( |
29 | "finit\t\n" |
30 | "fldt %2\t\n" |
31 | "int3\n\t" |
32 | "fstpt %2\t\n" |
33 | : "+a" (out.eax), "+b" (out.ebx) |
34 | : "m" (out.st0) |
35 | : "memory" , "st" |
36 | ); |
37 | |
38 | printf(format: "eax = 0x%08" PRIx32 "\n" , out.eax); |
39 | printf(format: "ebx = 0x%08" PRIx32 "\n" , out.ebx); |
40 | printf(format: "st0 = { " ); |
41 | for (int i = 0; i < sizeof(out.st0.data); ++i) |
42 | printf(format: "0x%02" PRIx8 " " , out.st0.data[i]); |
43 | printf(format: "}\n" ); |
44 | } |
45 | |
46 | int main() { |
47 | // block both threads from proceeding |
48 | std::unique_lock<std::mutex> m1_lock(t1_mutex); |
49 | std::unique_lock<std::mutex> m2_lock(t2_mutex); |
50 | |
51 | // start both threads |
52 | std::thread t1(t_func, std::ref(t&: t1_mutex)); |
53 | std::thread t2(t_func, std::ref(t&: t2_mutex)); |
54 | |
55 | // release lock on thread 1 to make it interrupt the program |
56 | m1_lock.unlock(); |
57 | // wait for thread 1 to finish |
58 | t1.join(); |
59 | |
60 | // release lock on thread 2 |
61 | m2_lock.unlock(); |
62 | // wait for thread 2 to finish |
63 | t2.join(); |
64 | |
65 | return 0; |
66 | } |
67 | |