layout: post
title: 測試編譯器下限之不同大小返回值的處理
categories: Reverse_Engineering
description: 測試編譯器下限之不同大小返回值的處理
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/
寫在前面的話
??編譯器會根據(jù)函數(shù)返回類型大小(sizeof操作符進(jìn)行4字節(jié)對齊后的值)不同進(jìn)行不同的操作。如果該值為4字節(jié)嫌松,那么默認(rèn)會返回到EAX寄存器中,如果該值為8字節(jié)疗垛,則通常使用EAX寄存器裝載結(jié)果的低4字節(jié)纹笼,EDX寄存器裝載結(jié)果的高4字節(jié)饱普。如果該值超過8孵延,則根據(jù)編譯器的不同會有不同的行為吕漂,在剩余寄存器足夠用的情況下,通常會使用這些寄存器來傳值尘应,如果編譯器發(fā)現(xiàn)現(xiàn)有寄存器無法滿足返回值長度要求惶凝,那么就會在內(nèi)存中開辟一塊相對安全的棧區(qū)域用于存儲該值,賦值完畢后犬钢,將起始位置指針傳遞給EAX苍鲜。一般情況下,返回大小超過8字節(jié)的行為并不恰當(dāng)娜饵,如果在設(shè)計不良的編譯器中很有可能造成返回地址覆蓋,也極為少見官辈。(基于32位 MSVC)
- 對于4字節(jié)返回值箱舞,例如int,眾所周知拳亿,返回值存在EAX
- 對于8字節(jié)返回值晴股,例如longlong,眾所周知肺魁,返回值存于EDX:EAX
- 對于8字節(jié)以上返回值电湘,雖然編程方法錯誤(因為有些不良編譯器可能直接返回棧地址),但是出于理論研究鹅经,還是想看看編譯器怎么考慮寂呛。
??對于20字節(jié)返回值,做個測試瘾晃,如果從頭單步調(diào)試的話贷痪,你會發(fā)現(xiàn)這句居然在父函數(shù)未使用的棧空間(通過ebp得到)分配了一段空間蹦误。返回值也不存在那些個寄存器里了劫拢,而是填充完畢棧以后,將首地址返回給EAX强胰,對16字節(jié)舱沧、12字節(jié)、8字節(jié)測試偶洋,效果同上熟吏,棧空間分配減少字節(jié)而已
??通常玄窝,對于8字節(jié)以上的返回值分俯,都不會通過按值傳遞來返回肾筐,而是按引用傳遞,這樣做一方面可以避免編譯器返回局部變量地址缸剪,另一方面用地址返回速度較快吗铐,不用一個個值拷貝⌒咏冢考慮到函數(shù)結(jié)束后唬渗,棧應(yīng)該由系統(tǒng)收回,所以不應(yīng)該再使用奋渔,因此不能讓其傳遞為當(dāng)前函數(shù)棧變量镊逝;基于上述2點(diǎn),需要返回的地址嫉鲸,需要在調(diào)用參數(shù)時由父函數(shù)提供撑蒜,這也是最正規(guī)的,不會產(chǎn)生bug的思路玄渗,舉個例子:
struct pt
{
int x;
int y;
int z;
}
const pt& Getpt(pt& src);