2010-03-07 8 views
5

ich eine asm-Funktion in Delphi 7 geschrieben, aber es verwandelt sich der Code etwas anderes:Delphi Label und Asm Seltsamkeit?

function f(x: Cardinal): Cardinal; register; 
label err; 
asm 
    not eax 
    mov edx,eax 
    shr edx, 1 
    and eax, edx 
    bsf ecx, eax 
    jz err 
    mov eax, 1 
    shl eax, cl 
    mov edx, eax 
    add edx, edx 
    or eax, edx 
    ret 
    err: 
    xor eax, eax 
end; 

// compiled version 
f: 
    push ebx  // !!! 
    not eax 
    mov edx,eax 
    shr edx, 1 
    and eax, edx 
    bsf ecx, eax 
    jz +$0e 
    mov eax, 1 
    shl eax, cl 
    mov edx, eax 
    add edx, edx 
    or eax, edx 
    ret 
    err: 
    xor eax, eax 
    mov eax, ebx // !!! 
    pop ebx  // !!! 
    ret 

// the almost equivalent without asm 
function f(x: Cardinal): Cardinal; 
var 
    c: Cardinal; 
begin 
    x := not x; 
    x := x and x shr 1; 
    if x <> 0 then 
    begin 
    c := bsf(x); // bitscanforward 
    x := 1 shl c; 
    Result := x or (x shl 1) 
    end 
    else 
    Result := 0; 
end; 

Warum es push ebx und pop ebx generiert? Und warum tut es mov eax, ebx?

Es scheint, dass es den Teilstapelrahmen wegen der mov eax, ebx erzeugt.

Dieser einfache Test erzeugt mov eax, edx aber erzeugt nicht, dass der Stapelrahmen:

function asmtest(x: Cardinal): Cardinal; register; 
label err; 
asm 
    not eax 
    and eax, 1 
    jz err 
    ret 
    err: 
    xor eax, eax 
end; 

// compiled 
asmtest: 
    not eax 
    and eax, $01 
    jz +$01 
    ret 
    xor eax, eax 
    mov eax, edx // !!! 
    ret 

Es scheint, dass es etwas mit den label err zu tun hat. Wenn ich das entferne, bekomme ich den mov eax, * Teil nicht.

Warum passiert das?


Einen Fehlerbericht auf Quality Central gemacht.

+0

Bitte melden Sie dies als einen Fehler bei http://qc.embarcadero.com/wc/qcmain.aspx –

+0

@Jeroen sicher bekam. .. no prob ... – Egon

+0

Sie haben hier einige "Warum" -Fragen gestellt, aber keine davon wurde mit Ihrer Antwort beantwortet. Es sieht so aus, als wolltest du wirklich nur wissen, wie man zu einer neuen Anweisung in Delphi Assembler springt, ohne Rücksicht darauf, warum deine eigenen Versuche gescheitert sind. Ist das genau? –

Antwort

7

Die praktischen Ratschläge: nicht Etikett Stichwort in asm-Code verwenden, verwenden Sie @@ - Präfix Etikett:

function f(x: Cardinal): Cardinal; register; 
asm 
    not eax 
    mov edx,eax 
    shr edx, 1 
    and eax, edx 
    bsf ecx, eax 
    jz @@err 
    mov eax, 1 
    shl eax, cl 
    mov edx, eax 
    add edx, edx 
    or eax, edx 
    ret 
@@err: 
    xor eax, eax 
end; 

Aktualisiert:

Ich habe nicht den Bug-Report gefunden in Basm area. Es sieht wie ein Bug aus, aber ich benutze BASM seit vielen Jahren und habe nie darüber nachgedacht, ein Label-Keyword zu verwenden. Tatsächlich habe ich in Delphi überhaupt kein Label-Schlüsselwort verwendet. :)

+0

Wow, das behebt es ... –

+0

Irgendeine Idee, warum 'Label' das' mov eax erzeugt, * 'dingy ... Ist es ein Fehler? Oder nur ein seltsames Verhalten? – Egon

+0

Anstelle von @@ MyLabel ist auch @MyLabel (mit einem einzigen "@") in asm..end blocks in Ordnung. – PhiS

1

Nun ... damals in der Delphi-Handbuch, es verwendet, um etwas über Compiler-Optimierung zu sagen und thealike-Verrücktheit:


Der Compiler Stackframes für verschachtelte Routinen nur erzeugt, für lokale Variablen Routinen mit und für Routinen mit Stapel-Parameter

Die automatisch generierten Initialization- und Finalizationcode für Routinen enthält:

PUSH EBP    ; If Locals <> 0 or Params <> 0 
MOV  EBP,ESP   ; If Locals <> 0 or Params <> 0 
SUB  ESP,Locals  ; If Locals <> 0 
    ... 
MOV  ESP,EBP   ; If Locals <> 0 
POP  EBP    ; If Locals <> 0 or Params <> 0 
RET  Params   ; Always 

Wenn lokale Variablen Varianten, lange Zeichenfolgen oder Schnittstellen enthalten, werden sie mit Null initialisiert, aber danach nicht finalisiert.

Lokal ist die Größe der lokalen Variablen, Parameter die Größe der Parameter. Wenn sowohl Locals als auch Params Null sind wird kein Init-Code erzeugt und der Finalization Code enthält nur einen RET-Befehl.


Vielleicht, die mit ihm etwas zu tun, alle ...