吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|pipinga.com

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 984|回復: 3

[會員申請] 申請會員ID: fox95963【未報到,已注銷】

[復制鏈接]
樓主
吾愛游客  發表于 2020-3-3 02:58 回帖獎勵 <
1、申 請 I D :fox95963                                 
2、個人郵箱:yingxiang.huo@gmail.com



回想起來本人使用VC已經有好些年頭了,風格是半吊子C+,(用class卻少用諸如繼承,try catch等)。最近有機會和一位寫java的朋友一起合作做項目,發現java的try catch finally 在做文件操作的時候很好用--close放在finally中,不用擔心忘記關閉。于是萌生了能否用C++來實現try catch finally的想法。要強調的是,并不是很推崇這樣的做法,因為復雜的宏定義實際上不利于調試--如果掛在宏里面的話將會比較費神--而且可能平臺遷移性不好,本文純屬娛樂折騰,練練手宏定義和內聯匯編

簡單而言就是實現對以下寫法的支持:
[C++] 純文本查看 復制代碼
try_{
}catch_(int e){
}
....
catch_(...){
}finally_{
}


設計上主要有以下問題需要解決
1.我希望使用的時候嚴格按照上面的語法,而不用任何額外的語句輔助,但由于a{}b{}c{}這樣的語句結構在C++語法中并沒有直接支持,所以要考慮變通方法
2.宏定義中大概不能出現直接的jmp <標號>這樣的內容,因為如果有形如try{}catch(e){}finally{};try{}catch(e){}finally{}這樣的調用,這藏在宏定義里的標號就會重復
3.Release問題,這大概是最頭痛的問題。C++和內聯asm混編,如果asm中使用了過多的改動,例如如企圖手動去平衡堆棧,debug的時候好好的,release的時候由于自動優化,就會有各種問題,比如,你預想會call的地方說不定優化成jmp。這樣一來,debug能跑通的,release就會掛。所以需要注意處理。
4.如何在用戶return前將代碼劫持到finally,和在throw后劫持到finally

對于問題1
一眼看上去,可能if(a){}else if(b){}else{}這樣的形式和try{}catch(e){}finally{}有點像,但是它們之間卻有一個明顯區別:try{}catch(e){}finally{}中各個大括號都有可能會進入,但是if(a){}else if(b){}else{}僅有一個大括號會進入。所以需要對其進行形如下面的改造:
for(int i=0;i<3;i++){
        if(!i){}
        else if(i==1){}
        else{}
}
然而這樣有一個問題,就是如紅色部分所示,最終有兩個右括號,這不符合finally{}這樣的格式要求,所以--雖然不是習慣寫法,但是上面其實可以改成如下形式:
for(int i=0;i<3;i++)
        if(!i){}
        else if(i==1){}
        else{}

對于問題2
不單是標號,其實臨時變量的定義也要小心,因為它們也有可能由于宏的重復調用而發生重定義。而這個問題,剛好能用1的方法解決:使用for-if-else if-else的形式進行跳轉,而不用__asm{jmp}和goto,可以躲過標號重名,而將臨時變量定義在for(int i=0;;)中,可以限制其作用域,讓其不至于被其他地方誤用。

對于問題3
一開始時候走了點彎路:
1)企圖通過一些辦法阻止優化,包括但不限于,調整編譯器設置--關了優化的release沒有靈魂
2)企圖通過printf(),time(NULL)之類的操作,讓編譯器不能在編譯時確定分支走向,從而阻止優化--效率和穩健性差,并且,有的時候編譯器寧愿不print你的內容也要剪掉分支。失敗告終
3)盡量多使用__asm,因為VC不會asm部分進行優化--有一定效果,但是跳轉時由于標號問題貌似躲不過,所以又混進C,然后又被優化掉...
4)用#ifdef _DEBUG之類的來做調整,分別對debug和release做處理--吃力不討好,可讀性較差。

鑒于上面問題搞了我一整晚都沒解決,天都要亮了,一怒之下將所有內容刪掉了,推倒重試
最終得出解決方案: 將匯編部分壓縮到最少,不得已才用,用假的遞歸調用來阻止編譯器將我的某些函數內聯

對于問題4
可簡化為:如何能在函數退出前做額外的操作?答案是,借用變量的使用析構函數
假設在代碼塊里面定義了A a();那么在退出代碼塊的時候,~A()會被觸發,無論是return退出,throw退出,還是自然退出,~A()都會被觸發,因此可以在里面做點額外的操作.

直接上代碼:
//頭文件===============================================================================
[C++] 純文本查看 復制代碼
struct killer{
        int i;
        void* p[1];
        bool (*kill)(void* p);
        killer(void* p_,bool (*kill_)(void* p));
        killer();
        ~killer();
};
void* getEip2();

#define RNDNAME aNUOgbujigYIKGOVYv4v1k08//避免名字碰撞
#define try_ for(killer kl##RNDNAME;kl##RNDNAME.i<1;kl##RNDNAME.i++)\
        for(int k##RNDNAME=(kl##RNDNAME=killer(NULL,ThrowSpc)).i;k##RNDNAME<2;k##RNDNAME++)\
        if(k##RNDNAME==1)\
        try{

#define catch_(x)        k##RNDNAME=-2;\
        kl##RNDNAME.kill=0;\
        *(kl##RNDNAME.p)=0;\
}catch(x){\
        k##RNDNAME=-2;\
        kl##RNDNAME.kill=0;\
        *(kl##RNDNAME.p)=0;

#define finally_        \
}\
                                        else\
                                        for (int j##RNDNAME=-1;j##RNDNAME<1;j##RNDNAME++)\
                                        if(j##RNDNAME==-1){\
                                        if(k##RNDNAME==-1){\
                                        k##RNDNAME=1;\
                                        continue;\
                                        }\
                                        void* pos;\
                                        __asm{__asm push 0}\
                                        *kl##RNDNAME.p=(void*)getEip2();\
                                        __asm{\
                                        __asm        mov eax,[esp]\
                                        __asm        mov j##RNDNAME,eax\
}\
        if(!j##RNDNAME){\
        __asm{__asm pop eax}\
        break;\
        }else{\
        j##RNDNAME=-3;\
        }\
        continue;\
                                        }else for(volatile int i##RNDNAME=j##RNDNAME;i##RNDNAME<1;i##RNDNAME++)\
                                        if (i##RNDNAME-j##RNDNAME==1){\
                                        __asm{__asm ret}\
                                        }\
                                                                else


函數實現cpp:========================================================================================
[C++] 純文本查看 復制代碼
killer::killer(){        
        *p=0;
        i=0;
        kill=NULL;
}
killer::killer(void* p_,bool (*kill_)(void* p)){        
        i=0;
        *p=p_;kill=kill_;
}
killer::~killer(){        
        if(*p==0&&kill==NULL){return;}
        bool ans=true;
        if(kill){
                ans=kill(this);
                //printf("kill %s\r\n",ans?"success":"failed");
        }
}

void* getEip2(){
        void* ans;
        __asm{
                mov eax,[ebp+4];
                mov ans,eax;
                pop         edi  
                pop         esi  
                pop         ebx  
                mov         esp,ebp  
                pop         ebp  
                ret                //←真正返回的位置!
        }
        return getEip2();//←防止release內聯!!實際永遠不會執行到這里
}

bool ThrowSpc(void* p_){
        killer* kl=(killer*)p_;
        void* p=kl->p[0];
        kl->kill=0;
        *kl->p=0;
        if(p){
                __asm sub esp,400
                __asm call p;
                __asm add esp,400
        }
        //throw SPC();
}

//測試用例===========================================================
[C++] 純文本查看 復制代碼
int test1(int cnt){
        try_
        {
                printf("main\r\n");
                //throw 0;
                if(cnt<10){
                        int ret=test1(cnt+1);
                        printf("ret%d\r\n",ret);
                }                
                if(rand()%2){
                        throw cnt;
                }
                return cnt;
        }
        catch_(int a)
        {
                printf("catch%d\r\n",a);
        }
        finally_{
                printf("FINAL\r\n");
        }
        return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
        test1(0);
        return 0;
}

//運行結果:=============================================================
main
main
main
main
main
main
main
main
main
main
main
catch10
FINAL
ret0
catch9
FINAL
ret0
FINAL
ret8
FINAL
ret7
catch6
FINAL
ret0
FINAL
ret5
FINAL
ret4
FINAL
ret3
FINAL
ret2
FINAL
ret1
catch0
FINAL

寫在最后:
這是第一次發帖,如果有不合要求處,望包含,敬請指正。說不定這個實現是一個笨辦法,希望指出更好的辦法。仍存一個小問題:現在若不寫final,是編譯不過的,可以改進。沒經過完整測試,bug未知

發帖前要善用論壇搜索广西快三功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

沙發
Hmily 發表于 2020-3-6 16:52
I D:fox95963                                 
郵箱:yingxiang.huo@gmail.com

申請通過,歡迎光臨吾愛破解論壇,期待吾愛破解有你更加精彩,ID和密碼自己通過郵件密碼找回功能修改,請即時登陸并修改密碼!
登陸后請在一周內在此帖報道,否則將刪除ID信息。
3#
Hmily 發表于 2020-3-25 13:21
4#
揮灑靈魂 發表于 2020-3-28 15:07

本版積分規則

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( )

GMT+8, 2020-4-3 11:11

Powered by Discuz!

广西快三Copyright © 2001-2020, Tencent Cloud.

快速回復 返回頂部 返回列表