Forum > Beginners

intel assembly code

(1/2) > >>

tormods:
I have made the following function in assembly located in a separate unit (not an object). By debugging this code everything works fine until it reaches the first ret-instruction where it ends up with an exception with text: External: SIGSEGV. One other thing is when looking at the produced code the final ret instruction seems to be missing. This code is taken directly from one of my Delphi projects, where this code works fine. I belive that Delphi will substitute the END with a ret instruction automatically. Has this something to do with establishing the routine in a separate unit and the compiler can not generate the correct return address?

function __SkrUtilCheckInRange(Low,High,Val : integer) : boolean; assembler;

      asm
        cmp ecx,edx         // check if Val > High
        ja @@1              // return with FALSE
        cmp ecx, eax        // check if Val < Low
        jb @@1              // return with FALSE
        mov eax, 1          // return with TRUE
        ret
  @@1:  xor eax, eax
      end;                                           

Tormods

Tomas Hajny:
Which compiler version and which options have you used for compiling this code? Can you post the generated assembly? It works in a simple test here performed with FPC 2.6.4 and using -Mdelphi (it wouldn't work correctly without -Mdelphi due to different size of "integer", because the code assumes 32-bit integers, but even then it shouldn't cause SIGSEGV, of course).

Laksen:
Did you compile it for x86_64 by chance?

I just  compiled it for i386-win32 and it worked just fine

Edit: Crashes once in a while when the inline ret is there. Strange... I suppose it's related to the debugger and stack frame.

But anyway. There's no reason to have inline assembler in this day and age :)
This code is almost twice as fast as the assembler version:

--- Code: ---function __SkrUtilCheckInRange2(Low,High,Val : longword) : boolean;
      begin
         result := longword(val-low)<=longword(high-low);
      end;

--- End code ---

ChrisF:
Using these assumptions will provoke a crash, indeed:

--- Code: ---{$mode objfpc}{$H+}
{$asmmode intel}

--- End code ---

While using the '{$mode delphi}' compatible mode seems to solve the problem.

Or you can remove the 'ret' instruction.

--- Code: ---function __SkrUtilCheckInRange(Low,High,Val : integer) : boolean; assembler;
  asm
          cmp ecx,edx         // check if Val > High
          ja @@1              // return with FALSE
          cmp ecx, eax        // check if Val < Low
          jb @@1              // return with FALSE
          mov eax, 1          // return with TRUE
          jmp @@2
    @@1:  xor eax, eax
    @@2:
  end;

--- End code ---


Anyway, and according to my own experience, using previous Delphi assembly code inside FPC can rapidly turn into a nightmare (even in Delphi mode).

See this one, for instance: http://bugs.freepascal.org/view.php?id=24061, especially Jonas Maebe's answer.

tormods:
I have tried to check out the code the compiler produces, and found the cause why the code crashes:

New functioning code:

function __SkrUtilCheckInRange(Low,High,Val : integer) : boolean; assembler;

      asm
        cmp ecx,edx         // check if Val > High
        ja @@1              // return with FALSE
        cmp ecx, eax        // check if Val < Low
        jb @@1              // return with FALSE
        mov eax, 1          // return with TRUE
        leave
        ret
  @@1:  xor eax, eax
      end;                 

The compiler produces the following code:

00552240 55                        push   ebp
00552241 89e5                     mov    ebp,esp
00552243 83ec04                  sub    esp,0x4
00552246 39d1                     cmp    ecx,edx
00552248 770b                     ja     0x552255 <__SKRUTILCHECKINRANGE+21>
0055224A 39c1                     cmp    ecx,eax
0055224C 7207                     jb     0x552255 <__SKRUTILCHECKINRANGE+21>
0055224E b801000000          mov    eax,0x1
00552253 c9                         leave
00552254 c3                         ret 
00552255 31c0                     xor    eax,eax
00552257 c9                         leave 
00552258 c3                         ret   


Since the compiler produces the additional code:

push   ebp
mov    ebp,esp
sub    esp,0x4 

it needs to restore the esp and get back the epb and that is what the leave instruction does - analog code is :
mov esp, ebp
pop ebp

Why is this additional code added? it seems uneccessary. If an additional begin-end is used it produces a longer code:

skrutilities.pas:37               begin
00552240 55                       push   ebp
00552241 89e5                    mov    ebp,esp
00552243 83ec10                 sub    esp,0x10
00552246 8945fc                 mov    DWORD PTR [ebp-0x4],eax
00552249 8955f8                mov    DWORD PTR [ebp-0x8],edx
0055224C 894df4                mov    DWORD PTR [ebp-0xc],ecx
0055224F 39d1                   cmp    ecx,edx 
00552251 770b                   ja     0x55225e <__SKRUTILCHECKINRANGE+30>
00552253 39c1                   cmp    ecx,eax
00552255 7207                   jb     0x55225e <__SKRUTILCHECKINRANGE+30>
00552257 b801000000        mov    eax,0x1
0055225C c9                       leave
0055225D c3                       ret 
0055225E 31c0                    xor    eax,eax
00552260 c9                       leave 
00552261 c3                       ret   

I tried to use delphi mode, this did not change the result.
I personally try to make effective assembly code and as such adding unecessary code is not a good idea.

By the way: it is possible to set the assmbly window in debugger to Intel notation rather than the A&T notation!

Tormods


Navigation

[0] Message Index

[#] Next page

Go to full version