По крайней мере, без включенной оптимизации у вашей функции есть преамбула и постамбула. Посмотри на это:
Project46.dpr.13: asm
0041A1F4 55 push ebp
0041A1F5 8BEC mov ebp,esp
0041A1F7 83C4F8 add esp,-$08
0041A1FA 8945F8 mov [ebp-$08],eax
Project46.dpr.14: CMP EAX, 0
0041A1FD 83F800 cmp eax,$00
Project46.dpr.15: JNZ Go
0041A200 7506 jnz $0041a208
Project46.dpr.16: MOV EAX, -1
0041A202 B8FFFFFFFF mov eax,$ffffffff
Project46.dpr.17: RET
0041A207 C3 ret
Project46.dpr.19: BSR EBX, EAX
0041A208 0FBDD8 bsr ebx,eax
Project46.dpr.20: MOV EAX, EBX
0041A20B 89D8 mov eax,ebx
Project46.dpr.21: RET
0041A20D C3 ret
Project46.dpr.22: end;
0041A20E 8B45FC mov eax,[ebp-$04]
0041A211 59 pop ecx
0041A212 59 pop ecx
0041A213 5D pop ebp
0041A214 C3 ret
Таким образом, преамбула устанавливает фрейм стека. Он сохраняет регистр ebp
и изменяет регистры ebp
и esp
. Обратите внимание также на постамбулу. Вам нужно выполнить этот код, чтобы восстановить сохраненные регистры.
Обычный способ справиться с этим — перейти в конец функции вместо использования ret
. Итак, напишите свой код следующим образом:
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@go
MOV EAX, -1
JMP @@exit
@@go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
Таким образом, вы гарантируете, что post-amble будет выполнен. Вы действительно должны привыкнуть писать код таким образом, чтобы гарантировать выполнение любой преамбулы.
Теперь, помимо этого, я подозреваю, что проблема, о которой вы упоминаете в вопросе, на самом деле связана с ошибкой компилятора, связанной с использованием вами метки Pascal, а не метки asm. Что ж, возможно, это ошибка компилятора, но, возможно, это просто ошибка использования метки Pascal. Рассмотрим следующую программу:
{$APPTYPE CONSOLE}
function MSb(const Val: Integer): Integer;
asm
CMP EAX, 0
JNZ @@Go
MOV EAX, -1
JMP @@exit
@@Go:
BSR EBX, EAX
MOV EAX, EBX
@@exit:
end;
function MSb2(const Val: Integer): Integer;
label
Go;
asm
CMP EAX, 0
JNZ Go
MOV EAX, -1
RET
Go:
BSR EBX, EAX
MOV EAX, EBX
end;
begin
Writeln(Msb(0));
Writeln(Msb(1));
Writeln(Msb2(0));
Writeln(Msb2(1));
Readln;
end.
Вывод при компиляции с оптимизацией:
-1
0
-1
4
Итак, как насчет этого довольно странного 4
. Что ж, давайте посмотрим на собранный код для Msb2
, который по сути является вашим кодом:
004059E8 83F800 cmp eax,$00
004059EB 7506 jnz $004059f3
004059ED B8FFFFFFFF mov eax,$ffffffff
004059F2 C3 ret
004059F3 0FBDD8 bsr ebx,eax
004059F6 89D8 mov eax,ebx
004059F8 8BC2 mov eax,edx
004059FA C3 ret
С какой стати значение edx
, изменчивого регистра, значение которого не было присвоено, перемещается в eax
непосредственно перед возвратом из функции. Это проблема, о которой вы сообщаете. Я предполагаю, что использование метки Pascal сбивает с толку ассемблер. Придерживайтесь ассемблерных этикеток.
Вот собранный код для Msb
:
004059D4 83F800 cmp eax,$00
004059D7 7506 jnz $004059df
004059D9 B8FFFFFFFF mov eax,$ffffffff
004059DE C3 ret
004059DF 0FBDD8 bsr ebx,eax
004059E2 89D8 mov eax,ebx
004059E4 C3 ret
Это больше походит на это! Обратите внимание, как компилятор знает, что здесь нет возможности публикации, и заменяет jmp @@exit
прямым ret
.
person
David Heffernan
schedule
25.11.2014