كيف يمكنني ضرب رقمين 64 بت باستخدام لغة التجميع x86؟

StackOverflow https://stackoverflow.com/questions/87771

  •  01-07-2019
  •  | 
  •  

سؤال

كيف سأمضي...

  • ضرب رقمين 64 بت

  • ضرب رقمين سداسيين مكونين من 16 رقمًا

...باستخدام لغة التجميع.

يُسمح لي فقط باستخدام السجلات %eax و%ebx و%ecx و%edx والمكدس.

يحرر:أوه، أنا أستخدم بناء جملة ATT على x86
تحرير 2:غير مسموح بفك التجميع ...

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

المحلول

استخدم ما ينبغي أن يكون كتابك الدراسي، وهو "فن لغة التجميع" لراندال هايد.

يرى 4.2.4 - الضرب الدقيق الموسع

على الرغم من أن الضرب 8x8 أو 16x16 أو 32x32 يكون كافيًا عادةً، إلا أنه في بعض الأحيان قد ترغب في مضاعفة القيم الأكبر معًا.ستستخدم تعليمات MUL وIMUL ذات المعامل الفردي x86 للضرب الدقيق الممتد.

ربما الشيء الأكثر أهمية هو أن نتذكر عند إجراء عملية ضرب موسعة الدقة، يجب عليك أيضًا إجراء عملية إضافة متعددة الدقة في نفس الوقت.تتطلب إضافة جميع المنتجات الجزئية عدة إضافات من شأنها أن تنتج النتيجة.توضح القائمة التالية الطريقة الصحيحة لضرب قيمتين 64 بت على معالج 32 بت..

(راجع الرابط للحصول على قائمة التجميع الكاملة والرسوم التوضيحية.)

نصائح أخرى

إذا كان هذا 64x86،

function(x, y, *lower, *higher)
movq %rx,%rax     #Store x into %rax
mulq %y           #multiplies %y to %rax
#mulq stores high and low values into rax and rdx.
movq %rax,(%r8)   #Move low into &lower
movq %rdx,(%r9)   #Move high answer into &higher

نظرًا لأنك تستخدم الإصدار x86، فإنك تحتاج إلى 4 تعليمات أساسية.قم بتقسيم كميات 64 بت إلى كلمتين 32 بت وضرب الكلمات المنخفضة في الكلمة الأدنى والثانية من النتيجة، ثم كلا الزوجين من الكلمات المنخفضة والعالية من أرقام مختلفة (يذهبان إلى الكلمة الثانية والثالثة الأدنى من النتيجة) و أخيرًا، تم تحويل كلتا الكلمتين العاليتين إلى أعلى كلمتين في النتيجة.قم بإضافتها جميعًا معًا دون أن تنسى التعامل مع الحمل.لم تحدد تخطيط الذاكرة للمدخلات والمخرجات لذا من المستحيل كتابة نموذج التعليمات البرمجية.

يفترض هذا الرمز أنك تريد x86 (وليس رمز x64)، وأنك ربما تريد منتج 64 بت فقط، وأنك لا تهتم بالأرقام الفائضة أو الموقعة.(نسخة موقعة مشابهة).

MUL64_MEMORY:
     mov edi, val1high
     mov esi, val1low
     mov ecx, val2high
     mov ebx, val2low
MUL64_EDIESI_ECXEBX:
     mov eax, edi
     mul ebx
     xch eax, ebx  ; partial product top 32 bits
     mul esi
     xch esi, eax ; partial product lower 32 bits
     add ebx, edx
     mul ecx
     add ebx, eax  ; final upper 32 bits
; answer here in EBX:ESI

هذا لا يحترم قيود التسجيل الدقيقة لـ OP، ولكن النتيجة تتناسب تمامًا مع السجلات التي يوفرها x86.(لم يتم اختبار هذا الرمز، ولكن أعتقد أنه صحيح).

[ملحوظة:لقد قمت بنقل (إجابتي) هذه الإجابة من سؤال آخر تم إغلاقه، لأنه لم يجيب أي من "الإجابات" الأخرى هنا بشكل مباشر على السؤال].

ذلك يعتمد على اللغة التي تستخدمها.مما أتذكره من تعلم تجميع MIPS، هناك أمر Move From High وأمر Move From Lo، أو mflo وmfhi.يقوم mfhi بتخزين أعلى 64 بت بينما يقوم mflo بتخزين 64 بت الأقل من العدد الإجمالي.

آه الجمعية، لقد كان لحظة منذ أن استخدمته.لذلك أفترض أن المشكلة الحقيقية هنا هي أن وحدة التحكم الدقيقة (ما استخدمته لكتابة التعليمات البرمجية في التجميع على أي حال) الذي تعمل عليه لا تحتوي على سجلات 64 بت؟إذا كان الأمر كذلك، فسوف تقوم بفصل الأرقام التي تتعامل معها عن بعضها البعض وإجراء عمليات ضرب متعددة للقطع.

يبدو هذا وكأنه واجب منزلي من الطريقة التي صيغت بها، لذلك لن أشرحه أكثر من ذلك بكثير:P

ما عليك سوى إجراء الضرب الطويل العادي، كما لو كنت تضرب زوجًا من الأرقام المكونة من رقمين، باستثناء أن كل "رقم" هو في الواقع عدد صحيح مكون من 32 بت.إذا كنت تقوم بضرب رقمين في العنوانين X وY وتخزين النتيجة في Z، فإن ما تريد القيام به (بالكود الزائف) هو:

Z[0..3] = X[0..3] * Y[0..3]
Z[4..7] = X[0..3] * Y[4..7] + X[4..7] * Y[0..3]

لاحظ أننا نتجاهل الـ 64 بت العليا من النتيجة (نظرًا لأن رقم 64 بت مضروبًا في رقم 64 بت هو رقم 128 بت).لاحظ أيضًا أن هذا يفترض القليل من endian.كن حذرًا أيضًا بشأن الضرب الموقع مقابل الضرب غير الموقع.

ابحث عن مترجم C يدعم 64 بت (GCC يفعل IIRC) وقم بتجميع برنامج يقوم بذلك، ثم احصل على التفكيك.يمكن لـGC بصقها من تلقاء نفسها ويمكنك إخراجها من ملف الكائن باستخدام الأدوات المناسبة.

OTOH هم 32bX32b = 64b المرجع على x86

a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d;  e += x;
x:y = b*c;  e += x;

كل شيء آخر يفيض

(غير مجرب)

يحرر غير موقعة فقط

أراهن أنك طالب، لذا انظر إذا كان بإمكانك تنفيذ هذا:افعل ذلك كلمةً بكلمة، واستخدم التحولات البتية.فكر في الحل الأكثر فعالية.احذر من علامة التوقيع.

إذا كنت تريد وضع 128 جرب هذا ...

__uint128_t AES::XMULTX(__uint128_t TA,__uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __XRBX,__XRCX,__XRSI,__XRDI;
    __uint128_t RESULT;

    KEY.WHOLE=TA;
    __XRSI=KEY.SPLIT.LWORDS[0];
    __XRDI=KEY.SPLIT.LWORDS[1];
    KEY.WHOLE=TB;
    __XRBX=KEY.SPLIT.LWORDS[0];
    __XRCX=KEY.SPLIT.LWORDS[1];
    __asm__ __volatile__(
                 "movq          %0,             %%rsi           \n\t"       
                 "movq          %1,             %%rdi           \n\t"
                 "movq          %2,             %%rbx           \n\t"
                 "movq          %3,             %%rcx           \n\t"
                 "movq          %%rdi,          %%rax           \n\t"
                 "mulq          %%rbx                           \n\t"
                 "xchgq         %%rbx,          %%rax           \n\t"
                 "mulq          %%rsi                           \n\t"
                 "xchgq         %%rax,          %%rsi           \n\t"
                 "addq          %%rdx,          %%rbx           \n\t"
                 "mulq          %%rcx                           \n\t"
                 "addq          %%rax,          %%rbx           \n\t"
                 "movq          %%rsi,          %0              \n\t"
                 "movq          %%rbx,          %1              \n\t"
                 : "=m" (__XRSI), "=m" (__XRBX)
                 : "m" (__XRSI),  "m" (__XRDI), "m" (__XRBX), "m" (__XRCX)
                 : "rax","rbx","rcx","rdx","rsi","rdi"
                 );
    KEY.SPLIT.LWORDS[0]=__XRSI;
    KEY.SPLIT.LWORDS[1]=__XRBX;
    RESULT=KEY.WHOLE;
    return RESULT;
}

إذا كنت تريد ضرب 128 بت، فيجب أن يعمل هذا بتنسيق AT&T.

__uint128_t FASTMUL128(const __uint128_t TA,const __uint128_t TB)
{
    union
    {
        __uint128_t WHOLE;
        struct
        {
            unsigned long long int LWORDS[2];
        } SPLIT;
    } KEY;
    register unsigned long long int __RAX,__RDX,__RSI,__RDI;
    __uint128_t RESULT;

KEY.WHOLE=TA;
__RAX=KEY.SPLIT.LWORDS[0];
__RDX=KEY.SPLIT.LWORDS[1];
KEY.WHOLE=TB;
__RSI=KEY.SPLIT.LWORDS[0];
__RDI=KEY.SPLIT.LWORDS[1];
__asm__ __volatile__(
    "movq           %0,                             %%rax                   \n\t"
    "movq           %1,                             %%rdx                   \n\t"
    "movq           %2,                             %%rsi                   \n\t"
    "movq           %3,                             %%rdi                   \n\t"
    "movq           %%rsi,                          %%rbx                   \n\t"
    "movq           %%rdi,                          %%rcx                   \n\t"
    "movq           %%rax,                          %%rsi                   \n\t"
    "movq           %%rdx,                          %%rdi                   \n\t"
    "xorq           %%rax,                          %%rax                   \n\t"
    "xorq           %%rdx,                          %%rdx                   \n\t"
    "movq           %%rdi,                          %%rax                   \n\t"
    "mulq           %%rbx                                                   \n\t"
    "xchgq          %%rbx,                          %%rax                   \n\t"
    "mulq           %%rsi                                                   \n\t"
    "xchgq          %%rax,                          %%rsi                   \n\t"
    "addq           %%rdx,                          %%rbx                   \n\t"
    "mulq           %%rcx                                                   \n\t"
    "addq           %%rax,                          %%rbx                   \n\t"
    "movq           %%rsi,                          %%rax                   \n\t"
    "movq           %%rbx,                          %%rdx                   \n\t"
    "movq           %%rax,                          %0                      \n\t"
    "movq           %%rdx,                          %1                      \n\t"
    "movq           %%rsi,                          %2                      \n\t"
    "movq           %%rdi,                          %3                      \n\t"
    : "=m"(__RAX),"=m"(__RDX),"=m"(__RSI),"=m"(__RDI)
    :  "m"(__RAX), "m"(__RDX), "m"(__RSI), "m"(__RDI)
    : "rax","rbx","ecx","rdx","rsi","rdi"
);
KEY.SPLIT.LWORDS[0]=__RAX;
KEY.SPLIT.LWORDS[1]=__RDX;
RESULT=KEY.WHOLE;
return RESULT;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top