1

i have created a structure like bellow :

[StructLayout(LayoutKind.Explicit, Pack = 1)]
    public class NodRecord
    {
        [FieldOffset(0)]
        public ushort Driver;


        [FieldOffset(2)]
        public ushort BaudRate;

        [FieldOffset(4)]
        public ushort EnquiryInterval;

        [FieldOffset(6)]
        public byte Protocol;

        [FieldOffset(7)]
        public ushort Delay;

        [FieldOffset(9)]
        public NodIPAddress IP_Addr_Other;

        [FieldOffset(13)]
        public ushort IP_Port_Other;

        [FieldOffset(15)]
        public ushort IP_Port_Own;

        [FieldOffset(17)]
        public ushort Application;
    }

then i have read it with code bellow:

 readBuffer = reader.ReadBytes(sizeType);
 handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
 nodes = (NodRecord)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NodRecord));
 handle.Free();

I wonderd in x86 ,x64 and cortex arm processors everything is ok but on Atmel ARM9 AT91SAM9G20 for ushort variables i got wrong values, for example first and third next bytes values replace instead of first and second next bytes, but for byte values everything is ok

Mohsen Zahraee
  • 3,309
  • 5
  • 31
  • 45

1 Answers1

2

Some old ARM processors (and some new, depending on their configuration and the operating system) have a broken concept when it comes to any unaligned address: they don't fault and they don't load the value at the specified address. What they do is (I forgot the details) some sort of mindless rotate or address alignment so that the data come out unlike you (or anyone else) expect it. Mono doesn't handle this case well (it would mean slowing down code for all the well-behaved cases, so we made the trade off to let almost everyone to enjoy the speed and a few people deal with the fringe cases). You have two possible solutions: see if the operating system you use has a configuration option that make the kernel deal with such cases or implement yourself the marshaling for this case by loading byte by byte and shifting to combine the values when you have unaligned data

lupus
  • 3,963
  • 1
  • 18
  • 13
  • If you can determine at code generation time whether the load is aligned or not, then you can generate fast or slow code as necessary. The key here is that the structure and its fields are clearly marked as being on arbitrary byte alignments, so you know you have to generate the byte-by-byte sequence. You're already going to be doing this for stores anyway. – Al Grant Dec 31 '12 at 18:26
  • If it was that simple... At code generation time you cannot know if the data is aligned or not (even if the fields are aligned, the structure could be stored in memory at an unaligned address, for example) so we'd have to always generate slow code for all the structure accesses. Using a layout like the above is a bad practice even on platforms where it works so it should be avoided anyway. – lupus Jan 02 '13 at 08:50
  • If the structure is Pack=1 then you know that the structure may be stored at an unaligned address, and you need to deal with that. If the structure is not Pack=1 you can assume it has default alignment. It's no different from GCC's support for packed access. There's decades of experience says this can be implemented with reasonable efficiency when the programmer explicitly wants unaligned access, without in any way compromising the efficiency of default aligned data - even in "unmanaged" languages like C. – Al Grant Jan 02 '13 at 12:23
  • You're missing that a structure can be stored at an unaligned address even if it doesn't have Pack=1 or Explicit layout. But, anyway, if you think this is easy and the implementation doesn't have any performance drawback for good code and data structures, I'm willing to try your patch and either write a test that breaks it or shows the performance degradation. – lupus Jan 03 '13 at 08:30