PDA

View Full Version : سوال: push pop بی استفاده ی کامپایلر



UfnCod3r
یک شنبه 19 مهر 1394, 09:32 صبح
چرا کامپایلر چنین تابعی رو ب این صورت اسمبل می کنه. هاین؟

unsigned QWEQWE(unsigned a , unsigned b, unsigned c)
{
return a + b + c;
};


_TEXT ENDS
PUBLIC ?QWEQWE@@YAIIII@Z ; QWEQWE
; Function compile flags: /Ogtp
; COMDAT ?QWEQWE@@YAIIII@Z
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
?QWEQWE@@YAIIII@Z PROC ; QWEQWE, COMDAT

; 246 : {

push ebp
mov ebp, esp

; 247 : return a + b + c;

mov eax, DWORD PTR _b$[ebp]
add eax, DWORD PTR _a$[ebp]
add eax, DWORD PTR _c$[ebp]

; 248 : };

pop ebp
ret 0
?QWEQWE@@YAIIII@Z ENDP ; QWEQWE
_TEXT ENDS





وقتی به ebp , esp اصلا کاری نداریم چ لزومی ب این کار هست.
اینطوری هم ک میشه.

_TEXT ENDS
PUBLIC ?QWEQWE@@YAIIII@Z ; QWEQWE
; Function compile flags: /Ogtp
; COMDAT ?QWEQWE@@YAIIII@Z
_TEXT SEGMENT
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_c$ = 16 ; size = 4
?QWEQWE@@YAIIII@Z PROC ; QWEQWE, COMDAT

mov eax, DWORD PTR _b$[esp]
add eax, DWORD PTR _a$[esp]
add eax, DWORD PTR _c$[esp]
ret 0

?QWEQWE@@YAIIII@Z ENDP ; QWEQWE
_TEXT ENDS

m.j_banitaba
یک شنبه 19 مهر 1394, 18:22 عصر
زبان c جهت نگهداری متغیر های محلی و ارسال پارامتر به تابع از stack استفاده میکند . نکته آن این است که استفاده از این روش وابستگی زبان را به سیستم عامل کم می کند و همچنین در توابع بازگشتی اینکار باعث می شود که به تعداد فراخوانی ها متغییر محلی داشته باشیم. در ضمن جهت نگهداری فریم فراخوانی از ebp استفاده می کند بنابر این هر مقدار هم که متغییر محلی ایجاد کنید ebp همواره به ابتدار فریم فراخوانی اشاره می کند .
https://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames

xman_1365_x
سه شنبه 21 مهر 1394, 08:14 صبح
چرا کامپایلر چنین تابعی رو ب این صورت اسمبل می کنه. هاین؟
همونطور که دوستمون گفتن استاندارد ارسال پارامتر به توابع هست که بهش میگن calling convention که انواعی داره که میتونید لینک 1 (https://en.wikipedia.org/wiki/Calling_convention) و 2 (https://en.wikipedia.org/wiki/X86_calling_conventions) را مطالعه کنید


وقتی به ebp , esp اصلا کاری نداریم چ لزومی ب این کار هست.
در این مورد اگر در تابع شما از push، pop یا فراخوانی تابع استفاده کرده باشید مقدار esp رو تغییر میده و شما نمیتونید ازش به اون شکلی که نوشتین(به صورت ثابت) استفاده کنید چون باید مقداری که تغییر میکنه محاسبه کرد و این برای توابع پویا سخت تر میشه چون باید زمان اجرا محاسبه بشه(شاید بخشی از کد اصلا فراخوانی نشه) با همه این دلایل از ebp(نام این ثبات اشاره گر بیس یا مبنا هست!) استفاده میکنند تا اشاره گر ثابتی داشته باشیم که بر اساس اون پارامتر ها رو ارسال کنیم درمواردی که شاید تابع شما نیازی به آرگومان ورودی ندارد(در مورد naked function مطالعه کنید) و یا از چه calling convention دیگری میخواهید استفاده کنید باید صراحتا برای کامپایلر مشخص کنید(مثل stdcall, cdecl).
موفق باشید

UfnCod3r
سه شنبه 21 مهر 1394, 20:43 عصر
اینچیزا ک شما گفتیدو می دونم.
من می گم وقتی ک ثبات هیچ تغییری نمی کنه چ لزومی ب push pop هست.
مثلا چنین چیزی معنی داره ؟ معمولمه ک ن


push eax
add ebx, ebx
pop eax

اصلا ما کاری ب eax نداریم پس این push, pop هم لازم نیست.
اون تابع صدا زدنش اینطوری میشه .

push 1
push 2
push 3
call QWEQWE
add esp, 12

چ ما تو تابعمون push , pop کنیم و نکنیم هیچ فرقی نداره . نمیدونم چرا کامپایلر چنین کدی تولید میکنه. اگه بهینه سازی قراره بکنه چرا این چنین چیز ساده ای رو نمی کنه . حتما ی دلیلی داره . مثلا شاید اینکه پردازشگر به prelouge , epilouge عادت داره ک بعید می دونم.

xman_1365_x
پنج شنبه 23 مهر 1394, 00:14 صبح
اینچیزا ک شما گفتیدو می دونم.
من می گم وقتی ک ثبات هیچ تغییری نمی کنه چ لزومی ب push pop هست.

دوست عزیز احتمالا اینایی هم که الان میگم از قبل میدونید برای همین کلی میگم، همونطور که در پست های قبلی گفته شد ما یک سری استاندارد داریم که بر اساس اون قواعد کامپایل انجام میشه، بعد از این حالت میشه سوال شما که چطور میتونیم سورس با حجم کمتر داشته باشیم یا حجم مهم نیست از چه دستور عمل هایی استفاده کنیم که سرعت بالاتر باشه و یا میانگین این دو و حالت های دیگه همه این موارد در Optimization بحث میشه، برای مثال شما اگر برنامتون رو با فلگ های Minimize Size (/O1) ,Disabled (/Ob0),Yes (/Oy) کامپایل کنید خروجی زیر رو میبینید که اگر ob0 رو Default کنید حتی خود دستور call و ret تابع هم حذف میشه و کلش میشه دو دستورالعمل اسمبلی



return a + b + c;
00A61000 lea eax,[ecx+edx]
00A61003 add eax,dword ptr [esp+4]
};
00A61007 ret

UfnCod3r
پنج شنبه 23 مهر 1394, 10:13 صبح
تو اینلاین و اینا ک اره درست بهینه میشه.ولی من هدفم ب صورت تابع cdecl_ هست.
من با VS2010 کامپایلکردم بهینه سازی هم رو حداکثر بود.
ما ک اخر نفهمیدم. این همه کد رو این کامپایلر بهینه میکنه چرا چنین چیز ساده ای رو نه:متفکر::متفکر::متفکر::متفک :
شایدم این کدی ک میده کد نهایی نیست واس . بزار برنامه رو دی اسمبلش کنم.

UfnCod3r
پنج شنبه 23 مهر 1394, 11:10 صبح
فهمیدم بخاطر فلگ Oy هست.
Oy/ اضافه بشه درست میشه .