At least without optimization enabled, your function has a pre-amble and a post-amble. Have a look at it:
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
So the pre-amble sets up the stack frame. It saves away the ebp register, and modifies both the ebp and esp registers. Notice also the post-amble. You do need to execute that code to restore the saved registers.
The usual way to deal with this is to jump to the end of the function instead of using ret. So write your code like this:
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;
This way you ensure that the post-amble is executed. You really should get into the habit of writing the code this way to ensure that any pre-amble is executed.
Now, beyond that I suspect that the problem you mention in the question actually relates to a compiler bug relating to your use of a Pascal label rather than an asm label. Well, perhaps it is a compiler bug, but perhaps it is just a mistake to use a Pascal label. Consider the following program:
{$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.
The output when compiled with optimization is:
-1
0
-1
4
So, what about that rather odd 4. Well, let's look at the assembled code for Msb2, which is essentially your code:
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
Why on earth is the value of edx, a volatile register whose value has not been assigned, being moved into eax just before the function returns. This is the problem that you are reporting. My guess is that the use of a Pascal label is confusing the assembler. Stick to asm labels.
Here is the assembled code for 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
That's more like it! Notice how the compiler knows that there is no post-able here, and replaces the jmp @@exit with a straight ret.