c++的CAS與內(nèi)存屏障: 內(nèi)聯(lián)匯編的實(shí)際應(yīng)用場(chǎng)景(S1封裝系統(tǒng)調(diào)用)
代碼可在這里查看: https://github.com/hi-quasars/quark/blob/master/tests/tst-syscall.cc
封裝了3個(gè)系統(tǒng)調(diào)用:write(2),exit(2),gittid(2).-
update notes:
- 20180708 initial version.
- 20180709 refine syscall wrapper.
- 20180709 refine version 2 for generic syscall wrapper.
上一篇主要討論了內(nèi)聯(lián)匯編語(yǔ)法層面的東西,現(xiàn)在接著深入研究下實(shí)際應(yīng)用的場(chǎng)景.
封裝系統(tǒng)調(diào)用
一些非posix標(biāo)準(zhǔn)的系統(tǒng)調(diào)用,可能需要通過(guò)glibc提供的syscall函數(shù)來(lái)調(diào)用.(unistd.h下的syscall(2))
在x86架構(gòu)下,x86_64linux上較新glibc的syscall函數(shù)最終調(diào)用的指令為syscall匯編指令,而較舊的x86_64架構(gòu)下的glibc或x86架構(gòu)可能調(diào)用int 0x80 指令.
Linux Assembly X86
-
syscall指令vsint 0x08
看wiki上的解釋
syscall
The x86_64 architecture introduced a dedicated instruction to make a syscall. It does not access the interrupt descriptor table and is faster.
- 實(shí)驗(yàn)1,x86_64下的write系統(tǒng)調(diào)用封裝.
這里用c++模板封裝了個(gè)簡(jiǎn)單的類型轉(zhuǎn)換層.
大概的層次關(guān)系如下:
| 層次 | 代碼片段 | 備注 |
|---|---|---|
| api層 | write(int, const char*, int) | 參數(shù)有類型,不同系統(tǒng)調(diào)用參數(shù)個(gè)數(shù)不同 |
| 膠水層 | DoSysCall... | 類型轉(zhuǎn)換和參數(shù)個(gè)數(shù)匹配,如int類型參數(shù)需要轉(zhuǎn)成64位寄存器的合法操作數(shù) |
| 系統(tǒng)調(diào)用 | asm(...) | 參數(shù)無(wú)類型(只有長(zhǎng)度),參數(shù)個(gè)數(shù)明確.(1-6) |
- 這個(gè)例子簡(jiǎn)單粗暴地進(jìn)行了復(fù)制和十分冗長(zhǎng)的類型轉(zhuǎn)換.
這個(gè)例子接受參數(shù)個(gè)數(shù)為3的系統(tǒng)調(diào)用(不算系統(tǒng)調(diào)用號(hào))
1
2 /*
3 *
4 *
5 * from the glibc wiki page https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux
6 - int 0x80
7 On both Linux x86 and Linux x86_64 systems you can make a syscall by calling interrupt 0x80 using the int $0x80 command. Parameters are passed by setting the general purpose registers as following:
8
9 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
10 eax ebx ecx edx esi edi ebp
11 Return value
12 eax
13 The syscall numbers are described in the Linux generated file $build/arch/x86/include/generated/uapi/asm/unistd_32.h or $build/usr/include/asm/unistd_32.h. The latter could also be present on your Linux system, just omit the $build.
14 All registers are preserved during the syscall.
15
16 - syscall
17 The x86_64 architecture introduced a dedicated instruction to make a syscall. It does not access the interrupt descriptor table and is faster. Parameters are passed by setting the general purpose registers as following:
18
19 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
20 rax rdi rsi rdx r10 r8 r9
21 Return value
22 rax
23 The syscall numbers are described in the Linux generated file $build/usr/include/asm/unistd_64.h. This file could also be present on your Linux system, just omit the $build.
24 All registers, except rcx and r11 (and the return value, rax), are preserved during the syscall.
25 * */
26
27 /// for x86 & x86_64
28 #include <iostream>
29 #include <cstring>
30 #include <sys/syscall.h>
31 #include <cstdio>
32
33 template <int len>
34 struct byte { /// this type is a pod type.
35 char ctn[len];
36 };
37
38
39 template <typename T>
40 struct byte_t {
41 byte<sizeof(T)> itn;
42 };
43
44 template<typename T>
45 uint64_t* FetchCtnPtr(T* x) {
46 return reinterpret_cast<uint64_t*>(x->itn.ctn);
47 }
48
49 template<typename T1, typename T2, typename T3>
50 int DoSysCall0(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3)
51 {
52 uint64_t ret;
53 byte_t<uint64_t> x1;
54 byte_t<uint64_t> x2;
55 byte_t<uint64_t> x3;
56 const char * ptr;
57 memcpy(static_cast<void*>(x1.itn.ctn), static_cast<void*>(&a1), sizeof(a1));
58 memcpy(static_cast<void*>(x2.itn.ctn), static_cast<void*>(&a2), sizeof(a2));
59 memcpy(static_cast<void*>(x3.itn.ctn), static_cast<void*>(&a3), sizeof(a3));
60
61 printf("%d %s %d\n", *(reinterpret_cast<int*>(x1.itn.ctn)),
62 (ptr = reinterpret_cast<const char*>(*(FetchCtnPtr(&x2)))) == NULL ? "NULL" : ptr,
63 *(reinterpret_cast<int*>(x3.itn.ctn)));
64
65 asm(
66 "movq %1, %%rax\n\t" /// SysCall Number
67 "movq %2, %%rdi\n\t" /// Para 1
68 "movq %3, %%rsi\n\t" /// Para 2
69 "movq %4, %%rdx\n\t" /// Para 3
70 "syscall\n\t" /// Call it
71 "movq %%rax, %0\n\t" /// Fetch Return Value
72 :"=r"(ret)
73 :"r"(SysCallNR),"r"(*(FetchCtnPtr(&x1))), "r"(*(FetchCtnPtr(&x2))), "r"(*(FetchCtnPtr(&x3)))
74 :"%rax","%rdi", "%rsi", "%rdx"
75 );
76 return (int)ret;
77 }
78
79
80 int Write(int fd, const char* str, int num) {
81 return DoSysCall0(SYS_write, fd, str, num);
82 }
83
84 int main() {
85 int ret;
86 const char * str1 = "Hello Syscall\n";
87 ret = Write(1, str1, strlen(str1));
88 std::cout << "Ret: " << ret << std::endl;
89 return 0;
90 }
運(yùn)行結(jié)果如下:

result
從這個(gè)例子可看出,glibc在包裹函數(shù)做的的事情應(yīng)該是包括:
- 入?yún)?出參類型轉(zhuǎn)換.(系統(tǒng)調(diào)用在上層的參數(shù)類型可能不同)
- 填充寄存器.(架構(gòu)相關(guān),填充哪些寄存器)
- 調(diào)用中斷指令
- 最后,總結(jié)一下這個(gè)部分
glibc的syscall函數(shù)是根據(jù)不同架構(gòu)、不同版本內(nèi)核由腳本生成來(lái)的,擴(kuò)展性比自己寫syscall_wrapper好得多.
建議還是使用syscall函數(shù)而非自己封裝一個(gè),畢竟這些臟活累活吃力不討好.
需要自己封裝時(shí),一定是非常少見的情況了(估計(jì)這輩子都碰不到),這有對(duì)添加system call的glibc現(xiàn)狀做一些討論.lwn - 這里對(duì)類型封裝部分進(jìn)行一些重構(gòu), 采用type_traits和enable_if等trick對(duì)類型轉(zhuǎn)換部分優(yōu)化了一下.
Here is an improve version of syscall wrapper
Compile: g++ tst-syscall.cc -o test -std=c++11 or g++ tst-syscall.cc -o test
1
2 /*
3 *
4 *
5 * from the glibc wiki page https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux
6 - int 0x80
7 On both Linux x86 and Linux x86_64 systems you can make a syscall by calling interrupt 0x80 using the int $0x80 command. Parameters are passed by setting the general purpose registers as following:
8
9 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
10 eax ebx ecx edx esi edi ebp
11 Return value
12 eax
13 The syscall numbers are described in the Linux generated file $build/arch/x86/include/generated/uapi/asm/unistd_32.h or $build/usr/include/asm/unistd_32.h. The latter could also be present on your Linux system, just omit the $build.
14 All registers are preserved during the syscall.
15
16 - syscall
17 The x86_64 architecture introduced a dedicated instruction to make a syscall. It does not access the interrupt descriptor table and is faster. Parameters are passed by setting the general purpose registers as following:
18
19 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
20 rax rdi rsi rdx r10 r8 r9
21 Return value
22 rax
23 The syscall numbers are described in the Linux generated file $build/usr/include/asm/unistd_64.h. This file could also be present on your Linux system, just omit the $build.
24 All registers, except rcx and r11 (and the return value, rax), are preserved during the syscall.
25 * */
26
27 /// for x86 & x86_64
28 #include <iostream>
29 #include <cstring>
30 #include <cstdio>
31 #include <sys/syscall.h>
32
33
34
35 struct b4 {
36 char buf[4];
37 };
38 struct b8 {
39 char buf[8];
40 };
41
42 #if __cplusplus >= 201103L
43
44 #include <type_traits>
45 typedef std::true_type true_type;
46 typedef std::false_type false_type;
47
48 #else
49 template <typename T, T Val>
50 struct integer_constant {
51 typedef T value_type;
52 enum { value = Val };
53 };
54 typedef integer_constant<bool, true> true_type;
55 typedef integer_constant<bool, false> false_type;
56 #endif
57
58 template <typename T>
59 struct is_b4 {
60 typedef false_type value_type;
61 const bool value = false;
62 };
63
64 template <>
65 struct is_b4<b4> {
66 typedef true_type value_type;
67 const bool value = true;
68 };
69
70 template <typename T>
71 struct is_b8 {
72 typedef false_type value_type;
73 static const bool value = false;
74 };
75
76 template <>
77 struct is_b8<b8> {
78 typedef true_type value_type;
79 static const bool value = true;
80 };
81
82 template <bool, typename T = void>
83 struct enable_if_my {
84 };
85 template <typename T>
86 struct enable_if_my<true, T> {
87 typedef T type;
88 };
89
90
91 template<typename T>
92 void makeb48(b4* b, T* x) {
93 memcpy(static_cast<void*>(b->buf), static_cast<void*>(x), sizeof(T));
94 }
95 template<typename T>
96 void makeb48(b8* b, T* x) {
97 memcpy(static_cast<void*>(b->buf), static_cast<void*>(x), sizeof(T));
98 }
99 template<typename T, typename enable_if_my<is_b4<T>::value, T>::type* = nullptr>
100 uint32_t* CtnPtr(T *b){
101 return reinterpret_cast<uint32_t*>(b->buf);
102 }
103 template<typename T, typename enable_if_my<is_b8<T>::value, T>::type* = nullptr> /// should be ::type* , or compiler cannot infer the tempalte argument.
104 uint64_t* CtnPtr(T *b){
105 return reinterpret_cast<uint64_t*>(b->buf);
106 }
107
108 template<typename T1, typename T2, typename T3>
109 int DoSysCall0(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3)
110 {
111 uint64_t ret;
112 b8 x1;
113 b8 x2;
114 b8 x3;
115 const char * ptr;
116 makeb48(&x1, &a1);
117 makeb48(&x2, &a2);
118 makeb48(&x3, &a3);
119
120 printf("%d %s %d\n", *(reinterpret_cast<int*>(CtnPtr(&x1))),
121 (ptr = reinterpret_cast<const char*>(*(CtnPtr(&x2)))) == NULL ? "NULL" : ptr,
122 *(reinterpret_cast<int*>(CtnPtr(&x3))));
123
124 asm(
125 "movq %1, %%rax\n\t" /// SysCall Number
126 "movq %2, %%rdi\n\t" /// Para 1
127 "movq %3, %%rsi\n\t" /// Para 2
128 "movq %4, %%rdx\n\t" /// Para 3
129 "syscall\n\t" /// Call it
130 "movq %%rax, %0\n\t" /// Fetch Return Value
131 :"=r"(ret)
132 :"r"(SysCallNR),"r"(*(CtnPtr(&x1))), "r"(*(CtnPtr(&x2))), "r"(*(CtnPtr(&x3)))
133 :"%rax","%rdi", "%rsi", "%rdx"
134 );
135 return (int)ret;
136 }
137
138
139 int Write(int fd, const char* str, int num) {
140 return DoSysCall0(SYS_write, fd, str, num);
141 }
142
143 int main() {
144 int ret;
145 const char * str1 = "Hello Syscall\n";
146 ret = Write(1, str1, strlen(str1));
147 std::cout << "Ret: " << ret << std::endl;
148 return 0;
149 }

improve version of syscall wrapper
- 重構(gòu)第二個(gè)版本,添加系統(tǒng)調(diào)用的通用化支持
1
2 /*
3 *
4 *
5 * from the glibc wiki page https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux
6 - int 0x80
7 On both Linux x86 and Linux x86_64 systems you can make a syscall by calling interrupt 0x80 using the int $0x80 command. Parameters are passed by setting the general purpose registers as following:
8
9 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
10 eax ebx ecx edx esi edi ebp
11 Return value
12 eax
13 The syscall numbers are described in the Linux generated file $build/arch/x86/include/generated/uapi/asm/unistd_32.h or $build/usr/include/asm/unistd_32.h. The latter could also be present on your Linux system, just omit the $build.
14 All registers are preserved during the syscall.
15
16 - syscall
17 The x86_64 architecture introduced a dedicated instruction to make a syscall. It does not access the interrupt descriptor table and is faster. Parameters are passed by setting the general purpose registers as following:
18
19 Param 1 Param 2 Param 3 Param 4 Param 5 Param 6
20 rax rdi rsi rdx r10 r8 r9
21 Return value
22 rax
23 The syscall numbers are described in the Linux generated file $build/usr/include/asm/unistd_64.h. This file could also be present on your Linux system, just omit the $build.
24 All registers, except rcx and r11 (and the return value, rax), are preserved during the syscall.
25 * */
26
27 /// for x86 & x86_64
28 #include <iostream>
29 #include <cstring>
30 #include <cstdio>
31 #include <sys/syscall.h>
32
33
34
35 struct b4 {
36 char buf[4];
37 };
38 struct b8 {
39 char buf[8];
40 };
41
42 #if __cplusplus >= 201103L
43
44 #include <type_traits>
45 typedef std::true_type true_type;
46 typedef std::false_type false_type;
47
48 #else
49 template <typename T, T Val>
50 struct integer_constant {
51 typedef T value_type;
52 enum { value = Val };
53 };
54 typedef integer_constant<bool, true> true_type;
55 typedef integer_constant<bool, false> false_type;
56 #endif
57
58 template <typename T>
59 struct is_b4 {
60 typedef false_type value_type;
61 const bool value = false;
62 };
63
64 template <>
65 struct is_b4<b4> {
66 typedef true_type value_type;
67 const bool value = true;
68 };
69
70 template <typename T>
71 struct is_b8 {
72 typedef false_type value_type;
73 static const bool value = false;
74 };
75
76 template <>
77 struct is_b8<b8> {
78 typedef true_type value_type;
79 static const bool value = true;
80 };
81
82 template <bool, typename T = void>
83 struct enable_if_my {
84 };
85 template <typename T>
86 struct enable_if_my<true, T> {
87 typedef T type;
88 };
89
90
91 template<typename T>
92 void makeb48(b4* b, T* x) {
93 memcpy(static_cast<void*>(b->buf), static_cast<void*>(x), sizeof(T));
94 }
95 template<typename T>
96 void makeb48(b8* b, T* x) {
97 memcpy(static_cast<void*>(b->buf), static_cast<void*>(x), sizeof(T));
98 }
99 template<typename T, typename enable_if_my<is_b4<T>::value, T>::type* = nullptr>
100 uint32_t* CtnPtr(T *b){
101 return reinterpret_cast<uint32_t*>(b->buf);
102 }
103 template<typename T, typename enable_if_my<is_b8<T>::value, T>::type* = nullptr> /// should be ::type* , or compiler cannot infer the tempalte argument.
104 uint64_t* CtnPtr(T *b){
105 return reinterpret_cast<uint64_t*>(b->buf);
106 }
107
108
109 #define SysCallCmd0 "movq %1, %%rax\n\t"
110 #define SysCallCmd1 SysCallCmd0 "movq %2, %%rdi\n\t"
111 #define SysCallCmd2 SysCallCmd1 "movq %3, %%rsi\n\t"
112 #define SysCallCmd3 SysCallCmd2 "movq %4, %%rdx\n\t"
113 #define SysCallCmd4 SysCallCmd3 "movq %5, %%r10\n\t"
114 #define SysCallCmd5 SysCallCmd4 "movq %6, %%r8\n\t"
115 #define SysCallCmd6 SysCallCmd5 "movq %7, %%r9\n\t"
116
117 #define SysCallRet "movq %%rax,%0\n\t"
118
119 #define OutputReg(x) "=r"(x)
120 #define InputReg(x) "r"(x)
121 #define SysCallInRegList0(nr,ofs) InputReg(nr)
122 #define SysCallInRegList1(nr,a1) InputReg(nr),InputReg(a1)
123 #define SysCallInRegList2(nr,a1,a2) SysCallInRegList1(nr,a1),InputReg(a2)
124 #define SysCallInRegList3(nr,a1,a2,a3) SysCallInRegList2(nr,a1,a2),InputReg(a3)
125 #define SysCallInRegList4(nr,a1,a2,a3,a4) SysCallInRegList3(nr,a1,a2,a3),InputReg(a4)
126 #define SysCallInRegList5(nr,a1,a2,a3,a4,a5) SysCallInRegList4(nr,a1,a2,a3,a4),InputReg(a5)
127 #define SysCallInRegList6(nr,a1,a2,a3,a4,a5,a6) SysCallInRegList5(nr,a1,a2,a3,a4,a5),InputReg(a6)
128
129 #define SysCallCrobList0 "%rax"
130 #define SysCallCrobList1 SysCallCrobList0,"%rdi"
131 #define SysCallCrobList2 SysCallCrobList1,"%rsi"
132 #define SysCallCrobList3 SysCallCrobList2,"%rdx"
133 #define SysCallCrobList4 SysCallCrobList3,"%r10"
134 #define SysCallCrobList5 SysCallCrobList4,"%r8"
135 #define SysCallCrobList6 SysCallCrobList5,"%r9"
136
137
138 #define SysCallTemplateX8664(ret, NR, i, ...) do { asm( \
139 SysCallCmd##i \
140 "syscall\n\t" \
141 SysCallRet \
142 :OutputReg(ret) \
143 :SysCallInRegList##i(NR, __VA_ARGS__) \
144 :SysCallCrobList##i \
145 ); } while(0)
146
147 #define X86_64DefSysCall0(ret, NR) SysCallTemplateX8664(ret, NR, 0)
148 #define X86_64DefSysCall1(ret, NR, a1) SysCallTemplateX8664(ret, NR, 1, a1)
149 #define X86_64DefSysCall2(ret, NR, a1, a2) SysCallTemplateX8664(ret, NR, 2, a1, a2)
150
151 #define X86_64DefSysCall3(ret, NR, a1, a2, a3) \
152 SysCallTemplateX8664(ret, NR, 3, a1, a2, a3)
153 #define X86_64DefSysCall4(ret, NR, a1, a2, a3, a4) \
154 SysCallTemplateX8664(ret, NR, 4, a1, a2, a3, a4)
155 #define X86_64DefSysCall5(ret, NR, a1, a2, a3, a4, a5) \
156 SysCallTemplateX8664(ret, NR, 5, a1, a2, a3, a4, a5)
157 #define X86_64DefSysCall6(ret, NR, a1, a2, a3, a4, a5, a6) \
158 SysCallTemplateX8664(ret, NR, 6, a1, a2, a3, a4, a5, a6)
159
160
161 int DoSysCall(uint64_t SysCallNR)
162 {
163 uint64_t ret;
164 X86_64DefSysCall0(ret, SysCallNR);
165 return (int)ret;
166 }
167
168 template<typename T1>
169 int DoSysCall(uint64_t SysCallNR, T1 a1)
170 {
171 uint64_t ret;
172 b8 x1;
173 makeb48(&x1, &a1);
174 X86_64DefSysCall1(ret, SysCallNR, (*CtnPtr(&x1)));
175 return (int)ret;
176 }
177
178 template<typename T1, typename T2>
179 int DoSysCall(uint64_t SysCallNR, T1 a1, T2 a2)
180 {
181 uint64_t ret;
182 b8 x1, x2;
183 makeb48(&x1, &a1);
184 makeb48(&x2, &a2);
185 X86_64DefSysCall2(ret, SysCallNR, (*CtnPtr(&x1)), (*CtnPtr(&x2)));
186 return (int)ret;
187 }
188
189 template<typename T1, typename T2, typename T3>
190 int DoSysCall(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3)
191 {
192 uint64_t ret;
193 b8 x1, x2, x3;
194 makeb48(&x1, &a1);
195 makeb48(&x2, &a2);
196 makeb48(&x3, &a3);
197 X86_64DefSysCall3(ret, SysCallNR, (*CtnPtr(&x1)), (*CtnPtr(&x2)), (*CtnPtr(&x3)));
198 return (int)ret;
199 }
200
201 template<typename T1, typename T2, typename T3, typename T4>
202 int DoSysCall(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3, T4 a4)
203 {
204 uint64_t ret;
205 b8 x1, x2, x3, x4;
206 makeb48(&x1, &a1);
207 makeb48(&x2, &a2);
208 makeb48(&x3, &a3);
209 makeb48(&x4, &a4);
210 X86_64DefSysCall4(ret, SysCallNR, (*CtnPtr(&x1)), (*CtnPtr(&x2)), (*CtnPtr(&x3)), (*CtnPtr(&x4)));
211 return (int)ret;
212 }
213
214 template<typename T1, typename T2, typename T3, typename T4, typename T5>
215 int DoSysCall(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
216 {
217 uint64_t ret;
218 b8 x1, x2, x3, x4, x5;
219 makeb48(&x1, &a1);
220 makeb48(&x2, &a2);
221 makeb48(&x3, &a3);
222 makeb48(&x4, &a4);
223 makeb48(&x5, &a5);
224 X86_64DefSysCall5(ret, SysCallNR, (*CtnPtr(&x1)), (*CtnPtr(&x2)), (*CtnPtr(&x3)), (*CtnPtr(&x4)), (*CtnPtr(&x5)));
225 return (int)ret;
226 }
227
228 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
229 int DoSysCall(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
230 {
231 uint64_t ret;
232 b8 x1, x2, x3, x4, x5, x6;
233 makeb48(&x1, &a1);
234 makeb48(&x2, &a2);
235 makeb48(&x3, &a3);
236 makeb48(&x4, &a4);
237 makeb48(&x5, &a5);
238 makeb48(&x6, &a6);
239 X86_64DefSysCall6(ret, SysCallNR, (*CtnPtr(&x1)), (*CtnPtr(&x2)), (*CtnPtr(&x3)), (*CtnPtr(&x4)), (*CtnPtr(&x5)), (*CtnPtr(&x6)));
240 return (int)ret;
241 }
242
243 template<typename T1, typename T2, typename T3>
244 int DoSysCall0(uint64_t SysCallNR, T1 a1, T2 a2, T3 a3)
245 {
246 uint64_t ret;
247 b8 x1;
248 b8 x2;
249 b8 x3;
250 const char * ptr;
251 makeb48(&x1, &a1);
252 makeb48(&x2, &a2);
253 makeb48(&x3, &a3);
254
255 printf("%d %s %d\n", *(reinterpret_cast<int*>(CtnPtr(&x1))),
256 (ptr = reinterpret_cast<const char*>(*(CtnPtr(&x2)))) == NULL ? "NULL" : ptr,
257 *(reinterpret_cast<int*>(CtnPtr(&x3))));
258
259 asm(
260 "movq %1, %%rax\n\t" /// SysCall Number
261 "movq %2, %%rdi\n\t" /// Para 1
262 "movq %3, %%rsi\n\t" /// Para 2
263 "movq %4, %%rdx\n\t" /// Para 3
264 "syscall\n\t" /// Call it
265 "movq %%rax, %0\n\t" /// Fetch Return Value
266 :"=r"(ret)
267 :"r"(SysCallNR),"r"(*(CtnPtr(&x1))), "r"(*(CtnPtr(&x2))), "r"(*(CtnPtr(&x3)))
268 :"%rax","%rdi", "%rsi", "%rdx"
269 );
270 return (int)ret;
271 }
272
273
274 int Write(int fd, const char* str, int num) {
275 return DoSysCall(SYS_write, fd, str, num);
276 }
277
278 int Exit(int code) {
279 return DoSysCall(SYS_exit, code);
280 }
281
282 int Gettid() {
283 return DoSysCall(SYS_gettid);
284 }
285
286 int main() {
287 int ret;
288 const char * str1 = "Hello Syscall\n";
289 ret = Write(1, str1, strlen(str1));
290 std::cout << "Ret: " << ret << std::endl;
291
292 std::cout << "Tid: " << Gettid() << std::endl;
293 return 0;
294 }

添加tid
內(nèi)存屏障和CAS放入下一篇.
內(nèi)存屏障
tbd...
CAS
tbd...