سؤال

كنت أبحث من خلال تفكيك برنامجي (لأنه تحطمت) ، ولاحظت الكثير من

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).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top