flat assembler
Message board for the users of flat assembler.

Index > Windows > Managed code

Thread Post new topic Reply to topic

Joined: 06 Jul 2009
Posts: 18
Bicyclist 08 Jul 2009, 21:42
I found some material that may be helpful in fixing some 32 bit code to run on a 64-Bit system.

Here is some code that may need to be changed followed by some info that may offer a way have it run safely.

There is a lot that I don't understand.

Do you think this material offers a way to change my code to run on a 64-Bit system?

Thanks or any help.

FShell_explodeOS PROC hb:DWORD
    mov edi,hb
    add edi,SPARC
    mov eax,nd
    dec eax
    shl eax,4
    fld dword ptr[edi+eax]     ; x coordinate
    fadd dword ptr[edi+eax+4]  ; x velocity
    fstp dword ptr[edi+eax]
    fld dword ptr[edi+eax+8]   ; y coordinate
    fadd dword ptr[edi+eax+12] ; y velocity
    fstp dword ptr[edi+eax+8]
    sub eax,16
    jnc @B
    dec dword ptr[edi-SPARC]
    mov eax,[edi-SPARC]        ; return(--life)
FShell_explodeOS ENDP    

In order to discuss the potential issues with unsafe code let's explore the following example. Our managed code makes calls to an unmanaged DLL. In

particular, there is a method called GetDataBuffer that returns 100 items (for this example we are returning a fixed number of items). Each of these items

consists of an integer and a pointer. The sample code below is an excerpt from the managed code showing the unsafe function responsible for handling this

returned data.

public unsafe int UnsafeFn() {
   IntPtr * inputBuffer = sampleDLL.GetDataBuffer();
   IntPtr * ptr = inputBuffer;
   int   result = 0;

   for ( int idx = 0; idx < 100; idx ++ ) {
      // Add 'int' from DLL to our result
      result = result + ((int) *ptr);

// Increment pointer over int (
      ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );

      // Increment pointer over pointer (
      ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );
   return result;

Note This particular example could have been accomplished without the use of unsafe code. More specifically, there are other techniques such as

marshaling that could have been used. But for this purpose we are using unsafe code.

The UnsafeFn loops through the 100 items and sums the integer data. As we are walking through a buffer of data, the code needs to step over both the integer

and the pointer. In the 32-bit environment this code works fine. However, as we've previously discussed, pointers are 8 bytes in the 64-bit environment and

therefore the code segment (shown below) will not work correctly, as it is making use of a common programming technique, e.g., treating a pointer as

equivalent to an integer.

// Increment pointer over pointer (
ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );    

In order for this code to work in both the 32-bit and 64-bit environment it would be necessary to alter the code to the following.

// Increment pointer over pointer (
ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( IntPtr ) );    

As we've just seen, there are instances where using unsafe code is necessary. In most cases it is required as a result of the managed code's dependency on

some other interface. Regardless of the reasons unsafe code exists, it has to be reviewed as part of the migration process.

The example we used above is relatively simple and the fix to make the program work in 64-bit was straightforward. Clearly there are many examples of unsafe

code that are more complex. Some will require deep review and perhaps stepping back and rethinking the approach the managed code is using.

moderator edit: added [ code ] tags to improve readbility. Please use code-tags for blocks of code.
Post 08 Jul 2009, 21:42
View user's profile Send private message Reply with quote

Joined: 21 Jul 2003
Posts: 3977
Location: vpcmipstrm
bitRAKE 08 Jul 2009, 23:23
Bah, re-factor the whole thing!:
struc SHELL {
      .life   rd 1
        .air    rd 1
        .0      rd 1 ; ?
    .1      rd 1 ; ?
    .. = $ - .
struc SPARK {
      .x      rd 1
        .dx     rd 1
        .x      rd 1
        .dx     rd 1
        .. = $ - .

   .hb equ rcx

     virtual at .hb
              .sh SHELL
   end virtual

     mov eax,[nd]
        dec eax
     shl eax,4 ; why divide sparks per shell by 16?

  ; bypass SHELL data for SPARK array
 lea rdi,[.hb+.sh..]
      virtual at rdi+rax
          .sp SPARK
   end virtual

     fld [.sp.x]
 fadd [.sp.dx]
       fstp [.sp.x]

    fld [.sp.y]
 fadd [.sp.dy]
       fstp [.sp.y]

    sub eax,.sp..
       jnc @B

  ; return(--life)
    dec [.sh.life]
      mov eax,[.sh.life]
...simply easier to read, easier to make changes, etc...

Migration to x64 means rewrite.
(Because shell and spark structures are the same size the loop can run the index from n to 1 -- rather than the current (n-1) to 0. Which results in three unneeded instructions.)
Post 08 Jul 2009, 23:23
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum

Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.