Маркировка Delphi и 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, * часть.

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


Сделанный отчетом об ошибках на Центральном Качестве.

5
задан PhiS 17 August 2011 в 08:34
поделиться

2 ответа

Практический совет: не используйте ключевое слово label в asm-коде, используйте @@-prefixed labels:

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. :)

.
7
ответ дан 14 December 2019 в 04:35
поделиться

Ну ... тогда в Руководстве по Delphi что-то говорилось об оптимизации компилятора и подобном безумии:


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

Автоматически сгенерированный код инициализации и финализации для подпрограмм включает:

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 - размер параметров. Если и Locals, и Params равны Null, код инициализации не будет сгенерирован, а код финализации содержит только RET-Intruction.


Может быть, это как-то связано со всем этим ...

1
ответ дан 14 December 2019 в 04:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: