JIT脚本引擎:stdcall、cdecl和fastcall
stdcall、cdecl和fastcall的参数都是从右到左入栈,并且返回值遵循以下规律:
小于等于4字节结构用EAX
小于等于8字节结构用EDX:EAX
浮点数用ST(0)
其他则在EAX放置一个指针,供返回值使用
stdcall被调用者清栈,cdecl调用者清栈,fastcall被调用者清栈并且前两个小于等于4字节的参数放入ECX和EDX。返回值和参数如果一方有构造函数或析构函数则不使用寄存器。
于是今天用字符串形式的汇编写了三种调用方法的求和函数,类型如下:
1
typedef VInt (__stdcall
*
Summer_Stdcall)(VInt
*
Numbers , VInt Count);
2 typedef VInt (__cdecl * Summer_Cdecl)(VInt * Numbers , VInt Count);
3 typedef VInt (__fastcall * Summer_Fastcall)(VInt * Numbers , VInt Count);
2 typedef VInt (__cdecl * Summer_Cdecl)(VInt * Numbers , VInt Count);
3 typedef VInt (__fastcall * Summer_Fastcall)(VInt * Numbers , VInt Count);
汇编代码如下:
1
CONSTANT
2 VARIABLE
3 CODE
4
5 @SUM_STDCALL:
6 PUSH EBP
7 MOV EBP, ESP
8 PUSH ECX
9 PUSH EDI
10 XOR EAX, EAX
11 MOV ECX, int32 [EBP + 12 ]
12 MOV EDI, int32 [EBP + 8 ]
13 @SUM_STDCALL_BEGIN:
14 CMP ECX, int32 0
15 JE @SUM_STDCALL_FINISHED
16 ADD EAX, int32 [EDI]
17 ADD EDI, int32 4
18 DEC ECX
19 JMP @SUM_STDCALL_BEGIN
20 @SUM_STDCALL_FINISHED:
21 POP EDI
22 POP ECX
23 MOV ESP, EBP
24 POP EBP
25 RET int16 8
26
27 @SUM_CDECL:
28 PUSH EBP
29 MOV EBP, ESP
30 PUSH ECX
31 PUSH EDI
32 XOR EAX, EAX
33 MOV ECX, int32 [EBP + 12 ]
34 MOV EDI, int32 [EBP + 8 ]
35 @SUM_CDECL_BEGIN:
36 CMP ECX, int32 0
37 JE @SUM_CDECL_FINISHED
38 ADD EAX, int32 [EDI]
39 ADD EDI, int32 4
40 DEC ECX
41 JMP @SUM_CDECL_BEGIN
42 @SUM_CDECL_FINISHED:
43 POP EDI
44 POP ECX
45 MOV ESP, EBP
46 POP EBP
47 RET
48
49 @SUM_FASTCALL:
50 PUSH EBP
51 MOV EBP, ESP
52 XOR EAX, EAX
53 @SUM_FASTCALL_BEGIN:
54 CMP EDX, int32 0
55 JE @SUM_FASTCALL_FINISHED
56 ADD EAX, int32 [ECX]
57 ADD ECX, int32 4
58 DEC EDX
59 JMP @SUM_FASTCALL_BEGIN
60 @SUM_FASTCALL_FINISHED:
61 MOV ESP, EBP
62 POP EBP
63 RET
2 VARIABLE
3 CODE
4
5 @SUM_STDCALL:
6 PUSH EBP
7 MOV EBP, ESP
8 PUSH ECX
9 PUSH EDI
10 XOR EAX, EAX
11 MOV ECX, int32 [EBP + 12 ]
12 MOV EDI, int32 [EBP + 8 ]
13 @SUM_STDCALL_BEGIN:
14 CMP ECX, int32 0
15 JE @SUM_STDCALL_FINISHED
16 ADD EAX, int32 [EDI]
17 ADD EDI, int32 4
18 DEC ECX
19 JMP @SUM_STDCALL_BEGIN
20 @SUM_STDCALL_FINISHED:
21 POP EDI
22 POP ECX
23 MOV ESP, EBP
24 POP EBP
25 RET int16 8
26
27 @SUM_CDECL:
28 PUSH EBP
29 MOV EBP, ESP
30 PUSH ECX
31 PUSH EDI
32 XOR EAX, EAX
33 MOV ECX, int32 [EBP + 12 ]
34 MOV EDI, int32 [EBP + 8 ]
35 @SUM_CDECL_BEGIN:
36 CMP ECX, int32 0
37 JE @SUM_CDECL_FINISHED
38 ADD EAX, int32 [EDI]
39 ADD EDI, int32 4
40 DEC ECX
41 JMP @SUM_CDECL_BEGIN
42 @SUM_CDECL_FINISHED:
43 POP EDI
44 POP ECX
45 MOV ESP, EBP
46 POP EBP
47 RET
48
49 @SUM_FASTCALL:
50 PUSH EBP
51 MOV EBP, ESP
52 XOR EAX, EAX
53 @SUM_FASTCALL_BEGIN:
54 CMP EDX, int32 0
55 JE @SUM_FASTCALL_FINISHED
56 ADD EAX, int32 [ECX]
57 ADD ECX, int32 4
58 DEC EDX
59 JMP @SUM_FASTCALL_BEGIN
60 @SUM_FASTCALL_FINISHED:
61 MOV ESP, EBP
62 POP EBP
63 RET
使用以下方法读取文件、编译并取出三个label的指针:
1
void
RunExecutable(VL_AsmProgram
*
Program , VL_AsmCompiled
*
Compiled , VL_AsmExecutable
*
Executable)
2 {
3 VInt Numbers[] = { 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 };
4 VInt Count = sizeof (Numbers) / sizeof ( * Numbers);
5 {
6 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_STDCALL " )];
7 Summer_Stdcall Summer = (Summer_Stdcall)((VInt)Executable -> GetInstruction() + Offset);
8 VInt Result = Summer(Numbers,Count);
9 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
10 }
11 {
12 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_CDECL " )];
13 Summer_Cdecl Summer = (Summer_Cdecl)((VInt)Executable -> GetInstruction() + Offset);
14 VInt Result = Summer(Numbers,Count);
15 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
16 }
17 {
18 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_FASTCALL " )];
19 Summer_Fastcall Summer = (Summer_Fastcall)((VInt)Executable -> GetInstruction() + Offset);
20 VInt Result = Summer(Numbers,Count);
21 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
22 }
23 }
24
25 void Main_Assembler()
26 {
27 VUnicodeString Code;
28 VInt Line = 0 ;
29 VUnicodeString Message;
30 {
31 VUnicodeString WorkData = VFileName(GetConsole() -> GetAppPath()).MakeAbsolute(L " ..\\..\\TestData\\ " ).GetStrW();
32 VL_FileStream CodeStream(WorkData + L " Assembly.txt " ,VL_FileStream::vomRead);
33 Code = ReadText( & CodeStream);
34 }
35
36 VL_AsmProgram * Program = CompileToAssembly(Code,Line,Message);
37 if ( ! Program)
38 {
39 GetConsole() -> Write(Message);
40 return ;
41 }
42
43 VL_AsmCompiled * Compiled = CompileToX86(Program);
44 if (Compiled -> Errors.GetCount())
45 {
46 PrintErrors(Program,Compiled);
47 delete Program;
48 delete Compiled;
49 return ;
50 }
51
52 VL_AsmExecutable * Executable = LinkX86(Compiled);
53 if (Compiled -> Errors.GetCount())
54 {
55 PrintErrors(Program,Compiled);
56 }
57 if (Executable)
58 {
59 RunExecutable(Program,Compiled,Executable);
60 delete Executable;
61 }
62 delete Program;
63 delete Compiled;
64 }
2 {
3 VInt Numbers[] = { 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 };
4 VInt Count = sizeof (Numbers) / sizeof ( * Numbers);
5 {
6 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_STDCALL " )];
7 Summer_Stdcall Summer = (Summer_Stdcall)((VInt)Executable -> GetInstruction() + Offset);
8 VInt Result = Summer(Numbers,Count);
9 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
10 }
11 {
12 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_CDECL " )];
13 Summer_Cdecl Summer = (Summer_Cdecl)((VInt)Executable -> GetInstruction() + Offset);
14 VInt Result = Summer(Numbers,Count);
15 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
16 }
17 {
18 VInt Offset = (VInt)Compiled -> LabelOffsets[Program -> LabelNames.IndexOf(L " @SUM_FASTCALL " )];
19 Summer_Fastcall Summer = (Summer_Fastcall)((VInt)Executable -> GetInstruction() + Offset);
20 VInt Result = Summer(Numbers,Count);
21 GetConsole() -> Write(L " 结果: " + VUnicodeString(Result) + L " \r\n " );
22 }
23 }
24
25 void Main_Assembler()
26 {
27 VUnicodeString Code;
28 VInt Line = 0 ;
29 VUnicodeString Message;
30 {
31 VUnicodeString WorkData = VFileName(GetConsole() -> GetAppPath()).MakeAbsolute(L " ..\\..\\TestData\\ " ).GetStrW();
32 VL_FileStream CodeStream(WorkData + L " Assembly.txt " ,VL_FileStream::vomRead);
33 Code = ReadText( & CodeStream);
34 }
35
36 VL_AsmProgram * Program = CompileToAssembly(Code,Line,Message);
37 if ( ! Program)
38 {
39 GetConsole() -> Write(Message);
40 return ;
41 }
42
43 VL_AsmCompiled * Compiled = CompileToX86(Program);
44 if (Compiled -> Errors.GetCount())
45 {
46 PrintErrors(Program,Compiled);
47 delete Program;
48 delete Compiled;
49 return ;
50 }
51
52 VL_AsmExecutable * Executable = LinkX86(Compiled);
53 if (Compiled -> Errors.GetCount())
54 {
55 PrintErrors(Program,Compiled);
56 }
57 if (Executable)
58 {
59 RunExecutable(Program,Compiled,Executable);
60 delete Executable;
61 }
62 delete Program;
63 delete Compiled;
64 }
得到结果:
接下来熟悉浮点数的操作,就可以开始中间指令集的构造了。