[comp.sys.mips] Unaligned struct access

CCHD@lure.latrobe.edu.au (Huw Davies - La Trobe University Computer Centre) (02/14/91)

I have a slight problem with the c compiler (on  MIPS 120/5 running RISC/os 
4.5.1).

The following code doesn't do what I want :-) Please note that this
is an example of the error extracted from debugging 6K lines of c code
(It took a while to find....).

$ more test_struct.c
#include <stdio.h>

struct test
{
    short a;
    int b;
} c;

main()
{
        printf("a: %x\nb: %x\nSize of a: %d\n", &c.a, &c.b, 
                                                  (int) &c.b - (int) &c.a);
}

$ ./test
a: 2003e460
b: 2003e464
Size of a: 4
$ 

I would have liked the difference in address to be 2, not 4. I know
that there are efficiency reasons for aligned access, but I would like
to be able to override the default.

For those few of you who read comp.unix.aix as well (there's got to be
someone else who believes in vendor independence...) I have the
same problem with our RS/6000 systems. (Different implementation - same
bugs :-)

Huw Davies
Computing Services

e-mail: cchd@lucifer.latrobe.edu.au

sah@batman (Steve Hanson) (02/15/91)

In article <5054@lure.latrobe.edu.au>, CCHD@lure (Huw Davies - La Trobe University Computer Centre) writes:
>I have a slight problem with the c compiler (on  MIPS 120/5 running RISC/os 
>4.5.1).
>
>The following code doesn't do what I want :-) Please note that this
>is an example of the error extracted from debugging 6K lines of c code
>(It took a while to find....).
>
>$ more test_struct.c
>#include <stdio.h>
>
>struct test
>{
>    short a;
>    int b;
>} c;
>
>main()
>{
>        printf("a: %x\nb: %x\nSize of a: %d\n", &c.a, &c.b, 
>                                                  (int) &c.b - (int) &c.a);
>}
>
>$ ./test
>a: 2003e460
>b: 2003e464
>Size of a: 4
>$ 
>
>I would have liked the difference in address to be 2, not 4. I know
>that there are efficiency reasons for aligned access, but I would like
>to be able to override the default.
>
>For those few of you who read comp.unix.aix as well (there's got to be
>someone else who believes in vendor independence...) I have the
>same problem with our RS/6000 systems. (Different implementation - same
>bugs :-)
>
>Huw Davies
>Computing Services
>
>e-mail: cchd@lucifer.latrobe.edu.au


Taken from the 2.20, in Beta now,  release notes:

o  #pragma pack(n)
   #pragma pack()
        The first form is used to change the strictest alignment of
        structure members within a structure. n is the new alignment
        restriction in bytes. If n is omitted, then it defaults to the
        compiler option -Zp, if present, or the compiler default,
        which is the strictest member alignment.



Your code would look like:

#include <stdio.h>
#pragma pack(2)
struct test
{
    short a;
    int b;
} c;



main()
{
        printf("a: %x\nb: %x\nSize of a: %d\n", &c.a, &c.b, 
                                                  (int) &c.b - (int) &c.a);
}

with the ouput:
a: 10000b7c
b: 10000b7e
Size of a: 2

cprice@mips.COM (Charlie Price) (02/16/91)

In article <5054@lure.latrobe.edu.au> CCHD@lure.latrobe.edu.au (Huw Davies - La Trobe University Computer Centre) writes:
>I have a slight problem with the c compiler (on  MIPS 120/5 running RISC/os 
>4.5.1).
>
>The following code doesn't do what I want :-) Please note that this
>is an example of the error extracted from debugging 6K lines of c code
>(It took a while to find....).
>
>$ more test_struct.c
>#include <stdio.h>
>
>struct test
>{
>    short a;
>    int b;
>} c;
>
>main()
>{
>        printf("a: %x\nb: %x\nSize of a: %d\n", &c.a, &c.b, 
>                                                  (int) &c.b - (int) &c.a);
>}
>
>$ ./test
>a: 2003e460
>b: 2003e464
>Size of a: 4
>$ 
>
>I would have liked the difference in address to be 2, not 4. I know
>that there are efficiency reasons for aligned access, but I would like
>to be able to override the default.
>
>For those few of you who read comp.unix.aix as well (there's got to be
>someone else who believes in vendor independence...) I have the
>same problem with our RS/6000 systems. (Different implementation - same
>bugs :-)

You seem to assume that fields in a struct will be packed.
That isn't C.
The compiler won't pack fields for you,
you have to do mis-alignment by hand.

When I need to use a packed (or otherwise oddly aligned) external
format, I normally read-and-unpack-from-odd-format into a
C structure, write the program to reference the C struct elements,
and pack-into-odd-format-and-write when I need to get it out.
This way, I control the pack and unpack and can possibly even
write this in a completely portable way.
MIPS has unaligned access library routines that would help
you write the unpack and pack parts.
The routines are in unaligned(3).

If it is important to you, for some reason, to run a program
that has unaligned references then MIPS helps you out.
In the program that will do this, you have to either:
* do the load/store by calling MIPS-supplied library routines
  that do unaligned references  (see unaligned(3)).
* call a MIPS-supplied signal-catcher once to emulate unaligned
  references when they occur (see unaligned(3)).
* make a MIPS-specific system call at the program start to have the
  the kernel emulate unaligned refs when they occur (see sysmips(2)).

The MIPS-supplied signal handler package catches the SIGBUS signal
caused by the unaligned reference,
emulates the unaligned reference,
and keeps track of how many it sees of each type.
The package has a way to let you print a report
that tells you how many references of each type it fixed up.
This package is also the one with library routines you can call
directly to do unaligned loads and stores.

If you don't mind even less portable code,
then you can make a MIPS-specific system call that tells
the kernel to look for and emulate unaligned references
whenever you get a bus error rather than give your process a SIGBUS.
The MIPS-specific calls are documented in sysmips(2),
and you want to look at MIPS_FIXADE.

The fastest performance is to write programs that don't need
to make alignment assumptions.

The next fastest is to use the library routines to do the
unaligned references each place you do one.

The emulation choices are VERY VERY slow, relative to a lw instruction.
You pay a high price for the convenience of running code
that has unaligned references -- but at least we help out.
-- 
Charlie Price    cprice@mips.mips.com        (408) 720-1700
MIPS Computer Systems / 928 Arques Ave. / Sunnyvale, CA   94086-23650