This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


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

plain C link incompatibility between gcc 2.7 and egcs on many i386 platforms



hi -

I was recently surprised to find that there is a link incompatibility
between gcc 2.7.2 and egcs for plain C on most i386 platforms.
(I expected see link incompatibilities for C++, but not for plain C.)

The problem has to do with structure returns from functions.
On the i386, gcc does structure returns by passing an extra pointer
on the stack to the callee giving the address of the destination
for the structure return.  (It appears that the NeXTstep configuration
is an exception to this.)  In gcc 2.7, the callee leaves all its
arguments on the stack, and they popped by the caller, including
the extra structure return arg.   For gcc 2.8/egcs, however, this
was changed.  Now, the callee pops the structure return arg,
and the caller pops all the remaining arguments.  (Unless -mrtd
is set, in which case the callee pops everything.)
This appears to have been introduced by the following change:

Thu Feb 29 11:39:30 1996  Stan Cox  <coxs@dg-rtp.dg.com>

	* i386.c (i386_return_pops_args): Cleanup extra argument
	used as address of a returned structure.



So, the result of calling a routine which returns a structure,
which was compiled with gcc 2.7, from code compiled with egcs,
is that an extra word is left on the stack after the call.
What makes this somewhat insidious is that in many cases, this
will have no ill effects.  However, it can lead to invalid
code if such a call is made in the process of building up an
argument list for another call.

Here's an example:

-- z1.c --------------------------------------------------------

struct s {
  int x;
};

struct s func (int y)
{
  struct s xx;
  xx.x = y * 10;
  return xx;
}

-- z2.c --------------------------------------------------------

struct s {
  int x;
};

extern struct s func (int y);

void func2 (struct s x1, struct s x2)
{
  printf ("%d %d\n", x1.x, x2.x);
}


int main ()
{
  func2 (func (1), func (2));
}
----------------------------------------------------------------


On linux, compile z1.c with gcc 2.7.2 and z2.c with egcs and link
them together.  The resulting program prints

10 1

rather than the expected

10 20

which one gets by compiling both modules with the same compiler.


This leaves me in a bit of a quandry.
The situation is that i'm using linux and i have some C code
which gcc 2.7.2.3 does not compile correctly.  (It's a FP-intensive
function, and gcc 2.7.2.3 gets a store out of order.)  egcs,
on the other hand, does compile this code correctly.  However,
i have libraries which i need to link with which are only available
in binary form and which were compiled with gcc 2.7.2.3.
(What i'm actually using is the KAI C++ compiler, which uses gcc
as a backend on linux.)

So, i tried adding an additional target-dependent switch to egcs,
-mcaller-pops-structreturn, to allow reverting its behavior for
structure returns to what gcc 2.7.2.3 did.  Patches (against 1.1.1
prerelease #2) are appended below.

Does this seem like a reasonable approach to take?

thanks,
sss
snyder@fnal.gov



Wed Nov 25 14:11:37 1998  scott snyder  <snyder@fnal.gov>

	* config/i386/i386.h (MASK_CALLER_POPS_STRUCTRETURN): New.
	(TARGET_CALLER_POPS_STRUCTRETURN): New.
	(TARGET_SWITCHES): Add -mcaller-pops-structreturn.
	* config/i386/i386.c (i386_return_pops_args): Test
	TARGET_CALLER_POPS_STRUCTRETURN.
	* invoke.texi: Document -mcaller-pops-structreturn flag.



Index: gcc/invoke.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/invoke.texi,v
retrieving revision 1.56
diff -u -p -r1.56 invoke.texi
--- invoke.texi	1998/07/13 12:39:33	1.56
+++ invoke.texi	1998/11/27 23:25:18
@@ -338,6 +338,7 @@ in the following sections.
 -mreg-alloc=@var{list}  -mregparm=@var{num}
 -malign-jumps=@var{num}  -malign-loops=@var{num}
 -malign-functions=@var{num}
+-mcaller-pops-structreturn
 
 @emph{HPPA Options}
 -mbig-switch  -mdisable-fpregs  -mdisable-indexing  
@@ -5060,6 +5061,17 @@ than 8 bytes away.
 Align the start of functions to a 2 raised to @var{num} byte boundary.
 If @samp{-malign-functions} is not specified, the default is 2 if optimizing
 for a 386, and 4 if optimizing for a 486.
+
+@item -mcaller-pops-structreturn
+The normal calling sequence for a function with a structure return
+involves pushing an extra argument for the address of the returned
+structure.  This extra argument is popped by the callee, while the
+remaining arguments are popped by the caller.  Setting this flag
+changes the calling sequence so that all the arguments are popped
+by the caller.  This corresponds to the behavior of gcc 2.7.
+Note that for some targets (such as SCO), the caller pops all arguments
+regardless of the state of this flag.  In addition, if the @samp{-mrtd} flag
+is set, the setting of this flag doesn't matter.
 @end table
 
 @node HPPA Options
Index: gcc/config/i386/i386.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.36.2.2
diff -u -p -r1.36.2.2 i386.c
--- i386.c	1998/07/28 22:31:09	1.36.2.2
+++ i386.c	1998/11/27 23:25:20
@@ -639,7 +639,8 @@ i386_return_pops_args (fundecl, funtype,
   }
 
   /* Lose any fake structure return argument.  */
-  if (aggregate_value_p (TREE_TYPE (funtype)))
+  if (aggregate_value_p (TREE_TYPE (funtype)) &&
+      ! TARGET_CALLER_POPS_STRUCTRETURN)
     return GET_MODE_SIZE (Pmode);
 
     return 0;
Index: gcc/config/i386/i386.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.27.2.1
diff -u -p -r1.27.2.1 i386.h
--- i386.h	1998/07/26 00:35:12	1.27.2.1
+++ i386.h	1998/11/27 23:25:21
@@ -96,6 +96,8 @@ extern int target_flags;
 #define MASK_DEBUG_ARG		000020000000	/* Debug function_arg */   
 #define MASK_SCHEDULE_PROLOGUE  000040000000    /* Emit prologue as rtl */
 #define MASK_STACK_PROBE	000100000000	/* Enable stack probing */
+#define MASK_CALLER_POPS_STRUCTRETURN 000200000000	/* Caller pops the */
+						/* structure return pointer */
 
 /* Use the floating point instructions */
 #define TARGET_80387 (target_flags & MASK_80387)
@@ -169,6 +171,17 @@ extern int target_flags;
 #define TARGET_DEEP_BRANCH_PREDICTION (ix86_cpu == PROCESSOR_PENTIUMPRO)
 #define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
 
+/* The normal calling sequence for a function with a structure return
+   involves pushing an extra argument for the address of the returned
+   structure.  This extra argument is popped by the callee, while the
+   remaining arguments are popped by the caller.  Setting this flag
+   changes the calling sequence so that all the arguments are popped
+   by the caller.  This corresponds to the behavior of gcc 2.7.
+   Note that for some targets (such as SCO), the caller pops all arguments
+   regardless of the state of this flag.  In addition, if the RTD flag
+   is set, the setting of this flag doesn't matter. */
+#define TARGET_CALLER_POPS_STRUCTRETURN (target_flags & MASK_CALLER_POPS_STRUCTRETURN)
+
 #define TARGET_SWITCHES							\
 { { "80387",			 MASK_80387 },				\
   { "no-80387",			-MASK_80387 },				\
@@ -207,6 +220,8 @@ extern int target_flags;
   { "no-debug-arg",		-MASK_DEBUG_ARG },			\
   { "stack-arg-probe",		 MASK_STACK_PROBE },			\
   { "no-stack-arg-probe",	-MASK_STACK_PROBE },			\
+  { "caller-pops-structreturn",  MASK_CALLER_POPS_STRUCTRETURN },       \
+  { "nocaller-pops-structreturn",-MASK_CALLER_POPS_STRUCTRETURN },      \
   { "windows",			0 },					\
   { "dll",			0 },					\
   SUBTARGET_SWITCHES							\


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