EmbDev.net

Forum: ARM programming with GCC/GNU tools accessing struct member getting incorrect offset


von Dustin S. (dbrazeau)


Rate this post
useful
not useful
I have several function that take a pointer of a struct as an input.
The problem that I'm having is that when I try to access some of the
members of the struct I'm receiving an incorrect offset to that member.
Here is an example:

struct A
{
  int one;
  int two;
  char a;
  char b;
  sX x[1];
}

void funcx(const A *pA)
{
  printf(pA->x);
}

So lets just say I know what is in pA->x and when printed it starts at
the third byte of pA->x.

Interesting enough if I change the struct to look like:
struct A
{
  int one;
  int two;
  sX x[1];
  char a;
  char b;
}

The offset is correct.  From my understanding this is not the expected
behavior,  and if it is could someone explain to me why.  I was also
wondering if there is some compile option that could effect this.

von Martin T. (mthomas) (Moderator)


Rate this post
useful
not useful
Cross posted to the GNUARM yahoo group and ongoing discussion there.

von Clifford S. (clifford)


Rate this post
useful
not useful
Martin Thomas wrote:
> Cross posted to the GNUARM yahoo group and ongoing discussion there.
I am not a member of either of those, so forgive me for that.


A::x is a single item of type sX. Without knowing what type sX is it is
hard to comment. For printf(pA->x); to be valid however A::x must be a
string, but you have declared it as 1 element array of Sx objects (why!?
What use is a single element array?). Assuming perhaps that Sx is an
alias for char, because strings must have a nul terminator, the only
valid 1-byte string is a nul terminator alone (not very useful), so it
seems likely that this is an invalid string. If however Sx is an alias
for char*, then you need to print pA->x[0].

Moreover the first parameter to printf() should be a string constant,
using a variable argument is very bad practice in any case (here's why:
http://www.ddj.com/security/184405774). Perhaps:

printf( "%s", pA->x ) ;

Exactly why it is doing what it is doing is hard to tell from the lack
of information provided, but that is probably academic and the code
looks dodgy in any case!

Clifford

von Dustin S. (dbrazeau)


Rate this post
useful
not useful
Clifford Slocombe wrote:
> A::x is a single item of type sX. Without knowing what type sX is it is
> hard to comment. For printf(pA->x); to be valid however A::x must be a
> string, but you have declared it as 1 element array of Sx objects (why!?
> What use is a single element array?). Assuming perhaps that Sx is an
> alias for char, because strings must have a nul terminator, the only
> valid 1-byte string is a nul terminator alone (not very useful), so it
> seems likely that this is an invalid string. If however Sx is an alias
> for char*, then you need to print pA->x[0].
>
> Moreover the first parameter to printf() should be a string constant,
> using a variable argument is very bad practice in any case (here's why:
> http://www.ddj.com/security/184405774). Perhaps:
>
> printf( "%s", pA->x ) ;
>
> Exactly why it is doing what it is doing is hard to tell from the lack
> of information provided, but that is probably academic and the code
> looks dodgy in any case!
>
> Clifford

Sorry about the confusion.  I actually don't use the printf statement
exactly like I put it there.  I have my own print function and what I do
is dump the hex from the element in the struct.  The problem is that the
pointer points (is offset) a few bytes into that element, which is shown
to me by the print.  And for example if I move that element up in the
declaration of that structure by the amount that it is incorrectly
offset then it fixes the problem.  Is that any compile option that deals
with the aligning of structures or something of that sort?

von Clifford S. (clifford)


Rate this post
useful
not useful
Dustin Sr wrote:
> Is that any compile option that deals
> with the aligning of structures or something of that sort?

There are compiler extensions to specify alignment, but that is not the
issue, you should be able to correctly access an individual member
regardless of its alignment. If you persist in hiding information, it is
hard to see how anyone can help you. I suggest that you post a complete
example of code that reproduces the problem. You are either doing
something unconventional or just plain wrong, and kludging the alignment
may make your code appear 'work' but that is not the same as making it
right!

The array size of 1 is still ringing alarm bells as 'weird code' and you
have not really explained that, so I have no confidence that the code
you are not showing is not flawed in some way that is causing the
situation you are observing. Also I have no confidence that your
observation is even valid since you tried to illustrate the situation
with something other than the real code, and code that is not even
valid.

The danger is that without full information you will fix the symptom
rather than the problem.

Now if you are simply trying to say that you expect the address of A::x
to be at a particular location and it is not there, then that is
'normal' behaviour, and I would suggest that that is not what you
actually stated. The compiler determines the alignment of structure
members, and generally does so to maximise efficiency on the target
platform. Forcing an alternative alignment is less efficient and not
portable and best avoided. If you need to ensure adjacency of data
elements, then use an array, offset constants, and casts wrapped in an
access layer to hide the nasty details, alternatively add
serialisation/deserialisation routines to unpack/pack teh structure as
necessary (easier in C++ as it happens). If portability is not an issue
for you then use structure packing advisedly:
http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Type-Attributes.html


Clifford

von Dustin S. (dbrazeau)


Rate this post
useful
not useful
Clifford Slocombe wrote:
> There are compiler extensions to specify alignment, but that is not the
> issue, you should be able to correctly access an individual member
> regardless of its alignment. If you persist in hiding information, it is
> hard to see how anyone can help you. I suggest that you post a complete
> example of code that reproduces the problem. You are either doing
> something unconventional or just plain wrong, and kludging the alignment
> may make your code appear 'work' but that is not the same as making it
> right!
>
> The array size of 1 is still ringing alarm bells as 'weird code' and you
> have not really explained that, so I have no confidence that the code
> you are not showing is not flawed in some way that is causing the
> situation you are observing. Also I have no confidence that your
> observation is even valid since you tried to illustrate the situation
> with something other than the real code, and code that is not even
> valid.
>
> The danger is that without full information you will fix the symptom
> rather than the problem.
>
> Now if you are simply trying to say that you expect the address of A::x
> to be at a particular location and it is not there, then that is
> 'normal' behaviour, and I would suggest that that is not what you
> actually stated. The compiler determines the alignment of structure
> members, and generally does so to maximise efficiency on the target
> platform. Forcing an alternative alignment is less efficient and not
> portable and best avoided. If you need to ensure adjacency of data
> elements, then use an array, offset constants, and casts wrapped in an
> access layer to hide the nasty details, alternatively add
> serialisation/deserialisation routines to unpack/pack teh structure as
> necessary (easier in C++ as it happens). If portability is not an issue
> for you then use structure packing advisedly:
> http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Type-Attributes.html
>
>
> Clifford

First off I would like to thank you for your help.  Sorry that I have
not given a more full and better example, as I'm trying to port this
code, that was not written by me, from the ARM tools to the GNU tools.
I believe I have discovered the problem, which is due to the code that
is built with GNU receiving a structure from an external source, which
was created with the ARM compiler, in which the padding and offsets of
the structure are different for the two compilers.

von Clifford S. (clifford)


Rate this post
useful
not useful
Dustin Sr wrote:
> I believe I have discovered the problem, which is due to the code that
> is built with GNU receiving a structure from an external source, which
> was created with the ARM compiler, in which the padding and offsets of
> the structure are different for the two compilers.

That would explain it, that information would have been useful from the
start! There is no point in holding back if you want a definitive
answer. By definition, if you don't know what teh problem is, you don't
really know what information is relevant.

Exchanging data between different systems or modules, or built with
different compilers, or even the same compiler with different options or
for a different target is error prone, structure packing and byte order
may differ. The most robust solution under code maintenance and re-use
is serialisation/deserialization. Consider also exchanging data in a
non-binary form, such as XML or CSV for example.

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.