2010-03-07 5 views
5

Я написал функцию ассемблера в Delphi 7, но он преобразует свой код на что-то другое:Маркировка Delphi и странность?

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; 

Почему это генерировать push ebx и pop ebx? И почему он делает mov eax, ebx?

Кажется, что он генерирует частичный стек кадров из-за mov eax, ebx.

Этот простой тест генерирует mov eax, edx, но не генерирует этот кадр стека:

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 

Кажется, что у него есть что-то делать с label err. Если я удалю, я не получу часть mov eax, *.

Почему это происходит?


Сообщить об ошибке Quality Central.

+0

пожалуйста, сообщите об этом как об ошибке в http://qc.embarcadero.com/wc/qcmain.aspx –

+0

@Jeroen уверен. . no prob ... – Egon

+0

Вы задали несколько вопросов «почему», но ни один из них не ответил на ответ, который вы приняли. Похоже, вы просто хотели узнать, как перейти к новой инструкции в ассемблере Delphi, не учитывая, почему ваши собственные попытки не удались. Это точно? –

ответ

7

Практический совет: не используйте метки ключевое слово в ассемблерный код, используйте @@ - приставочные метки:

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; 

Обновлено:

Я не нашел отчет об ошибке в Basm area. Это похоже на ошибку, но я использовал BASM уже много лет и никогда не думал об использовании ключевого слова label таким образом. На самом деле я никогда не использовал ключевое слово label в Delphi вообще. :)

+0

Ничего себе, это исправляет это ... –

+0

Любая идея, почему 'label' генерирует это' mov eax, * 'thingy ... Это ошибка? Или просто какое-то странное поведение? – Egon

+0

Вместо @@ MyLabel, также @MyLabel (с одним «@») отлично подходит для блоков asm..end. – PhiS

1

Ну ... тогда, в Delphi-Manual, он говорил что-то о Compiler-оптимизации и thealike-crazyness:


Компилятор генерирует Stackframes только для вложенных подпрограмм, для Подпрограммы, имеющие локальные переменные и для Подпрограммы с стеком параметрами

автоматически сгенерированное Initialization- и Finalizationcode для Подпрограммы включает в себя:

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 

Если локальные переменные содержат варианты, длинные строки или интерфейсы, они инициализируются с помощью Null, но не завершаются впоследствии.

Местные жители - это размер локальных переменных, Параметр Размер параметров. Если и Locals, и Params - Null no Init-Code будут сгенерированы, а код Finalization будет содержать только RET-Intruction.


Может быть, что получил что-то делать со всем этим ...