Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / November 2005

Tip: Looking for answers? Try searching our database.

CIL, CopyMemory and Compact Framework

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Luc Vaillant - 16 Nov 2005 07:12 GMT
Hi,

I'm trying to write a method for my PocketPC that will write a Double value
to an Array buffer at the specified offset.

The constraints are :
- Must be safe managed code
- Array buffer can be of any integral type (byte, short, int, long, etc.)
- offset can be unaligned

I already wrote this method for Win32, and it works fine.

Because I knew about alignement constraint on ARM processors, I rewrote the
method doing a loop on the 8 bytes of the double value like do the
BitConverter.ToDouble method in its Compact Framewrok version

The differences between BitConverter.ToDouble and my method are:
- I'm writing a SetDouble method
- The destination buffer is an Array of any integral type (not only a Byte[])

My Compact Framework version of SetDouble works fine on the Pocket PC 2002
emulator, but throws a 0x80000002 exception on my Pocket PC device (QTEK 9090)

Here is the method code I wrote (I know that I'm accessing the Array like a
Byte array, but only for the first element in order to retreive the array's
starting address. This works fine in my Windows.Forms version):

.method public hidebysig static void
           SetDouble(class [mscorlib]System.Array buffer,
                     int32 offset,
                     float64 'value') cil managed
{
  .locals (unsigned int8* pBuffer, int32 nIndex, unsigned int8* pValue)
       
  ldarg.0
  ldc.i4.0
  ldelema        [mscorlib]System.Byte
  ldarg.1
  add
  stloc.0
       
  ldc.i4.0
  stloc.1
       
  ldarga.s        2
  stloc.2
       
LOOP:
  ldloc.0
  ldloc.1
  add

  ldloc.2
  ldloc.1
  add

  ldind.i1
  stind.i1
       
  ldloc.1
  ldc.i4.1
  add
  stloc.1
       
  ldloc.1
  ldc.i4.8
  blt.s        LOOP   
  ret
   } // end of method Buffer::SetDouble

Any suggestion ?

Thanks a lot
Luc Vaillant - 16 Nov 2005 10:42 GMT
First of all, I'm using .Net Framework v1.1 with VS.NET 2003

I have made some tests, and I realized that "ldelema [mscorlib]System.Byte"
doesn't work on my Pocket PC device if my buffer is declared as follow even
if typeof(buffer) is Byte[]:

SetDouble(class [mscorlib]System.Array buffer,...

It does work if the buffer is declared as follow:

SetDouble(unsigned int8[] buffer,...

Here is the code of my method. It works on Win32 and Compact Framwork in the
emulator, but not on my Pocket PC device

   .method public hidebysig static void
           SetDouble(class [mscorlib]System.Array buffer,
           // SetDouble(unsigned int8[] buffer,
                     int32 offset,
                     float64 'value') cil managed
   {
    .locals (int32 nIndex, unsigned int8* pValue, unsigned int8* pBuffer)
       
    ldc.i4.0            // 0
    stloc.0            // nIndex = 0
   
    ldarga.s    2        // &value
    stloc.1            // pValue = &value;
       
    ldarg.0            // buffer
    ldarg.1            // offset
    ldelema [mscorlib]System.Byte    // &buffer[offset]
    stloc.2            // pBuffer = &buffer[offset]
   
LOOP:
    ldloc.2            // pBuffer
    ldloc.0            // nIndex
    add            // pBuffer + nIndex
    ldloc.1            // pValue
    ldloc.0            // nIndex
    add            // &pValue[nIndex]
    ldind.i1            // pValue[nIndex]
    stind.i1            // pBuffer[nIndex] = pValue[nIndex]
       
    ldloc.0            // nIndex
    ldc.i4.1            // 1
    add            // nIndex++
    stloc.0            // ->nIndex
   
    ldloc.0            // nIndex
    ldc.i4.8            // 8
    blt.s    LOOP        // if (nIndex < 8) goto LOOP
   
    ret
   } // end of method Buffer::SetDouble

> Hi,
>
[quoted text clipped - 69 lines]
>
> Thanks a lot
Mattias Sjögren - 16 Nov 2005 12:32 GMT
> I'm trying to write a method for my PocketPC that will write a Double value
> to an Array buffer at the specified offset.

Any reason you're not calling System.Buffer.BlockCopy ?

Mattias
Luc Vaillant - 17 Nov 2005 05:57 GMT
The main reason is that the source or destination is not an Array

> > I'm trying to write a method for my PocketPC that will write a Double value
> > to an Array buffer at the specified offset.
>
> Any reason you're not calling System.Buffer.BlockCopy ?
>
> Mattias
Mattias Sjögren - 17 Nov 2005 19:35 GMT
>The main reason is that the source or destination is not an Array

Looks to me like the destination is an array and you said so yoruself
in your original message.

The source value isn't an array but nothing's stopping you from
putting it into a single element double[].

Mattias

Signature

Mattias Sjögren [MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Holger Grund - 16 Nov 2005 12:52 GMT
> I'm trying to write a method for my PocketPC that will write a Double
> value
> to an Array buffer at the specified offset.
>
> The constraints are :
> - Must be safe managed code
Do you mean verifiable code? Or just valid CIL?

> - Array buffer can be of any integral type (byte, short, int, long, etc.)
> - offset can be unaligned
>
> I already wrote this method for Win32, and it works fine.

> My Compact Framework version of SetDouble works fine on the Pocket PC 2002
> emulator, but throws a 0x80000002 exception on my Pocket PC device (QTEK
[quoted text clipped - 5 lines]
> array's
> starting address. This works fine in my Windows.Forms version):

Did you write that in MSIL assembler? Can you share the source?

BTW: There's also unaligned
> .method public hidebysig static void
>            SetDouble(class [mscorlib]System.Array buffer,
>                      int32 offset,
>                      float64 'value') cil managed
> {
>   .locals (unsigned int8* pBuffer, int32 nIndex, unsigned int8* pValue)

I don't think you can do anything verifiable with native pointers. And
if you really want to use them, make sure the pointee is pinned.

>   ldarg.0
>   ldc.i4.0
>   ldelema [mscorlib]System.Byte
That's probably not verifiable. You should cast to the array
type before via
ldarg.0
castclass unsigned int8[]
ldc.i4.0
ldelema unsigned int8
...

>   ldarg.1
>   add
(Managed) pointer arithmetic is not verifiable.

>   stloc.0
You store a managed pointer into a variable of native pointer
type. You should only do so if you know the memory pointed
to can't be moved by the GC.

You might want to use unaligned.1 cpblk

-hg
Luc Vaillant - 17 Nov 2005 06:46 GMT
Thank you very much for your time, here are some answers

Lvt

> Do you mean verifiable code? Or just valid CIL?
LVT : I just want not to be bored if security constraints (like only managed
code is allowed to run on this computer) are ON in .Net Framework

> Did you write that in MSIL assembler? Can you share the source?
LVT : Yes, I wrote this code in MSIL : First I wrote a small class with
empty methods, then I used ILDASM to get the MSIL of my class with methods
doing nothing, and then I wrote the missing MSIL code in my methods
Here is the code of the C# class :

using System;

namespace Memory
{
  public class Buffer
  {
     private Buffer() {}
     public static void SetDouble(Array buffer, Int32 offset, Double value)
{}
  }
}

Here is the SetDouble generated code with my MSIL:

   .method public hidebysig static void
           SetDouble(class [mscorlib]System.Array buffer,
                     int32 offset,
                     float64 'value') cil managed
   {
    .locals (int32 nIndex, unsigned int8* pValue, unsigned int8* pBuffer)
       
    ldc.i4.0            // 0
    stloc.0            // nIndex = 0
   
    ldarga.s    2        // &value
    stloc.1            // pValue = &value;
       
    ldarg.0            // buffer
    ldarg.1            // offset
    ldelema [mscorlib]System.Byte    // &buffer[offset]
    stloc.2            // pBuffer = &buffer[offset]
   
LOOP:
    ldloc.2            // pBuffer
    ldloc.0            // nIndex
    add            // pBuffer + nIndex
    ldloc.1            // pValue
    ldloc.0            // nIndex
    add            // &pValue[nIndex]
    ldind.i1            // pValue[nIndex]
    stind.i1            // pBuffer[nIndex] = pValue[nIndex]
       
    ldloc.0            // nIndex
    ldc.i4.1            // 1
    add            // nIndex++
    stloc.0            // ->nIndex
   
    ldloc.0            // nIndex
    ldc.i4.8            // 8
    blt.s    LOOP        // if (nIndex < 8) goto LOOP
   
    ret
   } // end of method Buffer::SetDouble

> BTW: There's also unaligned
LVT: Yes, alignment is a big issue on ARM, that's why I used a loop
The first version I wrote in MSIL for SetDouble was:

     IL_0000:  ldarg.0
     IL_0001:  ldc.i4.0
     IL_0002:  ldelema    [mscorlib]System.Byte
     IL_0007:  ldarg.1
     IL_0008:  add
     IL_0009:  ldarg.2
     IL_000a:  unaligned. 1
     IL_000d:  stind.r8
     IL_000e:  ret

but this code throws an exception on my Pocket PC

> I don't think you can do anything verifiable with native pointers. And
> if you really want to use them, make sure the pointee is pinned.
LVT: I don't know how to pin memory

> That's probably not verifiable. You should cast to the array
> type before via
[quoted text clipped - 3 lines]
> ldelema unsigned int8
> ....
LVT : Unfortunately, I couldn't cast the Array because I don't know its type
My first Idea was to provide a method that works on any integral type array,
but I realize that drive me to a lot of problems for 'nothing'.
I Think I will simply allow bytes array and then used Byte[] parameter type
instead of Array type.
This way I can use the ldelem.u1 just like BitConverter.ToDouble is doing in
its CF version

> (Managed) pointer arithmetic is not verifiable.
> You store a managed pointer into a variable of native pointer
> type. You should only do so if you know the memory pointed
> to can't be moved by the GC.
LVT: You're right and I will avoid pointer arithmetic with ldelem.u1

> You might want to use unaligned.1 cpblk
LVT: Idealy YES but the following code throws an InvalidProgramException:

   .method public hidebysig static void
           SetDouble(unsigned int8[] buffer,
                     int32 offset,
                     float64 'value') cil managed
   {
    ldarg.0                // buffer
    ldarg.1                // offset
    ldelema    [mscorlib]System.Byte    // &buffer[offset]
    ldarga.s    2            // &value
    ldc.i4.8                // 8
    unaligned. 1 cpblk            // CopyMemory
    ret
   } // end of method Buffer::SetDouble

> > I'm trying to write a method for my PocketPC that will write a Double
> > value
[quoted text clipped - 55 lines]
>
> -hg
Holger Grund - 17 Nov 2005 13:22 GMT
>> Do you mean verifiable code? Or just valid CIL?
> LVT : I just want not to be bored if security constraints (like only
> managed
> code is allowed to run on this computer) are ON in .Net Framework

You probably want your code to verifiable then. Almost none of the things
suggested in here will work then. Maybe there are some base library
helpers which are statically known to be safe, but I'm afraid you'll have
to stick with a less efficient method.

[snip]

>> BTW: There's also unaligned
> LVT: Yes, alignment is a big issue on ARM, that's why I used a loop
Alignment is important on almost all platforms.

> The first version I wrote in MSIL for SetDouble was:
>
[quoted text clipped - 9 lines]
>
> but this code throws an exception on my Pocket PC

I don't see anything wrong here. What's the exception?
Can you locate where it happens in the CIL stream? (You may
want to ilasm with debug information /DEBUG)

>> I don't think you can do anything verifiable with native pointers. And
>> if you really want to use them, make sure the pointee is pinned.
> LVT: I don't know how to pin memory

You need a managed pointer with the pinned attribute to
point to the object (or any subobject of the complete object).
This can safely be converted to a native pointer. However,
native pointers are never verifiable.

.class X {  // .ctor
.field int32 f; }

.method public static void main() {
.entrypoint
.locals ( int32& pinned p )
newobj instance void class X::.ctor() // x
ldflda int32 X::f
stloc p
// x.f is now pinned => x is pinned
ldloc p
conv.u
// top of the stack can be used as a native pointer
ret
}

>> That's probably not verifiable. You should cast to the array
>> type before via
[quoted text clipped - 14 lines]
> in
> its CF version

You can't do much with an array whose element type is unknown (in
a verifiable way).

>> You might want to use unaligned.1 cpblk
> LVT: Idealy YES but the following code throws an InvalidProgramException:
[quoted text clipped - 12 lines]
> ret
>    } // end of method Buffer::SetDouble

Looks perfectly valid to me. Did you get the calling function
correct? What does peverify say?
Luc Vaillant - 17 Nov 2005 13:57 GMT
Unfortunately, I do not have time to spend on this issue right now (my
clients are waiting for me...), I will investigate this later.
For now, I just change Array type to Byte[] and use a 8 bytes loop just like
BitConverter.ToDouble does.

As you certainely guess, I'm new in MSIL coding, and I found your remarks
very helpfull.

Thank you very much

Lvt

> >> Do you mean verifiable code? Or just valid CIL?
> > LVT : I just want not to be bored if security constraints (like only
[quoted text clipped - 96 lines]
> Looks perfectly valid to me. Did you get the calling function
> correct? What does peverify say?

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.