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);
汇编代码如下:
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
使用以下方法读取文件、编译并取出三个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 }
得到结果:
接下来熟悉浮点数的操作,就可以开始中间指令集的构造了。
posted on 2009-03-01 05:27
陈梓瀚(vczh) 阅读(1792)
评论(9) 编辑 收藏 引用 所属分类:
JIT