Packing of structure fields and whole structs

2006-12-05 Thread Phil Endecott

Dear GCC Experts,

I am trying to understand the subtleties of __attribute__((packed)).  I 
have some code that works on x86, where unaligned accesses work, but 
fails on ARM where they do not.


As far as I can see, if I declare a struct with the packed attribute 
applied to the whole struct, like this:


struct test {
  int a;
  int b;
} __attribute__((packed));

and then use it like this:

{
  char c;
  struct test t;
}

Then t will be packed next to c, and t.a and t.b will be unaligned.  
This is not what I want!


There are lots of examples in the Linux kernel headers (if you have a 
source tree handy, grep for them).  Here's one example picked at random:


#define FDDI_K_OUI_LEN  3
struct fddi_snap_hdr
{
__u8dsap;   /* always 0xAA */
__u8ssap;   /* always 0xAA */
__u8ctrl;   /* always 0x03 */
__u8oui[FDDI_K_OUI_LEN];/* organizational universal id */
__be16  ethertype;  /* packet type ID field 
*/
} __attribute__ ((packed));

As far as I can see, making this packed can only cause trouble.  If 
packed wasn't there there would still be no gaps between the fields - 
would there? - and variables of this type would be word-aligned, so the 
16-bit field would be 16-bit aligned, and it would work on an ARM.  But 
by declaring it as packed then a variable of this type will be packed 
at any alignment (e.g. char c; struct fddi_snap_hdr x;) and the 16-bit 
field may be unaligned.


Am I completely misunderstanding all of this?

I am using gcc 4.1.2.

Here is the test that I have been using to investigate this:

struct test {
  int a;
  int b;
}__attribute__((packed));
char c = 1;
struct test t = { .a=2, .b=3 };

arm-linux-gnu-gcc -S test.c

.file   "test.c"
.global c
.data
.type   c, %object
.size   c, 1
c:
.byte   1
.global t
.type   t, %object
.size   t, 8
t:
.4byte  2
.4byte  3
.ident  "GCC: (GNU) 4.1.2 20061028 (prerelease) (Debian 4.1.1-19)"


Many thanks in advance for any advice.

Regards,

Phil.

(you're welcome to Cc: any replies as I'm subscribed to the digest.)






%dil in x86 inline asm

2005-05-25 Thread Phil Endecott

Dear GCC experts,

I'm having trouble compiling code that uses the following macro from the 
Apache Portable Runtime:


#define apr_atomic_cas(mem,with,cmp) \
({ apr_atomic_t prev; \
asm volatile ("lock; cmpxchgl %1, %2"  \
 : "=a" (prev)   \
 : "r" (with), "m" (*(mem)), "0"(cmp) \
 : "memory"); \
prev;})

It seems that on some machines it tries to use the AMD64 register %dil, 
which does not exist on a regular x86 machine, and gives an assembler error.


I've found bug 10153 and its duplicates which seem to be describing 
essentially the same thing, but say that the input is invalid because it 
uses "r" rather than "q".  I don't know enough about x86 to understand 
this; presumably only certain registers can be used with this 
instruction, or something.


However, naively, I'd argue that it is never right for gcc to use a 
register that doesn't exist on the target architecture.  Can someone 
justify its behaviour?  If the input is illegal surely it should 
generate an error.


Can you suggest how Apache should correct this code?

(I should explain that I have not seen this error first-hand myself. 
I'm the author of a GPL program, Anyterm, and have had this error 
reported by other users.  I'm therefore "debugging at a distance".  The 
platform that causes the problems is Mandrake 10.1.  I'm afraid I don't 
even know what version of gcc it has.)



Thanks for any suggestions.

--Phil.