لماذا يستخدم Visual Studio فأس XCHG ، الفأس
-
22-09-2019 - |
سؤال
كنت أبحث من خلال تفكيك برنامجي (لأنه تحطمت) ، ولاحظت الكثير من
xchg ax, ax
لقد غوغل واكتشفت أنها في الأساس nop ، ولكن لماذا يقوم Visual Studio بعمل XCHG بدلاً من noop؟
التطبيق هو تطبيق C# .NET3.5 64 بت ، تم تجميعه بواسطة Visual Studio
المحلول
على x86 NOP
تعليمات هو XCHG AX, AX
تتجمع الإرشادات ذاكري 2 إلى نفس الرمز الثنائي. (في الواقع ، أفترض أن المجمع يمكنه استخدام أي xchg
من السجل مع نفسه ، ولكن AX
أو EAX
هو ما يستخدم عادة ل nop
بقدر ما أعرف).
xchg ax, ax
لديه خصائص تغيير أي قيم التسجيل وتغيير عدم وجود أعلام (مهلا - إنه لا OP!).
تعديل (ردا على تعليق من قبل أنون.):
حسنًا - الآن أتذكر أن هناك العديد من الترميزات ل xchg
تعليمات. يأخذ البعض مجموعة Mod/R/M من البتات (مثل العديد من تعليمات الهندسة المعمارية Intel X86) التي تحدد مصدرًا ووجهة. هذه الترميزات تأخذ أكثر من بايت واحد. هناك أيضًا ترميز خاص يستخدم بايت واحد ويتبادل سجل الغرض العام مع (E)AX
. إذا كان السجل المحدد أيضًا (E)AX
ثم لديك تعليمات NOP بايت. يمكنك أيضًا تحديد ذلك (E)AX
يتم تبادلها مع نفسها باستخدام البديل الأكبر من xchg
تعليمات.
أظن أن MSVC يستخدم إصدار البايت المتعدد من xchg
مع (E)AX
كمصدر ووجهة عندما تريد مضغ أكثر من بايت واحد دون أي عملية - يستغرق نفس عدد الدورات مثل البايت المفرد xchg
, ، ولكن يستخدم مساحة أكبر. في التفكيك ، لن ترى البايت المتعدد xchg
فك تشفيرها NOP
, ، حتى لو كانت النتيجة هي نفسها.
على وجه التحديد xchg eax, eax
أو nop
يمكن تشفيرها على أنها رموز أوف 0x90
أو 0x87 0xc0
اعتمادًا على ما إذا كنت تريد استخدامها 1 أو 2 بايت. سوف يقوم Disassembler Visual Studio (وربما آخرين) بفك تشفير رمز opcode 0x90
كما NOP
التعليمات وسوف تفكك الرمز البسيط 0x87 0xc0
مثل xchg eax, eax
.
لقد مرت بعض الوقت منذ أن قمت بعمل لغة تجميع مفصلة ، لذا فمن المحتمل أن أكون مخطئًا في عدد واحد على الأقل هنا ...
نصائح أخرى
xchg ax,ax
و nop
هي في الواقع نفس التعليمات ، فإنها تخطط لنفس الرمز opcode (0x90 IIRC). هذا جيّد، xchg ax,ax
هو عدم وجود op. لماذا يجب أن يضيع أحد الرمز الإضافي مع التعليمات التي لا تفعل أي شيء؟
مشكوك فيه لماذا ترى كل من mnemonics مطبوعة. أعتقد أنه مجرد عيب في التفكيك الخاص بك ، لا يوجد فرق ثنائي.
فعلا، xchg ax,ax
هو فقط كيف تفكك MS "66 90". 66 هو تجاوز حجم المعامل ، لذلك من المفترض أنه يعمل على ax
بدلاً من eax
. ومع ذلك ، فإن وحدة المعالجة المركزية لا تزال تنفذها كـ NOP. يتم استخدام البادئة 66 هنا لجعل التعليمات في الحجم ، عادة لأغراض المحاذاة.
يضع MSVC NOPs في الكود المترجم لبناء التصحيح ، بشكل عام. هذا يسمح بتحرير ومواصلة العمل.
لا أعرف ما إذا كان له علاقة بالسؤال ولكن العديد من وظائف Windows تبدأ بـ MOV EDI ، EDI. هذا أيضا 2 بايت نوب. يعتبر اثنان من البايتات NOP مفيدة لرمز Hotpatch ، لأنه يمكنك استبداله بأمان بـ JMP قصير.
المرجعي: http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx
السؤال الحقيقي هنا هو ؛ لماذا اختار Disassembler عرضه كـ xchg ax,ax
و لا nop
?
أظن أن هذا من رمز 32 بت أو 64 بت و (بالنظر إلى أن disassembler عرض xchg ax,ax
و لا xchg eax,eax
) أن هناك بادئة تجاوز حجم المعامل تهدف إلى صنع nop
أكبر قليلاً (لتحقيق كمية معينة من الحشو مع تعليمات أقل) ؛ ووجود البادئات قد خلط xchg ax,ax
(عوضا عن nop
أو o16 nop
).