• <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的參數(shù)都是從右到左入棧,并且返回值遵循以下規(guī)律:
                小于等于4字節(jié)結構用EAX
                小于等于8字節(jié)結構用EDX:EAX
                浮點數(shù)用ST(0)
                其他則在EAX放置一個指針,供返回值使用

                stdcall被調用者清棧,cdecl調用者清棧,fastcall被調用者清棧并且前兩個小于等于4字節(jié)的參數(shù)放入ECX和EDX。返回值和參數(shù)如果一方有構造函數(shù)或析構函數(shù)則不使用寄存器。

                于是今天用字符串形式的匯編寫了三種調用方法的求和函數(shù),類型如下:
            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 }

                得到結果:

                接下來熟悉浮點數(shù)的操作,就可以開始中間指令集的構造了。
            posted on 2009-03-01 05:27 陳梓瀚(vczh) 閱讀(1807) 評論(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的參數(shù)都是從右到左入棧,并且返回值遵循以下規(guī)律:
                小于等于4字節(jié)結構用EAX
                小于等于8字節(jié)結構用EDX:EAX
                浮點數(shù)用ST(0)
                其他則在EAX放置一個指針,供返回值使用
            --------------------------------------------------------------------------------------------
             
            請問一下,關于這個規(guī)律,是有標準規(guī)定的嗎?
            C/C++的書籍或者標準中,都沒有規(guī)定調用約定。
            還是說,這些只是事實上的標準?
             
            如果只是事實上的標準,這些規(guī)律的應用范圍只限于x86以及其兼容機?
              回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-04 09:27 | 路人戊
            @OwnWaterloo
            參數(shù)入棧方向沒有標準,甚至沒有事實上的標準,IA86上GCC和VC編譯器方向就不同。
            其他寄存器多的CPU編譯器傾向盡可能地利用寄存器來傳遞參數(shù),會出現(xiàn)調用函數(shù)壓棧就只是壓進一個返回地址的情形

            一擊脫離……  回復  更多評論
              
            # 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實現(xiàn)不兼容。

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


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


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

              回復  更多評論
              
            # re: JIT腳本引擎:stdcall、cdecl和fastcall 2009-03-05 04:45 | 陳梓瀚(vczh)
            @OwnWaterloo
            有了ISO也不見得就怎么樣  回復  更多評論
              
            aaa级精品久久久国产片| 亚洲一区中文字幕久久| 伊人伊成久久人综合网777| 亚洲а∨天堂久久精品9966| 久久笫一福利免费导航 | 人妻精品久久无码专区精东影业| 色偷偷偷久久伊人大杳蕉| 国产精品9999久久久久| 青青久久精品国产免费看| 久久香蕉国产线看观看精品yw| 日本免费久久久久久久网站| 久久久久国产精品麻豆AR影院 | 久久中文骚妇内射| 女同久久| 精品久久久久成人码免费动漫| 精品国际久久久久999波多野| 一本大道久久香蕉成人网| 久久亚洲欧美日本精品| 久久精品国产91久久综合麻豆自制| 亚洲人AV永久一区二区三区久久| 欧美日韩中文字幕久久伊人| 欧美午夜精品久久久久免费视 | 国产精品18久久久久久vr| 久久午夜伦鲁片免费无码| 囯产精品久久久久久久久蜜桃| 欧美亚洲国产精品久久久久| 久久99热这里只频精品6| 无码AV中文字幕久久专区| 亚洲国产精品无码久久久秋霞2| 国色天香久久久久久久小说| 亚洲狠狠婷婷综合久久久久 | 久久婷婷五月综合成人D啪| 久久这里的只有是精品23| 久久综合久久自在自线精品自| 久久国产精品-久久精品| 久久婷婷色综合一区二区| 国产V综合V亚洲欧美久久| 精品久久综合1区2区3区激情| 亚洲精品无码专区久久久| 久久精品成人欧美大片| 久久91精品久久91综合|