This is the mail archive of the crossgcc@sources.redhat.com mailing list for the crossgcc project.

See the CrossGCC FAQ for lots more information.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Structure alignment problem


Doug:


Warning, OT!  :^)

>  > Yep, structure-defined i/o is evil.  But the alternatives are much worse...
> 
> Do both?  As in include/elf/external.h in binutils/gdb releases?
> [or am I missing the point ...]

This kind of stuff:

  unsigned char sh_size[4];             /* Size of section in bytes */

makes me wonder.  I mean, I don't know much about BFD code, but I bet
they're doing this because the endian ordering in a data file is
consistent, and so they use some endian-neutral logic to parse the data:

  int sh_size = 0;
  int wbyte;
  Elf32_External_Shdr *shdr;

  for (wbyte = 0; wbyte < sizeof(shdr->sh_size); wbyte++)
     sh_size = (sh_size << 8) + shdr->sh_size[wbyte];

[note: off the top of my head, not taken from any particular example. ymmv]

This is a good way to go about solving this particular class of
problems, I think.  The algorithm rigidly presumes a certain endian
sense in the incoming data stream (in this case, big endian), but
cleanly maps it to the host processor's integer endian orientation,
whatever it happens to be, because the << operator in C is defined to
be equivalent to a multiply, which is endian neutral.  And what's
more, the bitshift helps the compiler understand what's going on, so
the optimizer can clean up the code if it can find a way to.  The loop
may get replaced with a single, 32-bit move on a big endian machine,
for example.

I came to this thread late, but I think Grant was considering using
structure i/o to talk to external hardware devices vs. memcpy'ing the
data around.  Or, at least, that's what *I* was referring to.  :^)

I think that with few exceptions, the structure approach is the best
way to go about talking to external hardware, because what you're
doing is highly nonportable already (try switching endians on the host
processor, changing processors, packed vs. unpacked, whatever), so you
may as well go with something that's self-documenting so that when you
have to go into the code to fix it, you can tell what the code is
trying to do.

The one exception I can think of is for using bitmaps in structures to
talk to peripheral control registers that have "reserved, write zero"
bit fields.  I haven't come up with a clean way to deal with that one
without resorting to some unions that let me mask the whole byte/word
on the way out to the hardware, and *that* code starts looking pretty
evil too.

What would be cool is a language extension like this:

typedef struct {
   unsigned int field1 : 1;         /* read/write ok */
   unsigned int field2 : 1;         /* read/write ok */
   unsigned int reserved : 2 = 0;   /* reads garbage, write zero */
   unsigned int field3 : 4          /* read/write ok */
} foo_hardware;

So if I did this:

  foo_hardware *foo = FOO_ADDRESS;
  foo->field1 = 1;

the underlying implementation would do this:

  *foo = (*foo | 0x80) & 0xcf;
  
Now _that_ would be embedded friendly!


/soapbox



b.g.
-- 
Bill Gatliff
Affordable GNU and Linux training and consulting services.
See http://billgatliff.com for details.
etails.

------
Want more information?  See the CrossGCC FAQ, http://www.objsw.com/CrossGCC/
Want to unsubscribe? Send a note to crossgcc-unsubscribe@sources.redhat.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]