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

تحويل كود بلغة السي بلس الى الاسمبلي

بدأه ليااال في 14 ديسمبر 2010 · 6 رد · 3,638 مشاهدة · في أرشيف قسم الـــ Assembly
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

كيف يتم تحويل كود السي بلس بلس الى لغة الاسمبلي

post-237276-099196500 1292357869_thumb.j

المرفقات
Test2-1.jpg 7867659808.jpg
#2
.data
bb      dw 64 dup (0)   ; int[] bb

.data?
ct      dw ?            ; int ct .. it could also be dd
j       dw ?            ; int j  .. it could also be dd

.code
mov     ct, 0           ; ct = 0
mov     j, 0            ; j = 0

mov     di, offset bb

_while:
cmp     j, 64           ; j >= 64 ?
jge     _endWhile       ; jump to _endWhile if yes
; no
movsx	bx, j
cmp     [di+bx*2], 40     ; bb[j] < 40 ?
jl      _next           ; get next if yes
; no
cmp     [di+bx*2], 50     ; bb[j] >= 50 ?
jge     _next           ; get next if yes
; no
inc     ct              ; ct++
_next:
inc     j               ; j++
jmp     _while
_endWhile:

* افترضت أن المسجلات بطول 16 بت.

* افترضت قيمة بدائية صفرية لكامل محتوى المصفوفة bb[].

* يمكن كتابة الكود بصورة أبسط من خلال استخدام Conditional Control Flow كالمدعومة في الإصدار 6.1+ من MASM مثلاً، لكني أبقيته pure assembly.

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#3

أنا لا اريد جل ولكن اريد شرح لاساسيات العمل

#4

لديك طريقتين، في الامتحان إحداهما غير ممكنة:

1- كتابة البرنامج بـ C++ ومن ثم استخدام debugger لقراءة التعليمات التي تم تشكيلها بالأسمبلي :P وهذا غير ممكن في الامتحان.

2- قراءة كل سطر من سطور البرنامج وكتابة مثيلاتها بالمقابل في الأسمبلي، لا يوجد عصا الساحر هنا ليكون هناك قاعدة للتحويل، الأمر يحتاج إلى معرفة بلغة C++ حتى تستطيعين معرفة ما تقرأين وبالتالي كتابة المقابل في الأسمبلي.

الآن بشكل عام:

- لدينا تصريح عن متحولات:

علينا معرفة عدد البايتات التي يقوم بحجزها كل نمط type فمثلاً char سيحجز بايت واحد بالتالي نستخدم db لحجز بايت واحد في الأسمبلي، بينما int يلزمها 2 بايت أو أكثر (الأمر متعلق بالمعالج الذي تنفذ عليه، فإن كانت مسجلاته بطول 16 بت فالـ int تحجز بايتين وتكون القيمة العظمى هي 65,565 أي 0FFFFh .. وهكذا)

في الحل افترضت أنك تتعاملين مع مسجلات بطول 16 بت وعليه استخدمت dw لحجز word للمتحولين ct و j

- لدينا كتلة التحكم بالتدفق WHILE:

هذه التعليمة مبنية على شرط يجب تحقيقه حتى يتم تنفيذ الكتلة المحصورة بين القوسين { }

في مثالنا هنا الشرط هو أن تكون قيمة j أصغر تماماً من 64 (حتى لا يخرج الـ index خارج المجال الخاص بالمصفوفة bb[] كما تلاحظين)

ومن المعروف أنه في حال انتفاء الشرط، لا يتم تنفيذ الكتلة بين القوسين ويتم تجاوزها تماماً، إذاً سأقوم بكتابة التالي:

cmp	j, 64
jge	_endWhile
;{
;	...
;	...
;}
_endWhile:

من الواضح أني أقوم هنا بمقارنة قيمة j مع 64، هل j أكبر أو تساوي 64 ؟ إن كانت الإجابة نعم فعليك الانتقال إلى اللافتة _endWhile والتي تتخطى الكتلة وتتجاوزها لأن شرط تنفيذ الكتلة هو أن تكون j أصغر تماماً من 64

- لدينا كتلة تحكم بالتدفق IF:

الشرط الذي يجب تحقيقه بـ C++ هو:

if (bb[j] >= 40 && bb[j] < 50)

السؤال الأهم هنا: كيف يتم التعبير عن المصفوفة bb[j] في الأسمبلي؟

لنتخيل المصفوفة في الذاكرة وهي عبارة عن مربعات متراصة إلى جانب بعضها البعض.

يجب فهم النقاط التالية للحصول على أفضل جودة عرض في التخيل :P:

  • كل مربع من هذه المربعات له طول محدد بنمط المصفوفة (مثلاً: int[] bb فتكون المصفوفة لأعداد صحيحة كل واحد بطول 2 بايت كما افترضنا سابقاً)
  • كل مربع من هذه المربعات يحمل قيمة.
  • كل مربع من هذه المربعات له عنوان في الذاكرة.
  • وكل مربع من هذه المربعات له ترتيب محدد، يتم الاصطلاح على أن يحمل المربع الأول في المصفوفة الترتيب 0 والمربع الثاني الترتيب 1 وهكذا .. ويكون المربع الأخير ذو ترتيب n-1 حيث n تساوي طول المصفوفة (في السؤال هنا n = 64)

إذاً نستطيع تخيل bb[] في الذاكرة بالشكل التالي:

post-7008-093262600 1292426630_thumb.png

كيف نعبر عن bb[4] بتعليمات أسمبلي؟

كما نرى من الصورة نحتاج إلى Base address وهو يمثل عنوان أول بايت في المصفوفة bb[]

يمكن الحصول على هذا العنوان باستخدام تعليمة LEA (Load Effective Address) أو MOV مع التوجيه OFFSET بالشكل:

lea di, bb       ; is equivalent to
mov di, offset bb

نحتاج أيضاً إلى معرفة ترتيب (index) العنصر المطلوب الحصول عليه وهنا index = 4

نحتاج أيضاً إلى معرفة حجم نمط المتحول الذي نسعى إليه وهو هنا int وقد افترضنا أن int = word بالحجم أي 2، لكننا نستطيع أن ندع الأسمبلر يقوم بحساب الحجم المناسب بشكل اوتوماتيكي من خلال المعامل المسمى sizeof

التعليمات المناسبة بالأسمبلي تكون:

lea     di, bb
mov     ax, [di + 4 * sizeof(word)]

(للمزيد من المعلومات حول هذه النقطة بشكل عام يجب دراسة مفاهيم العنونة)

سنقوم بإضافة هذا المفهوم إلى الهيكل الذي أنشأناه سابقاً لكتلة التحكم WHILE:

cmp	j, 64
jge	_endWhile
;{
mov	di, offset bb
movsx	bx, j
cmp	word ptr [di+bx*2], 40
jl	_next
cmp	word ptr [di+bx*2], 50
jge	_next
;	..
;	..
_next:
;	..
;}
_endWhile:

لكن العنوان القاعدي للمصفوفة bb[] ثابت لذلك سننقل التعليمة التالية إلى خارج الحلقة حتى لا يتم تكرار تنفيذها بدون داع

mov	di, offset bb

ويصبح الكود

mov	di, offset bb

cmp	j, 64
jge	_endWhile
;{
movsx	bx, j
cmp	word ptr [di+bx*2], 40
jl	_next
cmp	word ptr [di+bx*2], 50
jge	_next
;	..
;	..
_next:
;	..
;}
_endWhile:

الشرط الذي أضفناه باستخدام التعليمة CMP وتعليمات القفز المناسبة يختبر محتوى العنوان bb[j] فإن كان أصغر تماماً من 40 و أكبر أو يساوي 50 يتم تخطي الأمر ct++ بالقفز إلى اللافتة _next

لإكمال الكود بشكله النهائي نضيف تعليمتي ct++ و j++ في الأمكنة المناسبة

mov	di, offset bb

_while:
cmp	j, 64
jge	_endWhile
;{
movsx	bx, j
cmp	word ptr [di+bx*2], 40
jl	_next
cmp	word ptr [di+bx*2], 50
jge	_next
inc	ct
_next:
inc	j
jmp   _while
;}
_endWhile:
المرفقات
untitled.PNG
4

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#5

شكرا اخي شرحك واضح

سارفق لك الحل النموذجي للدكتور

ولكن هناك اختلاف قليل في الاجابة هل تفسر لي ذلك

post-237276-088739300 1292439064_thumb.j

المرفقات
Test2-1.jpg rwfqwfaw.jpg
#6

اوك.

- بدلاً من أن يقوم بحجز متغير j كما فعلت أنا. قام باعتماد المسجل ESI لتمثل قيمته قيمة المتحول j وهذا جائز شرعاً وقانوناً :)

لذلك قام بتنفيذ int j = 0 من خلال السطر التالي:

mov esi, 0

- بدلاً من أن يقوم بزيادة قيمة j بمقدار 1 ومن ثم ضربها بـ 2 كما فعلت أنا في السطر

[di+bx*2]

حيث j = bx

قام بزيادة قيمة j بمقدار 2 مباشرة من خلال السطر

add esi, 2

- بما أنه اعتمد هذه الطريقة أصبح شرط الكتلة WHILE أن تكون قيمة ESI كحد أقصى تساوي mimetex.cgi?(n-1)*2 حيث n=64 (حجم المصفوفة) و 2 يمثل حجم النمط (int).

- لأن ESI أصبحت تمثل قيمة عددية (imm) وهي j أصبح بالإمكان اتباع العنونة بالشكل [reg+imm] لتمثيل bb[j] بدلاً من [reg+index*size] لذلك استخدم السطر التالي:

cmp bb[esi], 40

وهي ذاتها لو كتبتها بالشكل

 cmp [esi+bb], 40

- القفزات التالية لها التأثير ذاته:

jb <-> jl

jae <-> jge

حيث نستخدم: JG و JL ومشتقاتها (JGE, JLE, ...) مع الأعداد المؤشرة

ونستخدم: JA و JB ومشتقاتها (JAE, JBE, ...) مع الأعداد الغير مؤشرة

وعلى الرغم من أني حاولت مراعاة هذه النقطة لورودها في السؤال (unsigned word values) عند كتابتي لطريقتي إلا أنه يبدو أني قد كبرت وخانتني ذاكرتي فكتبت JGE بدلاً من JAE وكتبت JL بدلاً من JB :blush:

طبعاً النتيجة واحدة بما أننا نتعامل مع القيم غير مؤشرة، لكن في حال تعاملنا مع قيم مؤشرة فيجب استخدام التعليمات المناسبة حصراً.

انتهى :)

3

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#7

شكرا اتعبتك معي

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