Delphi Label и ASM странность?
Вопрос
Я написал функцию ASM в Delphi 7, но это преобразует мой код на что-то еще:
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, *
часть.
Почему это происходит?
Сделал сообщение об ошибке на Качество центральное.
Решение
Практический совет: не используйте ключевое слово метки в коде ASM, используйте @@ - префиксные этикетки:
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;
Обновленный:
Я не нашел отчет об ошибках в Басменская область. Отказ Это похоже на ошибку, но я уже много лет использовал басмен и никогда не думал использовать такое ключевое слово этикетки. На самом деле я никогда не использовал ключевое слово Label в Delphi. :)
Другие советы
Ну ... Вернитесь тогда, в Delphi-Manual, он использовал что-то о компиляторе-оптимизации и Thealike-Crazyness:
Компилятор генерирует штаб-кадры только для вложенных процедур, для процедур, имеющих локальные переменные и для подпрограмм со стеком-параметрами.
Автоматическая сгенерированная инициализация и финаризацияCode для процедуры включает в себя:
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 - это размер локальных переменных, параметры размером параметров. Если оба местных жителя, а также на словах NULL не будут сгенерированы INIT-код, и финарирующий код содержит только вторжение.
Может быть, что есть что-то делать с ним все ...