الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الفرق بين Stdcall و Fastcall

مثبّت
بدأه fkugd2003 في 12 مايو 2009 · 14 رد · 4,717 مشاهدة · في المواضيع المميزة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكــم ورحمـة الله وبركاتــه ،،

الملل قاتل اليوم ولم اجد ما افعل فقلت اتسلى قليلا بسي و دلفي... على الاقل الواحد يجد ما يفعل

الفكرة بسيطة و ربما يعرفها الكثيرون لكن ربما تنفع احد الاخوة (لا تلوموني اذا لم تفدكم :D ).

ذكر iczelion في درسه الاول في القسم المتعلق بتمرير البراميتر (Parameter Passing Conventions under Win32) ما يلي :

بخصوص طريقة لغة السي في تمرير البارامترات...

اقتباس
The C calling convention passes parameters from right to left, that is , the rightmost parameter is pushed first. The caller is responsible for balancing the stack frame after the call

.

اما بخصوص طريقة الباسكال

اقتباس
The PASCAL calling convention is the reverse of the C calling convention. It passes parameters from left to right and the callee is responsible for the stack balancing after the call

.

لكن هذه الطريقتين لا تستعملان الان في انظمة الوين 32 (حسبما اعرف)...

.. stdcall و fastcall هي الاكثر استعمالا حسب ما اعرف (ارج وان يصحح لي اي شخص يظن انني مخطأ).

لذلك فقد رايت ان اجرب لارى هل دلفي و vc++ 9.0 يستعمل احدى الطريقتين..

قمت بكتابة برنامج بسيط بسي و دلفي يقوم بجمع متغيرين و يضعهما في واحد اخر.

سي:

 
#include "stdafx.h"
#include <stdio.h>
#include <string.h>

void add(int a, int b);
int res, a,b;
int main(int argc, char *argv[]) {
	a= 3;
	b= 2;
	add(a,b);
}

void add(int a, int b)
{
	res = a+b;
}

يمكن ان تحول main الى _tmain لكي تستطيع ان تقوم بتنقيح الكود على الفيجوال ستوديو

لا تهتم ب #include "stdafx.h" لان مترجم مكروسوفت يقوم بتضمين ذلك الملف اوتوماتيكيا

نفس البرنامج قمت بكتابته على دلفي 7.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;
var res,a,b:integer;

procedure add(a:integer;b:integer);
begin
res := a+b;
end;
begin
  { TODO -oUser -cConsole Main : Insert code here }
  a:=3;
  b:=2 ;
  add(a,b);
end.

قمت بتحميل برنامج الدلفي على اوللي

post-64798-1242161124_thumb.jpg

هل لاحظت العنوان

004011DE --call Project1.00401148

لنحاول ان نرى ما يحتويه

post-64798-1242161250_thumb.jpg

يقوم بجمع EDX+ EAX مباشرة دون اللجوء الى المكدس... هذه هي ال fastcall

ثم قمت بتحميل كود السي في منقح visual studio مباشرة لانه يعطي التنقيح + السورس كود

 	a= 3;
004113BE  mov		 dword ptr [a (417144h)],3 
	b= 2;
004113C8  mov		 dword ptr [b (417140h)],2 
	add(a,b);
004113D2  mov		 eax,dword ptr [b (417140h)] 
004113D7  push		eax  
004113D8  mov		 ecx,dword ptr [a (417144h)] 
004113DE  push		ecx  
004113DF  call		add (4110CDh) 
004113E4  add		 esp,8

العكس تماما في السي مقارنة بدلفي

 
004113D7  push		eax  
.
.
004113DE  push		ecx  
004113DF  call		add (4110CDh)

يتم نسخ المتغيرين الى المكدس... هذه هي ال stdcall

حسبما اعرف فان ال fastcall اسرع من stdcall...و هذا ما يفسر سرعة الدلفي... :D

التكنيك محفوظ لي :D :D لا تنسبوه لانفسكم في مواضيع اخرى و تقولو تكنيككم و الا فضحتكم ( يا حلاوة :D :D )

تم تعديل هذه المشاركة بواسطة fkugd2003 في 13 مايو 2009 في 01:10

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#2

وعليكــم السـلام ورحمة الله وبركاتـه..

جميل ،، موضوع الCalling Convention موضوع مهم أحيانا وغير مهم في نفس اللحظه :) .

تقريبا الCalling Convention تحدد 3 أمور اساسيه :

طريقه تمرير المعاملات سواء left-to-right او right-to-left

عمليه تفريغ المكدس Stack Cleanup ومن المسؤول عن تلك العمليه Caller or Callee

الdecoration الذي يضعه المترجم للداله سواء بالحاق علامه _ أو @ قبل أو بعد اسم الداله .

بالنسبه للغه السي فهي تستخدم ال __cdecl وهو يكون كما ذكر مستر iczelion أن رفع المعاملات pushing on stack تكون من اليمين الى اليسار ،، ولكن الداله التي تقوم بالاستدعاء عليها أن تقوم بعمل pop لهذه المعاملات بعد انتهاء الداله stack cleanup ويتم ذلك باضافه حجم المعاملات للstack pointer .

ومن هنا كان الأسلوب ال __cdecl يأخذ حجما أكبر من ال __stdcall حيث الأخيره تكون الstack cleanup داخل الداله ،، خصوصا في حال تم استدعاء الداول بشكل كثير ،،،

كانت هذه اضافه بسيطه لقتل الملل أيضا :P

تسلم أخي على الموضوع :) .

بالتوفيق ،،

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

#3

بارك الله فيك على الاضافة اخي وجدي...

لتفريغ المكدس يتم اضافة البايتات التي حملت الى المؤشر كما في المثال

add		 esp,8

4 + 4 حجم متغيرين من نوع int...

اقتباس
كانت هذه اضافه بسيطه لقتل الملل أيضا

جميل جدا اظن ان الملل مفيد كثيرا :D

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#4

لمادالغةالبسكال تستعمل fastcall ولغة C استعملت sdtcall ممكن توضيح سبب هدا الفرق

#5
اقتباس
لمادالغةالبسكال تستعمل fastcall ولغة C استعملت sdtcall ممكن توضيح سبب هدا الفرق

الحقيقة أن لغة C لا تحدد طريقة استدعاء الدوال و عملية التنظيف بعدها :lol:

هذا عائد لمصنعي المترجمات,

هذه Conventions و بالتالي يمكنك اختراع طريقة جديدة إن أحببت, و لكن هذا يتم على مستوى لغة الأسمبلي الخاصة بالمعالج :)

بالطبع ستظهر المشكلة عندما تريد استدعاء قطعة الكود من مكان آخر من مترجم آخر و كان ذلك المترجم يعتمد على وضع افتراضي, لهذا وضعت هذه الـ Conventions ...

في الحقيقة أن مترجمات C كـ GCC و VC لديها وضع افتراضي, و يمكنك تغيير الـ Conventions حسب الرغبة ...

تحياتي ...

#6

كلام اخي خالد كامل و مفيد كالعادة...

انا لم اعتمد على اي optimisation بل فقط الاعدادات الافتراضية التي تأتي مع كلا المنتوجين..

اما اذا اردنا ان نحدد طرق المناداة و optimisations فالامر يختلف كثيرا...

كفكرة عامة الامر كله كان لتوضيح fastcall و stdcall بطريقة تطبيقية :D

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#7

حيل لغة السى لا تعد ولا تحصى ، إذا اردت أن تنجز شيئ بشكل ما ، فتأكد أن السى تستطيع إنجازة بالشكل الذى تريده

#include "stdafx.h"
#include <stdio.h>

int res, a, b;

#define add(x, y) res = x+y

void main(int argc, char *argv[])
{
	a= 3;
	b= 2;
	add(a,b);
}

هل الاسميلى الخاص بالكود

13:	   a= 3;
00401038   mov		 dword ptr [a (00427c54)],3

14:	   b= 2;
00401042   mov		 dword ptr [b (00427c50)],2

15:	   add(a,b);
0040104C   mov		 eax,[a (00427c54)]
00401051   add		 eax,dword ptr [b (00427c50)]
00401057   mov		 [res (00427c58)],eax

تم تعديل هذه المشاركة بواسطة helaly في 15 مايو 2009 في 10:48

#8
اقتباس
حيل لغة السى لا تعد ولا تحصى ، إذا اردت أن تنجز شيئ بشكل ما ، فتأكد أن السى تستطيع إنجازة بالشكل الذى تريده

اعرف هذه <_<

يمكن ان تلاحظ انني اتكلم عن fastcall و stdcall و ليس ال macro....

فقط كتعليق... عندما ستتعمل ال macro فان الكود المكتوب عندما يمر من مرحلة ال preprocessor يصبح

#include "stdafx.h"
#include <stdio.h>

int res, a, b;

#define add(x, y) res = x+y

void main(int argc, char *argv[])
{
	a= 3;
	b= 2;
	res = a+b;
}

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#9

نعم اخى انا اتحدث على حيل لأداء افضل

الا تعتقد أن كود السى السابق اسرع من نظيره

سأقربها لك، ماذا لو استبدلنا int بـــ float :

#include "stdafx.h"
#include <stdio.h>
#include <string.h>

void add(float a, float b);
float res, a,b;
void main(int argc, char *argv[]) {
	a= 3.0;
	b= 2.0;
	add(a,b);
}

void add(float a, float b)
{
	res = a+b;
}

ماذا سيكون أداء الدلفى فى هذا المثال؟ وهل توجد حيل لرفع اداءه؟

#10
اقتباس
نعم اخى انا اتحدث على حيل لأداء افضل

لاحظ ان الموضوع لا يتحدث عن حيل و انما عن calling conventions

اقتباس
ماذا لو استبدلنا int بـــ float :

لا يتغير شيئ... فقط يتم استعمال floating point operations

	12: 	a= 3;
004113DE D9 05 38 58 41 00 fld		 dword ptr ds:[00415838h] 
004113E4 D9 1D 54 71 41 00 fstp		dword ptr ds:[00417154h] 
	13: 	b= 2;
004113EA D9 05 34 58 41 00 fld		 dword ptr ds:[00415834h] 
004113F0 D9 1D 50 71 41 00 fstp		dword ptr ds:[00417150h] 
	14: 	add(a,b);
004113F6 51			   push		ecx  
004113F7 D9 05 50 71 41 00 fld		 dword ptr ds:[00417150h] 
004113FD D9 1C 24		 fstp		dword ptr [esp] 
00411400 51			   push		ecx  
00411401 D9 05 54 71 41 00 fld		 dword ptr ds:[00417154h] 
00411407 D9 1C 24		 fstp		dword ptr [esp] 
0041140A E8 E6 FC FF FF   call		004110F5 
0041140F 83 C4 08		 add		 esp,8

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#11

السلام عليكم ....

بواسطة VC :)

int __cdecl square1( int x ){

	return x*x;
}

int __stdcall square2( int x ){

	return x*x;
}

int __fastcall square3( int x ){

	return x*x;
}

int main(){

	int x1 = square1(2), x2 = square2(2), x3 = square3(2);

	return 0;
}

تحياتي ...

#12

لاحظ ان بعض الـConventions يكون هناك اختلاف بين مجمّع وآخر ، راجع ردّي :

/index.ph...st&p=931621

أيضا هناك Internal conventions تستخدم في الـC++/Java Classes مثل thiscall .

تم تعديل هذه المشاركة بواسطة GamingMasteR في 15 مايو 2009 في 23:56

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#13
اقتباس
تسال الناس عن __cdecl *** وعند مكروسوفت الخبر اليقين

:D

كنت اتجهز لاكتب عن الرموز @ و _ التي تضاف في الدوال حتى ذكرتها ... مشكور GM

لك غيبة يا رجل :D

العمل كثير و الوقت قليل أعاننا الله

seo zen SEO Enlightment amazon danbo

#14

جو الامتحانات المحبط ،، اكتفي بالمشاهدة فقط كي لا انقل عدوى "النكد" لكم :D

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#15

اضافه صغيره ، وهي الدوال متعددة المعاملات Variadic Function مثل printf وغيرها في لغه السي يجب أن تتبع الـ __cdecl ، حيث لا تستطيع الدالة المستدعاة Calle معرفة عدد المعاملات المرسله في المكدس لذلك تصحيح أو تنظيف أو تحرير :) المكدس سيكون من مسؤوليه الCaller .

بالتوفيق :) .

http://informatic-ar.com منصة تعليمية عربية في علوم الحاسب والبرمجة

https://moalfat.com  للكتب الالكترونية والكورسات التعليمية

Everything we see now is just an engineering solution based on old science

مواضيع مشابهة