problem w/ memory alaignment

I’ve a massive problem if normaly realy legal C/C++ code running on a sh4.
see the example below

char *GetMemory() ;
short local = 0;

// this one is not working
// the value I get is not byte swaped or something else it is only absolutly
wrong
// the same code running on x86 is working proper
short *pLocal = (short *)(GetMemory() + 7);
local = *pLocal;

// versus this version is working and gets the right value
char *pLocal = GetMemory() + 7;
local = ((short)(pLocal[1]) << :sunglasses: | (short)(pLocal[0]);

I’ve been looking at this and there’s something weird going on. Here’s some
assembly:

case1:
short *pLocal = (short *)(GetMemory() + 7);
80404aa: f3 61 mov r15,r1
80404ac: 38 d8 mov.l 8040590 <main+0xf0>,r8 ! 0x8040460
80404ae: 0b 48 jsr @r8
80404b0: 09 00 nop
80404b2: 03 61 mov r0,r1
80404b4: 07 71 add #7,r1
80404b6: 11 1e mov.l r1,@(4,r14)
local = *pLocal;
80404b8: e1 51 mov.l @(4,r14),r1
80404ba: 11 62 mov.w @r1,r2
80404bc: 21 2e mov.w r2,@r14


case2:
char *pLocal = GetMemory() + 7;
8040500: f3 61 mov r15,r1
8040502: 23 d8 mov.l 8040590 <main+0xf0>,r8 ! 0x8040460
8040504: 0b 48 jsr @r8
8040506: 09 00 nop
8040508: 03 61 mov r0,r1
804050a: 07 71 add #7,r1
804050c: 11 1e mov.l r1,@(4,r14)
local = ((short)(pLocal[1] << :sunglasses: | (short)(pLocal[0]));
804050e: e1 52 mov.l @(4,r14),r2
8040510: 23 61 mov r2,r1
8040512: 01 71 add #1,r1
8040514: 10 62 mov.b @r1,r2
8040516: 23 61 mov r2,r1
8040518: 18 41 shll8 r1
804051a: e1 52 mov.l @(4,r14),r2
804051c: 20 63 mov.b @r2,r3
804051e: 3b 21 or r3,r1
8040520: 11 2e mov.w r1,@r14

My array returned by GetMemory is a short array {1,2,3,4,5,6} which looks
like 0x00020001 0x00040003… in memory.
It looks like the instruction in case 1 at 04ba is where the problem lies.
Instead of getting 0500 from the array (like we do in case2) we wind up with
0xffff0000. The psuedocode for the mov.w instruction is:

MOVWL(long m, long n)
{
R[n]=(long)Read_Word(R[m]);
if ((R[n] & 0x8000) == 0) R[n] &= 0x0000FFFF;
else R[n] |= 0xFFFF0000;
PC+=2;
}

So it seems like we’re getting zero and then sign extending to 0xFFFF0000.
The question, of course, is why the Read_Word is not getting the 0x0500 from
the array. I’ll look further into it. It’s likely that gcc is generating
invalid code in this case but I’ll have to figure out what the valid code is
first.

cheers,

Kris

“HP Reichert” <hp.reichert@idea.REMOVE.soft.de> wrote in message
news:atuff1$fku$1@inn.qnx.com

I’ve a massive problem if normaly realy legal C/C++ code running on a sh4.
see the example below

char *GetMemory() ;
short local = 0;

// this one is not working
// the value I get is not byte swaped or something else it is only
absolutly
wrong
// the same code running on x86 is working proper
short *pLocal = (short *)(GetMemory() + 7);
local = *pLocal;

// versus this version is working and gets the right value
char *pLocal = GetMemory() + 7;
local = ((short)(pLocal[1]) << > :sunglasses: > | (short)(pLocal[0]);

Looks like it might be user error in this case but there’s still something
strange going on. According to the SH4 programming manual:

“A word operand must be accessed starting from a word boundary (even address
of a 2-byte unit: address 2n). An address error will result if this rule is
not observed. A byte operand can be accessed from any address.”

So case2 is correct code (for this CPU) because it requires aligned memory
access. I was confused because I was expecting a bus error or some such.
In fact, this code DOES give a bus error on arm and mips (but not ppc and
sh4). I’ll have to look into that because this would have gone a lot
quicker if there had been a bus error.

So the lesson is, when programming for non-x86 platforms which require
aligned memory access, don’t assume the cpu will do it for you.

cheers,

Kris

Just answered my own question. Look at the documentation for procnto in the
Utilities reference. x86, ppc and sh4 all use alignment fault emulation by
default which explains why there was no sigbus. So it looks like we
actually might have found an alignment fault emulation bug for sh4. Thanks
for your report.

cheers,

Kris

Kris,

The current default on SH-4 (will change in the near future) is for
procnto to emulate unaligned access. For the time being, you can change
the default behavior in your IFS build script with the “-ad” flag to
procnto:

… procnto -v -ad

Your application will get a SIGBUS that you can catch with gdb.


Cheers,
-david



Kris Warkentin wrote:

Just answered my own question. Look at the documentation for procnto in the
Utilities reference. x86, ppc and sh4 all use alignment fault emulation by
default which explains why there was no sigbus. So it looks like we
actually might have found an alignment fault emulation bug for sh4. Thanks
for your report.

cheers,

Kris