[Mono-dev] Alignment issue when interoperate with native code

Christian Krause chkr at plauener.de
Sun Jan 30 15:56:33 EST 2011


Hi,

During debugging a C# wrapper for a C-library I have stumbled over an
unexpected alignment issue in mono / C#:


It looks like that the internal alignment of data structures deviates on
32-bit X86 systems from the standard ELF alignment.

I've created a minimal testcase which can be downloaded from here:
http://chkr.fedorapeople.org/mono-alignment/

1. libalignmenttest.c:
a C-library containing a function "testfunc" which returns a structure
containing a "double":

struct  t1 {
    int i1;
    double d1;
};
The function sets the values always to i1 = 1234 and d1 = 1.1.

2. test.cs:
a C# file which calls "testfunc" from the C-library:

Since all of the variables of the "t1" structure are blittable types, it
should be possible just to define the structure in C# and declare the
appropriate function using DllImport.

http://www.mono-project.com/Interop_with_Native_Libraries :
"[...] so if an unmanaged function returns a pointer to a structure,
IntPtr must be used for "safe" code, or a pointer to the structure can
be used for "unsafe" code.[...]".

I have chosen the 2nd choice:
--------------------------------------------
struct t1 {
    public int i1;
    public double d1;
}

[DllImport("libalignmenttest")]
unsafe public static extern t1* testfunc();
--------------------------------------------

3. Running the test:
$ gcc -Wall -Werror -o libalignmenttest.so -shared
-Wl,-soname,libalignmenttest.so libalignmenttest.c
$ gmcs -unsafe test.cs
$ mono ./test.exe
i1: 1234
d1: 5.35799274627359E-313
$

So the value of "d1" is messed up. It looks like that C# aligns double
data types on 8-byte boundaries but linux ELF ABI defines an 4-byte
alignment which is used in the native library. If I restrict the
alignment of C# to 4-byte alignment by adding "[StructLayout
(LayoutKind.Sequential, Pack=4)]", it works fine.

4. Definition of C# / ELF alignment:

The X86 ELF ABI defines that double values should be 4-byte aligned
X86 ELF ABI: http://refspecs.freestandards.org/elf/abi386-4.pdf , Figure
3-1.

The ECMA CLI standard defines the alignment so:
http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf ,
12.6.2
"[...] and int64, unsigned int64, and float64 start on an address
divisible by 4 or 8, depending upon the target architecture. [...] It is
strongly recommended that float64 be aligned on an 8-byte boundary, even
when the size of native int is 32 bits.".


5. My questions:

a) Is it the intended behavior of mono on X86-32 systems that the
internal representation of struct data types uses 8-byte alignment for
double types even if this deviates from the ELF alignment rules?

b) Since the same problem happens with the 64bit integer type ("long
long" in C, "long" in C#) this would mean, that as soon as 64 bit data
types are involved, structures can never be transferred between native
code and C# using pointers to C# structures and it is strictly required
to use a technology which marshals them correctly (either using IntPtr
and Marshal.PtrToStructure or use C# classes as return values for the
native function where the marshalling seems to be done implicitly.)

c) The ECMA CLI standard recommends explicitly for float64 to use an
8-byte alignment and so the implementation seems to follow the standard
here. But what about the int64 data type? The specification states only,
that it should 4- or 8-byte aligned, "[...] depending upon the target
architecture" and on X86-32 systems that target architecture does not
require an 8-byte alignment for 64bit integers. Is it intended that
int64 is also 8-byte aligned?


It would be great if someone could confirm whether my findings are
correct. ;-) Thank you very much in advance!

Best regards,
Christian


More information about the Mono-devel-list mailing list