The Unix Heritage Society mailing list
 help / color / mirror / Atom feed
From: Alexander Monakov <amonakov@ispras.ru>
To: tuhs@minnie.tuhs.org
Subject: [TUHS] pcc struct return quirk
Date: Sat, 12 Mar 2022 11:00:54 +0300 (MSK)	[thread overview]
Message-ID: <d165b2bb-425d-d457-97c8-af5e84ab44c3@ispras.ru> (raw)

Hello,

I'm trying to understand a quirk in 32-bit x86 code generation conventions:
on Linux, when returning a structure from a function by value:

struct S {
	int i, j;
};

struct S f(int x)
{
	return (struct S){x, sizeof(void*)};
}

the caller reserves space for the returned structure and passes a pointer
to that space as an 'invisible' extra argument, which is prepended to
the argument list; the callee returns this pointer (although the caller
knows it anyway); it's as if the function is transformed to

struct S *f(struct S *ret, int x)
{
	ret->i = x;
	ret->j = sizeof(void*);
	return ret;
}

with one essential difference: the function 'f' itself is responsible for
popping the extra argument off the stack (the 'x' argument is popped by
its caller).

This necessitates using the return-with-immediate ('ret 4') instruction
instead of the normal 'ret'; this is the only instance where this variant of
the 'ret' instruction is used in code generation for C programs on Linux
normally.

I wonder how this exception came to be.

Early versions of GCC (e.g. gcc-1.27) did not implement this convention, i.e.
the caller was responsible for popping the invisible pointer similar to the
normal arguments. The "callee-pops" variant was implemented later for
"compatibility with other compilers", and the option that controls this is
called -fpcc-struct-return, which also disables returning small structures in
registers (in the example above GCC would return the value in EDX:EAX register
pair).

Operating systems differ on following this convention. For example, FreeBSD
and OpenBSD do not, and neither does Windows.

Looking at 386BSD tree in unix-history-repo, I see that it used GCC, not PCC.
Where can I look at the history of x86 code generation development in PCC?
Do I understand correctly that i386 code generation in PCC evolved in parallel
with GCC, and at some point GCC was convinced to adopt the (less efficient)
PCC calling convention by default?

Did PCC prefer to do this stack adjustment for the invisible pointer on the
callee side for some other platform, and the behavior was merely carried over
to the i386 port?

Thank you.
Alexander

                 reply	other threads:[~2022-03-12  8:03 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d165b2bb-425d-d457-97c8-af5e84ab44c3@ispras.ru \
    --to=amonakov@ispras.ru \
    --cc=tuhs@minnie.tuhs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).