Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 08 Mar 2001 15:50:29 -0500 (EST)
From:      "Philippe O. Pouliquen" <philippe@alpha.ece.jhu.edu>
To:        freebsd-alpha@FreeBSD.ORG
Subject:   Re: Strange results from compiled alpha code
Message-ID:  <200103082050.PAA0000024187@alpha.ece.jhu.edu>

next in thread | raw e-mail | index | archive | help
I've had an e-mail exchange with Ray Newman, and have investigated the
problem further.

Peter Jeremy <peter.jeremy@alcatel.com.au> wrote:
> Ray Newman <raymond@one.com.au> wrote:
>>Tony Griffiths wrote:
>>> In the case you give below, the 'short len' is misaligned on an
>>> odd byte boundary.  This might be the cause of the problem...
> I suspect that gcc is ignoring the low bit of the address when
> loading the short.  The Compaq CC masks the address so as to create
> an alignment fault in this case.

Just to clear things up here, in the C sequence:

    *((short *) char_pointer)

The problem only occurs with GCC when the word (short in C, 16 bit)
straddles a quad-word (long in C, 64 bit) boundary.  The instruction
sequence emitted by GCC works fine for any word completely contained
in a quad-word (see end of message).  In any case, the instruction
sequence *never* generates an alignment trap (it uses LDQ_U) -- it
just silently loads the wrong value when the straddling occurs.

*This is legal ANSI C behavior.* According to the ANSI C standard,
loading a short from an unaligned address results in undefined
behavior.

The Compaq CC is friendlier: if the word is not word aligned, an
alignement trap is generated, and the proper value is loaded by the
kernel.


>>> I know that with DEC/Compaq cc there is a #pragma and also a
>>> compiler switch to assume_unaligned pointers for cases like this.
>...
>>> I don't know that the [g]cc equivalent switch is but presume that
>>> there is one!
>Actually, there doesn't appear to be one.

#pragma pack 1

only works in Compaq's CC, but causes structure to be created without
internal padding.  As a side effect, the compiler then assumes that
pointers will be misaligned.  Packing the structures in Ray's case may
be a good thing, because beyond the misaligned pointer, his code
assumes that the second structure member is stored two bytes after the
first (that's why he has sizeof(short) in there):

typedef struct CSTRING
{ short len;
  u_char buf[32768];
} cstring;

    mumpspc += ((cstring*)mumpspc)->len + sizeof(short) + 1;


>>> Alternatively, change the code slightly to ensure that the
>>> 'mumpspc' pointer is always incremented by an even number of bytes.
>>> eg.
>>> 
>>> mumpspc += ( ((cstring*)mumpspc)->len + sizeof(short) + 2 ) & ~1;
>
> If you can't guarantee alignment, then your other option is to
> totally avoid the use of CSTRING and use code like (assuming
> little-endian data):
>
>        short   len = mumpspc[0] | (mumpspc[1] << 8);
>        mumpspc = mumpspc + len + sizeof(short) + 1;

Ray was hoping not to modify his code, as the problem occurs in many
locations.  In any case, the code above is not strictly correct.
First, it does not properly access the structure elements, because it
assumes that 'buf' (second structure member) is stored two bytes
(sizeof(short)) after 'len' (first structure member).  Second, 'len'
is a signed (16 bit) integer, but mumpspc is a pointer to unsigned
byte.  (and, as mentioned by Peter, the code is endian dependent)


Here is the shortest sequence that I could come up with which
highlights the problem:
----------------------------------------------------------------
#include <stdio.h>

unsigned char data[16]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
		0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10};

short get_short(unsigned char *ptr)
{
  return(*((short *)ptr));
}

main()
{
  printf("0x%X\n",get_short(&(data[7])));
}
----------------------------------------------------------------

gcc version 2.95.2 (alpha-dec-osf4.0) prints 0x100.  Comapq C V6.1-011
on Digital UNIX V5.0 (Rev. 910) generates an unaligned access trap and
prints 0x908.

Here is the GCC instruction sequence: (gcc -O)

    addq    a0, 0x2, a0    // a0=a0+2   (2=sizeof(short))
    ldq_u   v0, -2(a0)     // v0=*((long *)(a0-2)) (won't trap)
    extqh   v0, a0, v0     // v0=v0<<((64-8*a0)&0x3F)

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-alpha" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200103082050.PAA0000024187>