سؤال

أنا أستخدم Borland Turbo C ++ مع بعض رمز التجميع المضمّن ، لذلك من المفترض أن يكون رمز تجميع Turbo Assembler (TASM). أتمنى أن أفعل ما يلي:

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
SomeLabel:
    // ...
}

لذلك يتم وضع عنوان Somelabel في EAX. هذا لا يعمل ويشكو المترجم من: رمز غير محدد "سوملابل".

في Microsoft Assembler (MASM) ، يعمل رمز الدولار ($) كعضو الموقع الحالي ، والذي سيكون مفيدًا لغرضي. ولكن مرة أخرى لا يبدو أن هذا يعمل في بورتلاندز Assember (خطأ في بناء جملة التعبير).

تحديث: لكي أكون أكثر تحديداً بقليل ، أحتاج إلى المترجم لإنشاء العنوان الذي ينتقل إلى EAX باعتباره ثابتًا أثناء التجميع/الارتباط وليس في وقت التشغيل ، لذلك سيتم تجميعه مثل "MOV EAX ، 0x00401234".

هل يمكن لأي شخص أن يقترح كيفية الحصول على هذا العمل؟

تحديث: للرد على سؤال PAX (انظر التعليق) ، إذا تم تغيير العنوان الأساسي في وقت التشغيل بواسطة Windows Loader ، فسيظل يتم نقل صورة DLL/EXE PE بواسطة Windows Loader وسيتم تصحيح عنوان التسميات في وقت التشغيل بواسطة المحمل لاستخدام العنوان القائم على إعادة التخصيص ، لذا فإن استخدام قيمة وقت الترجمة/الارتباط لعنوان التسمية ليس مشكلة.

شكرا كثيرا مسبقا.

هل كانت مفيدة؟

المحلول

آخر مرة حاولت فيها جعل بعض كود التجميع متوافقًا مع بورلاند ، واجهت القيد الذي لا يمكنك فيه تسميات المرجع الأمامي. لست متأكدًا مما إذا كان هذا هو ما تواجهه هنا.

نصائح أخرى

كل ما يمكنني العثور عليه حول بورلاند يشير إلى أن هذا يجب أن يعمل. أسئلة مماثلة على مواقع أخرى (هنا و هنا) تشير إلى أن Borland يمكنه التعامل مع المراجع الأمامية للعلامات ، ولكنه يصر على أن تكون الملصقات خارج كتل ASM. ومع ذلك ، نظرًا لأن التسمية الخاصة بك كانت بالفعل خارج كتلة ASM ...

أشعر بالفضول حول ما إذا كان المترجم الخاص بك سيسمح لك باستخدام هذه التسمية ، على سبيل المثال ، تعليمات JMP. عندما أتجول معها (من المسلم به ، في برنامج مترجم مختلف تمامًا) ، وجدت ميلًا مزعجًا للمترجم للشكوى من أنواع المعامل.

بناء الجملة مختلف تمامًا ، وهي محاولتي الأولى في ASM المضمّنة منذ فترة طويلة ، لكنني أعتقد أنني أزعجت هذا بما يكفي للعمل بموجب مجلس التعاون الخليجي. ربما ، على الرغم من الاختلافات ، قد يكون هذا مفيدًا لك:

#include <stdio.h>
int main()
{
    void *too = &&SomeLabel;
    unsigned int out;
    asm
    (
      "movl %0, %%eax;"
      :"=a"(out)
      :"r"(&&SomeLabel)
    );
SomeLabel:
    printf("Result: %p %x\n", too, out);

    return 0;
}

هذا يولد:

...
        movl    $.L2, %eax
...
.L2:

مشغل && هو امتداد غير قياسي ، لا أتوقع أن يعمل في أي مكان آخر غير مجلس التعاون الخليجي. نأمل أن يكون هذا قد أثار بعض الأفكار الجديدة ... حظا سعيدا!

تحرير: على الرغم من أنه مدرج على أنه Microsoft محدد ، هنا هو مثال آخر للقفز إلى الملصقات.

3 اقتراحات:

1) ضع "_" أمام السليم في التجميع بحيث يصبح "Mov Eax ، _somelabel". عادةً ما يضيف المترجم واحدًا عندما يترجم C إلى التجميع.

أو

2) ضع الملصق في قسم التجميع. هذا سيمنع المترجم من إضافة "_".

أو

3) التعليق على التجميع ، وتجميع ، وابحث في ملف القائمة (*.LST) لمعرفة ما يصبح اسم التسمية.

هل لدى بيئة Turbo C ++ وسيلة لتحديد خيارات TASM (أعرف أن بعضًا من Ides Borland DID)؟

إذا كان الأمر كذلك ، راجع ما إذا كان تغيير الخيار لـ "Maximum Passes (/M)" إلى 2 أو أكثر يساعد (قد يكون افتراضيًا إلى 1 تمريرة).

أيضًا ، إذا كنت تستخدم اسم تسمية طويل قد يشكل مشكلة - فقد تم تعيين IDE على الأقل إلى 12. قم بتغيير "خيار طول الرمز (/MV)".

تستند هذه المعلومات إلى Borland's Rad Studio IDE:

بضعة أشياء أخرى (لقطات في الظلام) لمحاولة:

  • معرفة ما إذا كان استخدام تعليمات التجميع التالية يساعد:

    mov eax, offset SomeLabel
    
  • يمكن لمعظم المترجمين إنتاج قائمة تجميع بالرمز الذي يقومون بإنشائه (غير متأكد من أن Turbo C ++ يمكنه ، لأن Codegear/Embarcadero يضعه كمترجم مجاني وغير محترف).

    حاول إنتاج قائمة باستخدام رمز C الذي يحتوي على تسمية (كـ goto الهدف على سبيل المثال) ، مع بعض التجميع المضمّن في نفس الوظيفة - ولكن لا تحاول الوصول إلى الملصق من التجميع. هذا حتى تتمكن من الحصول على مترجم بدون أخطاء وقائمة تجميع. شيء مثل:

    int foo()
    {
        int x = 3;
        printf( "x =%d\n", x);
        goto SomeLabel;
                               //
        __asm {
            mov eax, 0x01
        }
                               //
    SomeLabel:
        printf( "x =%d\n", x);
                               //
        return x;
    }
    

    انظر إلى قائمة التجميع ومعرفة ما إذا كانت المجموعة التي تم إنشاؤها تزين اسم التسمية بطريقة قد تتمكن من تكرارها في التجميع المضمّن.

من ما أتذكره ، لا يمكنك استخدام تسمية خارجية (C ++) في التجميع المضمّن الخاص بك ، على الرغم من أنه يمكنك الحصول على ملصقات على طراز Tasm في كتلة ASM التي يمكن الرجوع إليها من خلال تعليمات التجميع نفسها. أعتقد أنني سأستخدم علامة وبيان تبديل بعد التجميع للتعامل مع المتفرعة. فمثلا:

int result=0;

__asm__ {
    mov result, 1
}

switch (result){
    case 1:  printf("You wanted case 1 to happen in your assembler\n"); break;
    case 0:  printf("Nothing changed with the result variable.. defaulting to:\n");
    default: printf("Default case!\n"); break;
}

لا أعرف عن برنامج التحويل البرمجي / المجمع الخاص بك على وجه التحديد ، لكن الخدعة التي استخدمتها قليلاً هي استدعاء الموقع التالي ثم قم ببث المكدس في السجل الخاص بك. تأكد من أن المكالمة التي تقوم بها فقط تدفع عنوان الإرجاع.

أعتقد أن المشكلة التي تواجهها هي أن تسمية داخل __asm الحظر والتسمية في رمز C ++ هما شيئان مختلفان تمامًا. لا أتوقع أن تتمكن من الرجوع إلى علامة C ++ بهذه الطريقة من التجميع المضمّن ، لكن يجب أن أقول أنها مضى وقت طويل جدًا منذ أن استخدمت Turbo C ++.

هل جربت lea التعليمات بدلا من mov?

مجرد التخمين لأنني لم أستخدم مجمعًا مضمّنًا مع أي مترجم C/++ ...

void foo::bar( void )
{
    __asm
    {
      mov eax, SomeLabel
      // ...
    }
    // ...
    __asm
    {
      SomeLabel:
      // ...
    }
    // ...
}

لا أعرف بناء الجملة الدقيق لل tasm.

هذا هو البديل من اقتراح إيفان ولكن جرب هذا:

void foo::bar( void )
{
    __asm
    {
      mov eax, offset SomeLabel
      // ...
    }
    // ...
    __asm SomeLabel:
    // ...
}

هذه طريقة محتملة:

// get_address
// gets the address of the instruction following the call
// to this function, for example
//     int addr = get_address (); // effectively returns the address of 'label'
//   label:
int get_address ()
{
    int address;
    asm
    {
        mov eax,[esp+8]
        mov address,eax
    }
    return address;
}
// get_label_address
// a bit like get_address but returns the address of the instruction pointed
// to by the jmp instruction after the call to this function, for example:
//     int addr;
//     asm
//     {
//       call get_label_address // gets the address of 'label'
//       jmp label
//       mov addr,eax
//     }
//     <some code>
//   label:
// note that the function should only be called from within an asm block.
int get_label_address()
{
    int address = 0;
    asm
    {
        mov esi,[esp+12]
        mov al,[esi]
        cmp al,0ebh
        jne not_short
        movsx eax,byte ptr [esi+1]
        lea eax,[eax+esi-1]
        mov address,eax
        add esi,2
        mov [esp+12],esi
        jmp done
    not_short:
        cmp al,0e9h
        jne not_long
        mov eax,dword ptr [esi+1]
        lea eax,[eax+esi+2]
        mov address,eax
        add esi,5
        mov [esp+12],esi
        jmp done
    not_long:
        // handle other jmp forms or generate an error
    done:
    }
    return address;
}
int main(int argc, char* argv[])
{
    int addr1,addr2;
    asm
    {
        call get_label_address
        jmp Label1
        mov addr1,eax
    }

    addr2 = get_address ();
Label1:
    return 0;
}

إنه مخترق بعض الشيء ولكنه يعمل في إصدار Turbo C ++ الذي لدي. من المؤكد أنه يعتمد على إعدادات التحويل البرمجي والتحسين.

أحد الخيارات هو استخدام إجراء "عارية" (أقل من مقدمة) منفصل بدلاً من التسمية

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