Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Division großer Zahlen in Assembler - Hilfe beim Verständnis (https://www.delphipraxis.net/32895-division-grosser-zahlen-assembler-hilfe-beim-verstaendnis.html)

AlphaBug 29. Okt 2004 11:38


Division großer Zahlen in Assembler - Hilfe beim Verständnis
 
Hi :hi:

Kann man mir bitte mal Teile des nachfolgenden Assembler-Code (auch gerne den Ganzen) aus der System.pas erklären ?

Es ist ja soweit ersichtlich, dass dort eine Division zweier 64-Bit-Integer durchgeführt wird, aber ich verstehe den Sinn einiger Befehlsfolgen nicht.
Ich habe zwar eine komplette Referenz aller (Intel-)Assembler-Befehle mit Erklärungen, an deren Verständnis es nicht hakt, aber Ich bin kein Assembler-Profi und kein Mathematik-Spezi. :angel2:
Die Prozedur "__lldiv" ist ja eine Software-Umsetzung für Divisionen von 64-Bit-Integern auf 32-Bit-CPUs. Demnach müsste sie sich ja auf größere Zahlen erweitern lassen. Natürlich müssten die Zahlen dann in einem Array gespeichert werden (imho), z.B. einem array [0..3] of DWORD für 128-Bit-Zahlen.

Also bei mir hapert es jetzt an drei Stellen:
1. am Verständnis einiger Assembler-Befehle
2. am Verständnis einiger Assembler-Befehlsfolgen
3. an der Erweiterung auf größere Zahlen in Array-Form

Ich suche also nach einer allgemeinen Erklärung des Ablaufs dieser Prozedur,
und, wenn dann noch nötig, nach Hilfe für eine Erweiterung.
Ich suche NICHT nach einer Bibliothek, die mir das Lernen abnimmt.
Ich hoffe, man kann mir weiterhelfen:

1.:
Was sagt mit diese Zeile:
Delphi-Quellcode:
        mov    ebx,20[esp]
Ich kenne nur solche Befehle:
Delphi-Quellcode:
        mov    ebp,ecx
        mov    ecx,64
2:
Warum werden hier die Register edx, esi und edi um 1 über das Carry hinweg rotiert:
Delphi-Quellcode:
@__lldiv@xloop:
        shl    eax,1
        rcl    edx,1
        rcl    esi,1
        rcl    edi,1
Das waren wahrscheinlich nur die ersten Fragen...

Delphi-Quellcode:
// ------------------------------------------------------------------------------
//  64-bit signed division
// ------------------------------------------------------------------------------

//
//  Dividend = Numerator, Divisor = Denominator
//
//  Dividend(EAX:EDX), Divisor([ESP+8]:[ESP+4]) ; before reg pushing
//
//

procedure __lldiv;
asm
        push   ebp
        push   ebx
        push   esi
        push   edi
        xor    edi,edi

        mov    ebx,20[esp]            // get the divisor low dword
        mov    ecx,24[esp]            // get the divisor high dword

        or     ecx,ecx
        jnz    @__lldiv@slow_ldiv     // both high words are zero

        or     edx,edx
        jz     @__lldiv@quick_ldiv

        or     ebx,ebx
        jz     @__lldiv@quick_ldiv    // if ecx:ebx == 0 force a zero divide
        // we don't expect this to actually
        // work

@__lldiv@slow_ldiv:
//               Signed division should be done. Convert negative
//               values to positive and do an unsigned division.
//               Store the sign value in the next higher bit of
//               di (test mask of 4). Thus when we are done, testing
//               that bit will determine the sign of the result.
        or     edx,edx                // test sign of dividend
        jns    @__lldiv@onepos
        neg    edx
        neg    eax
        sbb    edx,0                   // negate dividend
        or     edi,1

@__lldiv@onepos:
        or     ecx,ecx                // test sign of divisor
        jns    @__lldiv@positive
        neg    ecx
        neg    ebx
        sbb    ecx,0                   // negate divisor
        xor edi,1

@__lldiv@positive:
        mov    ebp,ecx
        mov    ecx,64                  // shift counter
        push   edi                    // save the flags
//
//       Now the stack looks something like this:
//
//               24[esp]: divisor (high dword)
//               20[esp]: divisor (low dword)
//               16[esp]: return EIP
//               12[esp]: previous EBP
//                8[esp]: previous EBX
//                4[esp]: previous ESI
//                 [esp]: previous EDI
//
        xor    edi,edi                // fake a 64 bit dividend
        xor    esi,esi

@__lldiv@xloop:
        shl    eax,1                   // shift dividend left one bit
        rcl    edx,1
        rcl    esi,1
        rcl    edi,1
        cmp    edi,ebp                // dividend larger?
        jb     @__lldiv@nosub
        ja     @__lldiv@subtract
        cmp    esi,ebx                // maybe
        jb     @__lldiv@nosub

@__lldiv@subtract:
        sub    esi,ebx
        sbb    edi,ebp                // subtract the divisor
        inc    eax                    // build quotient

@__lldiv@nosub:
        loop   @__lldiv@xloop
//
//       When done with the loop the four registers values' look like:
//
//       |     edi   |    esi    |    edx    |    eax    |
//       |        remainder       |         quotient       |
//
        pop    ebx                    // get control bits
        test   ebx,1                   // needs negative
        jz     @__lldiv@finish
        neg    edx
        neg    eax
        sbb    edx,0                   // negate

@__lldiv@finish:
        pop    edi
        pop    esi
        pop    ebx
        pop    ebp
        ret    8

@__lldiv@quick_ldiv:
        div    ebx                    // unsigned divide
        xor    edx,edx
        jmp    @__lldiv@finish
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz