procedure parameter struct order

R

Richard Bos

Yoon Soo said:
while mixing assembler and c code I got the following question:

struct bar {
int bar_val1;
int bar_val2;
(...)
}

void foo(struct bar)
{
DO_SOMETHING;
};


My question is, if the order of the struct vars on the stack (eg.
bar_val1, bar_val2)is defined within C.

It is not even defined whether they are on a stack to begin with; small
structs could be passed in a couple of registers, for example.
Mixing assembly and C is deep into implementation-dependent territory
anyway, so if I were you I'd ask in a newsgroup that discusses the
specifics of your compiler; if you're tying your code into a single
compiler version anyway by including assembly, it's not going to hurt to
tie it a bit further by depending on its order. But do document that
you've done this.

Richard
 
Y

Yoon Soo

Hi, there

while mixing assembler and c code I got the following question:

struct bar {
int bar_val1;
int bar_val2;
(...)
}

void foo(struct bar)
{
DO_SOMETHING;
};


My question is, if the order of the struct vars on the stack (eg.
bar_val1, bar_val2)is defined within C.

In assembler code the values should be pushed onto the stack and then
foo should be called. My code is 'working for me', but I want to know,if
it is a defined behaviour, or it is gcc specific.

thx in advance

yoon
 
A

Alex

Yoon Soo said:
Hi, there

while mixing assembler and c code I got the following question:

struct bar {
int bar_val1;
int bar_val2;
(...)
}

void foo(struct bar)
{
DO_SOMETHING;
};


My question is, if the order of the struct vars on the stack (eg.
bar_val1, bar_val2)is defined within C.

No. The standards do not even specify that a stack is used for argument
passing at all (and indeed, it sometimes isn't). The "calling convention" is
implementation specific.
 
Y

Yoon Soo

Richard said:
It is not even defined whether they are on a stack to begin with; small
structs could be passed in a couple of registers, for example.

I forgot to mention, that foo is declared with the attribute regparm(0)
... which is (afaik) also depending on the implementation of the
compiler, so the stack should be used in any cases.
Mixing assembly and C is deep into implementation-dependent territory
anyway, so if I were you I'd ask in a newsgroup that discusses the
specifics of your compiler; if you're tying your code into a single
compiler version anyway by including assembly, it's not going to hurt to
tie it a bit further by depending on its order. But do document that
you've done this.

thx for the replies. I think I will include some inline asm codes into
foo to be sure, that the correct parameters are found on the stack.

yoon
 
R

Richard Bos

Guillaume said:
That's right, but he didn't use the right vocabulary, and you overlooked
(in my opinion) the point he was trying to figure out.

He was asking whether the MEMBERS of a given struct would always have
the same order (ie. offsets), whether the struct is passed as an
argument of a function, or used as a variable (or whatever), and the
short answer is: YES.

Short, but misleading. The answer is "yes, when accessed using a C
pointer"; but this doesn't tell you anything about what the assembly
code sees.
For example, if you do not use the & operator inside the function, it
might be more efficient to pass the struct in registers instead of on
the stack, if it's small; the C code cannot tell the difference, if it
doesn't ask for the struct's address. But for the assembly code, it
would be another kettle of fish entirely.

Richard
 
G

Guillaume

My question is, if the order of the struct vars on the stack (eg.
No. The standards do not even specify that a stack is used for argument
passing at all (and indeed, it sometimes isn't). The "calling convention" is
implementation specific.

That's right, but he didn't use the right vocabulary, and you overlooked
(in my opinion) the point he was trying to figure out.

He was asking whether the MEMBERS of a given struct would always have
the same order (ie. offsets), whether the struct is passed as an
argument of a function, or used as a variable (or whatever), and the
short answer is: YES. I think the norm actually guarantees that the
members of a struct are always in the same order as they are declared.
 
X

xarax

Richard Bos said:
Short, but misleading. The answer is "yes, when accessed using a C
pointer"; but this doesn't tell you anything about what the assembly
code sees.
For example, if you do not use the & operator inside the function, it
might be more efficient to pass the struct in registers instead of on
the stack, if it's small; the C code cannot tell the difference, if it
doesn't ask for the struct's address. But for the assembly code, it
would be another kettle of fish entirely.

Richard

Which is yet another reason why I prefer to
use a struct pointer, rather than a copy of
the struct (whether passing into or out of
a function call). By using a struct pointer,
the OP's "problem" is reduced to finding
the pointer that was passed to the assembler
function, rather than where each member is
located on the stackframe (if there *is* a
stackframe).

After finding the pointer, he knows that the
struct members will be in ascending order, but
be sure to account for inter-member gaps for
alignment (also implementation dependent).


--
----------------------------
Jeffrey D. Smith
Farsight Systems Corporation
24 BURLINGTON DRIVE
LONGMONT, CO 80501-6906
http://www.farsight-systems.com
z/Debug debugs your Systems/C programs running on IBM z/OS!
Are ISV upgrade fees too high? Check our custom product development!
 
R

Roc

No. The standards do not even specify that a stack is used for argument
passing at all (and indeed, it sometimes isn't). The "calling convention" is
implementation specific.

Then is the keyword "pascal" implementation specific?

I thought I read was it introduced to influence/enforce argument
stack-order... but that was a long time ago...
 
T

Thomas Matthews

Roc said:
Then is the keyword "pascal" implementation specific?

I thought I read was it introduced to influence/enforce argument
stack-order... but that was a long time ago...

Yes, the identifier "pascal" is implementation specific.
Some compilers use it to specify how the parameters are
passed to a receiving function.

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
C

Clark Cox

No. The standards do not even specify that a stack is used for argument
passing at all (and indeed, it sometimes isn't). The "calling convention" is
implementation specific.

Then is the keyword "pascal" implementation specific?[/QUOTE]

Umm, yes. The word "pascal" doesn't appear anywhere in the standard.
 
A

Alex

Guillaume said:
No. The standards do not even specify that a stack is used for
argument passing at all (and indeed, it sometimes isn't). The
"calling convention" is implementation specific.

That's right, but he didn't use the right vocabulary, and you
overlooked (in my opinion) the point he was trying to figure out.
Perhaps...

He was asking whether the MEMBERS of a given struct would always
have the same order (ie. offsets) [...]

I read that the OP was asking whether the standard specified how to retrieve
(in assembler) the values from a struct passed as a function argument. This
falls at the first hurdle: the calling convention is implementation defined.

It would also fall at the second hurdle: while the order of members /is/ -
as you said - defined by the standard, member offsets are not, due to
implementation-defined padding. But does this matter, if you never get
beyond the first hurdle?

Alex
 
C

Chris Torek

[original poster wrote]
I forgot to mention, that foo is declared with the attribute regparm(0)
.. which is (afaik) also depending on the implementation of the
compiler, so the stack should be used in any cases.

Indeed, it does depend on the compiler -- but be aware that just
because you force the compiler to pass the structure on its
implementation-specific stack does *not* mean that the structure
will be where you expect it to be.

In particular, I once fixed some (seriously scary) i386-specific
boot code that included, in part:

void f(struct S arg) {
... make changes to arg.fields ...
now call other functions, or even just return
}

plus assembly-language code that carefully called f() with a known
stack pointer and secret arrangements to access the changed values
in arg.fields in those other functions or after f() returned.

This actually worked in versions 1.x and 2.x of the compiler, but
gcc3 would sometimes choose to *copy* the argument "arg" to local
storage before making changes to arg.fields, so that the changes
were no longer being made to the special, known-stack-position
struct. Debugging this was "interesting" because the code would
hang very early in the boot process, long before there was any way
to debug it without an ICE, and making *any* change to the code --
including even a single "write a byte to the display memory to
observe progress" -- changed gcc's internal decisions as to whether
and when to copy the argument. (Thus, this was what is often called
a "Heisenbug", whose behavior changes when you attempt to observe
it.)

The fix for this was simple enough and brings us back on topic. I
changed f() to read:

void f(struct S *arg) {
... make changes to arg->fields ...
now call other functions, or return
}

This did take a whole extra four bytes of stack space, along with
an extra instruction or two in the assembly startup; but why whoever
it was who wrote the original might have been concerned about this
is beyond me since f() not only had its own compiler-generated
(hence unpredictable) stack usage but also called other functions
which were not *that* tightly code-and-stack-space-constrained.

The moral, as it were, is also on-topic: even if you know all about
your compiler, choosing to depend on it may be a mistake, as a
future version of that compiler may change its internals. If there
is a way to write the code so that it *has* to work according to
the language rules, consider using that code instead.

Finally, one last note: The offsets of the various fields of a
structure can be obtained with the offsetof() macro, and will be
in ascending order according to the structure's definition. There
may be gaps for "struct padding" between fields, but the first
field will be at offset 0, the next at an offset no less than
"sizeof" the first field, the next no less than "sizeof" that field
further on, and so on.
 
Y

Yoon Soo

Guillaume said:
That's right, but he didn't use the right vocabulary, and you overlooked
(in my opinion) the point he was trying to figure out.

He was asking whether the MEMBERS of a given struct would always have
the same order (ie. offsets), whether the struct is passed as an
argument of a function, or used as a variable (or whatever), and the
short answer is: YES. I think the norm actually guarantees that the
members of a struct are always in the same order as they are declared.

yes, I think I really used the wrong vocabulary.

My question was exactly: if a struct is passed as an argument of a
function, the members of this struct would always have the same order on
the stack..or to be more exact, if the function expects to find the
members in the order they are declared. Within only c this is not that
great problem, but since I am pushing the values manually onto the
stack, I need to know, where the translated c code will expect them
conform to the c standard.

And if this is guaranted by the norm.

To explain my thoughts: Maybe a compiler xyz could say, that it is
better to reorder the struct for better performance or similar. So I
will push the first member and the function is expecting the second one
there instead.

thx for your short answer. I will try to find something about it in the
norm.

yoon
 
J

Jack Klein

I forgot to mention, that foo is declared with the attribute regparm(0)

There is no such thing as "attribute regparm(0)" in C. You are
talking about some non-standard extension provided by your particular
compiler. It is both nonsense and off-topic here, and needs to be
asked in a support group for your compiler.
.. which is (afaik) also depending on the implementation of the
compiler, so the stack should be used in any cases.

No, it is not something that C defines as "implementation-defined", it
is something that is not C at all.
thx for the replies. I think I will include some inline asm codes into
foo to be sure, that the correct parameters are found on the stack.

Likewise, there is no such thing as inline assembly language code in
the C language. All such features are again non-standard and specific
to your compiler.

There is nothing wrong with using non-standard extensions, you just
need to realize that they are not discussed here because they are not
part of the language, and discuss them in groups for the specific
compiler that provides them.
 
J

Jack Klein

That's right, but he didn't use the right vocabulary, and you overlooked
(in my opinion) the point he was trying to figure out.

He was asking whether the MEMBERS of a given struct would always have
the same order (ie. offsets), whether the struct is passed as an
argument of a function, or used as a variable (or whatever), and the
short answer is: YES. I think the norm actually guarantees that the
members of a struct are always in the same order as they are declared.

The short answer is: NO WAY TO TELL.

On most of the platforms I use today, the struct would no be passed on
"the stack" at all, but in two registers.

The passed copy would never reside in memory at all in many cases. If
an address of the copy were needed, for example if the function
receiving the copy in turn called another function and passed a
pointer to the passed structure copy, the called function would
provide some space in memory and copy the register contents to the
appropriate addresses. The caller, passing a copy, would neither know
nor care that this might eventually take place.

C does not specify anything about "the stack" or about anything passed
by value. And the as-if rule certainly allows the compiler to hold
any object entirely in registers or other non-memory locations so long
as its address is not taken.
 
R

Richard Bos

Yoon Soo said:
My question was exactly: if a struct is passed as an argument of a
function, the members of this struct would always have the same order on
the stack..or to be more exact, if the function expects to find the
members in the order they are declared.

No. In particular, as has already been written by several people, you do
not even know whether the arguments are passed on the stack in the first
place. All you know is that to code using C pointers, it must appear as
all members are at the same place in memory. Even this might mean that
the struct is copied into some (cheap, fast, plentiful) allocated
memory, and a hidden pointer to this copied struct is passed on the
(slow, small) stack.
But even when the stack is used, you do not know that the whole stack is
passed, or in what order. For example, take this code:

struct rectangle {
char *label;
int width;
int heigth;
t_colour background;
t_colour foreground;
t_pattern hatching;
int top;
int left;
}

int rect_size(struct rectangle r)
{
if (r.hatching==PAT_BLANK)
return 0;
return r.width*r.heigth;
}

Since nothing in the function references anything else in the structure,
and there is no possible way for you to detect the difference, the
compiler would be quite correct if, behind the scenes, all it pushed on
the stack were the hatching, width and heigth members, and adjusted the
object code for the function accordingly. The program would function
identically, except that it spends a few cycles less pushing and popping
needless struct members. No problem, in ISO C.
Now along comes someone who shoves a bit of assembly code inside that
function which starts manipulating the SP register as if all the members
are right there on the stack. Oops...

Richard
 
Y

Yoon Soo

Jack said:
There is nothing wrong with using non-standard extensions, you just
need to realize that they are not discussed here because they are not
part of the language, and discuss them in groups for the specific
compiler that provides them.

in some points you are right, but you did not got the key point. Neither
my questions nor the informations I got from this thread was related to
the non-standard extensions.

My key question was related to the standard..of course I could ask that
to people who does not care much about ISO and similar but I doubt I
would get there the informations I got here..and there were many helpful
informations.

however, greets

yoon
 
Y

Yoon Soo

Richard Bos wrote:

Since nothing in the function references anything else in the structure,
and there is no possible way for you to detect the difference, the
compiler would be quite correct if, behind the scenes, all it pushed on
the stack were the hatching, width and heigth members, and adjusted the
object code for the function accordingly. The program would function
identically, except that it spends a few cycles less pushing and popping
needless struct members. No problem, in ISO C.
^^^^^^^^^^^^^^^^^^^^^^^^
that's the (main) info I wanted. Many thanks for your clear example and
the explanations to it.

yoon
 
D

Dave Thompson

No. In particular, as has already been written by several people, you do
not even know whether the arguments are passed on the stack in the first

True. Or if there even is a (single) stack as such, although to allow
functions to be recursive, which *is* required, there must be some way
to make automatic (aka local) variables operate stackishly.
place. All you know is that to code using C pointers, it must appear as
all members are at the same place in memory. Even this might mean that

Not quite the same place, that would be a union. In a contiguous chunk
of memory than can be memcpy'ed to another struct object of the same
type and work, yes; and with member addresses/offsets in ascending
order, but as noted elsethread possibly skipping padding.
the struct is copied into some (cheap, fast, plentiful) allocated
memory, and a hidden pointer to this copied struct is passed on the
(slow, small) stack.

Stacks are rarely slow and small, usually they are fast -- often
distinctly faster than general memory, because of better cache
locality -- but may be small(ish). Or, often a pointer (but not a full
struct) can be passed in register(s), which are usually (very) small
and (very) fast.
But even when the stack is used, you do not know that the whole stack is
passed, or in what order. For example, take this code:

struct rectangle { [snipped]
}
(Nit: missing semicolon)
int rect_size(struct rectangle r)
{
if (r.hatching==PAT_BLANK)
return 0;
return r.width*r.heigth;
}

Since nothing in the function references anything else in the structure,
and there is no possible way for you to detect the difference, the
compiler would be quite correct if, behind the scenes, all it pushed on
the stack were the hatching, width and heigth members, and adjusted the
object code for the function accordingly. The program would function
identically, except that it spends a few cycles less pushing and popping
needless struct members. No problem, in ISO C.

Although this function could be called from a separately compiled
"module" (strictly, translation unit), and the compiler, or linker, or
something, would have to make sure that such calls also do that same
optimization, which on many/most? systems is so hard as to be
practically impossible. Now if you made the function 'static', it
would be somewhat more likely. In fact, if the definition is visible
during compilation -- as it must be, if static -- there's a fair
chance it will be inlined, and nothing will be pushed at all. Perhaps
even a slightly better chance in C99 if you *specify* 'inline'.

(PS- it's spelled 'height', or spelt depending on your location.)

- David.Thompson1 at worldnet.att.net
 
R

Richard Bos

Dave Thompson said:
Stacks are rarely slow and small, usually they are fast -- often
distinctly faster than general memory, because of better cache
locality -- but may be small(ish).

Usually, but hey, we're talking about guarantees here. The above _could_
happen.
Although this function could be called from a separately compiled
"module" (strictly, translation unit), and the compiler, or linker, or
something, would have to make sure that such calls also do that same
optimization, which on many/most? systems is so hard as to be
practically impossible.

Again, I know, but it's not impossible. It might even be worth the
trouble.
(PS- it's spelled 'height', or spelt depending on your location.)

Damn, I was wondering whether I'd spelled that correctly!

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,619
Members
45,315
Latest member
VernellPos

Latest Threads

Top