OpenNETCF
(1)
Factory.SerialNumber
(1)
NKDbgPrintfW
(1)
CcData.Factory.ManufacturerId
(1)
CcData.Factory.SerialNumber
(1)
CcData.Factory.ChipId
(1)
Bruce.Eitman
(1)
EMVP
(1)

Datatype misalignment exception....

Asked By paolo patierno
06-Feb-10 04:00 AM
Hello,
I am developing with Windows CE 5.0 and a Freescale iMX31 ARM11 processor.
I know the problem of data type alignment and the datatype misalignment
exception but I do not understand the following.
I have the following struct :

typedef struct _FACTORY
{
BYTE ATR[6];
BYTE ManufacturerId;
BYTE ChipId[6];
BYTE SerialNumber[4];
} FACTORY, *PFACTORY;

typedef struct _CCDATA
{
FACTORY Factory;
}

and the following function Compute() and main() :

void Compute(PCCDATA pBytes)
{
DEBUGMSG(TRUE, (TEXT("pBytes=%u"),
*((UINT32*)pBytes->Factory.SerialNumber)));
}

int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
CCDATA ccData;
ccData.Factory.ATR[0] = 0x01;
ccData.Factory.ATR[1] = 0x02;
ccData.Factory.ATR[2] = 0x03;
ccData.Factory.ATR[3] = 0x04;

ccData.Factory.ManufacturerId = 0x18;

ccData.Factory.ChipId[0] = 0x13;
ccData.Factory.ChipId[1] = 0xFF;
ccData.Factory.ChipId[2] = 0xFF;
ccData.Factory.ChipId[3] = 0xFF;
ccData.Factory.ChipId[4] = 0xFF;
ccData.Factory.ChipId[5] = 0xFF;

ccData.Factory.SerialNumber[0] = 0x28;
ccData.Factory.SerialNumber[1] = 0x32;
ccData.Factory.SerialNumber[2] = 0x1B;
ccData.Factory.SerialNumber[3] = 0x32;

// 840643112
BYTE serialNumber[4];
serialNumber[0] = 0x28;
serialNumber[1] = 0x32;
serialNumber[2] = 0x1B;
serialNumber[3] = 0x32;

DEBUGMSG(TRUE, (TEXT("SerialNumber=%u"),
*((UINT32*)ccData.Factory.SerialNumber)));
//Compute(ccData.Factory.SerialNumber);
Compute(&ccData);

return 0;
}

In the main I try to read SerialNumber byte array like a UINT32...I know
that it is a bad thing like reported in the MSDN documentation but I do not
understand why the code in the main() does not throw the datatype misalignment
exception while the code in the Compute funcion throws this....
Why ?

Thanks,
Paolo

SerialNumber is not DWORD aligned (it is addres is not evenly divisible by

Chris Tacke, MVP replied to paolo patierno
06-Feb-10 01:06 PM
SerialNumber is not DWORD aligned (it is addres is not evenly divisible by 4)
so you cannot treat it as a DWORD (UINT32) directly.  Copy it to a DWORD and
use that:


DWORD serial;
// copy bytes to an aligned variable from the unaligned byte array
memcpy(&serial, pBytes->Factory.SerialNumber, sizeof(DWORD));
// use serial here

-Chris

Yes Chris....I know that but my question is...

paolo patierno replied to Chris Tacke, MVP
07-Feb-10 04:36 AM
Yes Chris....I know that but my question is...why the datatype misalignment
exception is raised if I execute the access to the variable in function
Compute() but it is not raised in the same instruction in the main() ?

Thanks,
Paolo

My guess is that what you call "the same instruction in the main()" is infact

Bruce Eitman [eMVP] replied to paolo patierno
07-Feb-10 11:39 AM
My guess is that what you call "the same instruction in the main()" is in
fact considerably different in Compute().

Main uses a compile/assemby time known address while compute uses an address
that is not known until runtine becuase it is a pointer.

--
Bruce Eitman (eMVP)
Senior Engineer
Bruce.Eitman AT Eurotech DOT com
My BLOG http://geekswithblogs.net/bruceeitman

Eurotech Inc.
www.Eurotech.com
Obviously, when I said "the same instruction in the main()" I mean the
paolo patierno replied to Bruce Eitman [eMVP]
07-Feb-10 01:15 PM
Obviously, when I said "the same instruction in the main()" I mean the same
instruction in C++. If I print (with printf or DEBUGMSG) the pointer
ccData.Factory.SerialNumber in the main() and the pointer pBytes in the
Compute() function, they are the same. The address is not aligned to 4 bytes
(UINT32 dimension) and I think that the Datatype Misalignmnet exception wuold
be raised in both main and Compute().

Thanks,
Paolo
I would expect it too.
Chris Tacke, MVP replied to paolo patierno
07-Feb-10 01:50 PM
I would expect it too.  Don't consider the fact the it is not excepting to
mean that what you are doing is OK, becasue it is not.  Align the access for
all uses, regarless of whether the system excepts or not.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
I agree with you....
paolo patierno replied to Chris Tacke, MVP
07-Feb-10 02:28 PM
I agree with you....I have already change the code because I have already
wrote that this access is a bad thing but I would like to undestand why the
exception is not raised in the main...only for knowledge...

Thanks,
Paolo
Huh?
Bruce Eitman [eMVP] replied to paolo patierno
07-Feb-10 05:17 PM
Huh?  What I mean is that the two C instructions are not the same.  They are
similar but radically different.

--
Bruce Eitman (eMVP)
Senior Engineer
Bruce.Eitman AT Eurotech DOT com
My BLOG http://geekswithblogs.net/bruceeitman

Eurotech Inc.
www.Eurotech.com
Ok...but at runtime the two pointers are the same....
paolo patierno replied to Bruce Eitman [eMVP]
08-Feb-10 02:56 AM
Ok...but at runtime the two pointers are the same....the memory address of
the BYTE array is the same...so you said that the assembly code generated at
compile time is different and even if the address is the same, this
difference in assembly code determines a different behavior ?
Thank you for you patience...

Paolo
That is what I suspect.
Bruce Eitman [eMVP] replied to paolo patierno
08-Feb-10 11:31 AM
That is what I suspect.  You can take a look at the assembly code by setting
WINCECOD=1 the compiling.  The COD file will be in the OBJ folder.

--
Bruce Eitman (eMVP)
Senior Engineer
Bruce.Eitman AT Eurotech DOT com
My BLOG http://geekswithblogs.net/bruceeitman

Eurotech Inc.
www.Eurotech.com
Hi Bruce....you are right....
Paolo Patierno replied to Bruce Eitman [eMVP]
09-Feb-10 03:23 AM
Hi Bruce....you are right....following the ASSEMBLY code of Compute()
function and main() :

Compute()
..
; 21   : 	DEBUGMSG(TRUE, (TEXT("pBytes=%u"),
*((UINT32*)pBytes->Factory.SerialNumber)));

00010	e59d300c	 ldr         r3, [sp, #0xC]
00014	e283300d	 add         r3, r3, #0xD
00018	e5931000	 ldr         r1, [r3]
0001c	e59f0020	 ldr         r0, [pc, #0x20]
00020	eb000000	 bl          NKDbgPrintfW
..
..

main()
..
; 53   : 	DEBUGMSG(TRUE, (TEXT("SerialNumber=%u"),
*((UINT32*)ccData.Factory.SerialNumber)));

00104	e5dd3010	 ldrb        r3, [sp, #0x10]
00108	e1a02403	 mov         r2, r3, lsl #8
0010c	e5dd300f	 ldrb        r3, [sp, #0xF]
00110	e1833002	 orr         r3, r3, r2
00114	e1a02403	 mov         r2, r3, lsl #8
00118	e5dd300e	 ldrb        r3, [sp, #0xE]
0011c	e1833002	 orr         r3, r3, r2
00120	e1a02403	 mov         r2, r3, lsl #8
00124	e5dd300d	 ldrb        r3, [sp, #0xD]
00128	e1831002	 orr         r1, r3, r2
0012c	e59f003c	 ldr         r0, [pc, #0x3C]
00130	eb000000	 bl          NKDbgPrintfW
..
..
In the main(), the compiler generates 4 access in memory that read one byte
at time (byte aligned) and build the UINT32 into internal registry (using r2
and r3) so the access does not rise exception because it is byte aligned. In
the compute(), the compiler generates 1 direct access to the address that
is not aligned to UINT32 (4 bytes).

Thanks,
Paolo
--
Paolo Patierno
Embedded Software Engineer
Yes, so long as the compiler knows that you are accessing a non-alignedmember
Aaron Lawrence replied to Paolo Patierno
18-Feb-10 01:50 AM
Yes, so long as the compiler knows that you are accessing a non-aligned
member it can work around it. However if you just pass an address to a
function, the code in that function has no way to know whether the
address is aligned or not.

The part that is surprising is the compiler silently working around the
problem ; at a considerable performance cost too ...
Post Question To EggHeadCafe