• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評論-2670  文章-0  trackbacks-0
                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) 閱讀(1801) 評論(9)  編輯 收藏 引用 所屬分類: JIT

            評論:
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-03 05:39 | lnn
            To day is my birthday!  回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-03 21:20 | OwnWaterloo
            --------------------------------------------------------------------------------------------
            stdcall、cdecl和fastcall的參數都是從右到左入棧,并且返回值遵循以下規律:
                小于等于4字節結構用EAX
                小于等于8字節結構用EDX:EAX
                浮點數用ST(0)
                其他則在EAX放置一個指針,供返回值使用
            --------------------------------------------------------------------------------------------
             
            請問一下,關于這個規律,是有標準規定的嗎?
            C/C++的書籍或者標準中,都沒有規定調用約定。
            還是說,這些只是事實上的標準?
             
            如果只是事實上的標準,這些規律的應用范圍只限于x86以及其兼容機?
              回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-04 09:27 | 路人戊
            @OwnWaterloo
            參數入棧方向沒有標準,甚至沒有事實上的標準,IA86上GCC和VC編譯器方向就不同。
            其他寄存器多的CPU編譯器傾向盡可能地利用寄存器來傳遞參數,會出現調用函數壓棧就只是壓進一個返回地址的情形

            一擊脫離……  回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-04 19:20 | 陳梓瀚(vczh)
            @路人戊
            這是windows下編譯器的約定,windows下的vc++、gcc和c++builder都遵守這個約定。至于其他的怎么辦其實都無所謂了,因為windows的程序只能直接調用windows的程序。  回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-04 19:21 | 陳梓瀚(vczh)
            @OwnWaterloo
            這在msdn里有詳細描述。  回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-04 23:44 | OwnWaterloo
            @陳梓瀚(vczh)
            MSDN就是微軟的編譯器了。

            其他的編譯器是否也是這樣?

            雖然我也覺得其他編譯器也應該是這樣。
            沒有理由無故的與樓主描述的__cdecl,__stdcall實現不兼容。

            但是心里沒譜啊 ……
            樓主作過其他編譯器的調查么?
            有前人作過類似的調查么?
              回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-05 00:07 | 陳梓瀚(vczh)
            @OwnWaterloo
            我以前用的是C++Builder,根據觀察一致。而且這里有一個很強大的理由,如果不兼容的話,怎么調API?所以必須兼容。  回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-05 03:03 | OwnWaterloo
            @陳梓瀚(vczh)
            ---------------------------------------------
            如果不兼容的話,怎么調API?所以必須兼容。
            ---------------------------------------------
            ---------------------------------------------
            雖然我也覺得其他編譯器也應該是這樣。
            沒有理由無故的與樓主描述的__cdecl,__stdcall實現不兼容。
            ---------------------------------------------
            我想說的就是這個意思,應該不會有編譯器放棄大多數舊有的C目標文件遵守的約定,另尋它法。


            但是呢。。。 還是不像有個ISO那么有把握。


            http://www.unixwiz.net/techtips/win32-callconv.html
            這篇文章里說了一個入棧順序,和平時所說的右到左不同。
            但在win32上結論是一樣的。

              回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-05 04:45 | 陳梓瀚(vczh)
            @OwnWaterloo
            有了ISO也不見得就怎么樣  回復  更多評論
              
            国产精品久久久亚洲| 7777精品久久久大香线蕉 | 亚洲欧美精品伊人久久| 品成人欧美大片久久国产欧美...| 久久精品国产亚洲沈樵| 日本久久中文字幕| 伊人久久无码中文字幕| 国产国产成人精品久久| 久久久久亚洲AV无码专区网站 | 性高湖久久久久久久久| 91精品婷婷国产综合久久| 一本久久免费视频| 97久久精品国产精品青草| 久久青青色综合| 欧美色综合久久久久久| 99久久er这里只有精品18| 青青久久精品国产免费看| 日韩精品久久久肉伦网站| 久久久亚洲精品蜜桃臀| 国产精品9999久久久久| 中文字幕久久波多野结衣av| 久久久久综合国产欧美一区二区| 99久久国语露脸精品国产| 久久人人爽人人爽人人片AV麻烦| 国产69精品久久久久9999| 777米奇久久最新地址| 亚洲中文久久精品无码| 久久亚洲精品无码观看不卡| 精品综合久久久久久97超人 | 久久99国产亚洲高清观看首页 | 亚洲欧洲久久av| 久久影视综合亚洲| 精品国产91久久久久久久a| 99久久精品九九亚洲精品| 狠狠色丁香婷婷综合久久来| 久久精品国产清高在天天线| 久久婷婷五月综合色高清| 人妻少妇久久中文字幕一区二区| 综合网日日天干夜夜久久| 久久人人爽人人爽人人爽| 久久亚洲中文字幕精品一区|