This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


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: [RFC] Linux-specific ppc32 ABI


Hi,

On Fri, 2008-01-11 at 10:57 -0500, Daniel Jacobowitz wrote:
> On Fri, Jan 11, 2008 at 01:55:20PM -0200, Luis Machado wrote:
> > > How about an extra flag inside the gdbarch_tdep structure that
> > > you'll be using inside the push dummy call?  It would be a shame
> > > duplicate this function when most of it is common.
> > 
> > Yes. This would work, but putting linux specific code inside the
> > ppc-sysv-tdep.c file doesn't look quite right. But if there isn't a
> > better way of doing this, should be OK.
> 
> For practical reasons, this is how it is usually done.

Actually, we won't need to go through the flag. I've checked and the
PPC/Linux ABI conforms with the PPC/SysV ABI regarding Calling Sequences
and the Stack layout.

Considering we have a function with a great number of float parameters,
exceeding the number of available FP registers, we need to store those
parameters in the stack space, and then there's a problem with the
ABI/GDB.

The SysV ABI says we should promote exceeding float parameters (the ones
that should go to the stack) to double, and store then with 8 bytes
alignment in the stack.

Trying to call a function like that, from within GDB, made it clear that
some parameters were getting trashed, and this is due to the fact that
GCC (XLC as well) doesn't promote floats to doubles and does not align
them to 8 bytes in the stack. Actually, it just aligns the prototyped
float parameters to 4 bytes in the stack.

This is something that needs to be improved in the ABI text. I've
attached a note next to the portion of code responsible for handling
float parameters.

The patch follows, with a minor change in the ABI handling for PPC32 and
a testcase Thiago wrote to verify the problem.

Comments?

Regards,

-- 
Luis Machado
Software Engineer 
IBM Linux Technology Center
2008-01-11  Luis Machado  <luisgpm@br.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* testsuite/gdb.base/callfuncs.c (t_float_many_args): New function.
	(t_double_many_args): New function.
	* testsuite/gdb.base/callfuncs.exp: Add tests for exceeding float
	and double parameters passed through the stack.
	* ppc-sysv-tdep.c: Convert spaces to tabs.
	(ppc_sysv_abi_push_dummy_call): Align floats to	4 bytes in the stack.

Index: gdb/testsuite/gdb.base/callfuncs.c
===================================================================
--- gdb.orig/testsuite/gdb.base/callfuncs.c	2008-01-11 09:59:22.000000000 -0800
+++ gdb/testsuite/gdb.base/callfuncs.c	2008-01-11 09:59:33.000000000 -0800
@@ -1,6 +1,6 @@
 /* This testcase is part of GDB, the GNU debugger.
 
-   Copyright 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2004, 2007, 2008
+   Copyright 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2004, 2007
    Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -46,9 +46,35 @@
 
 float float_val1 = 3.14159;
 float float_val2 = -2.3765;
+float float_val3 = 0.25;
+float float_val4 = 1.25;
+float float_val5 = 2.25;
+float float_val6 = 3.25;
+float float_val7 = 4.25;
+float float_val8 = 5.25;
+float float_val9 = 6.25;
+float float_val10 = 7.25;
+float float_val11 = 8.25;
+float float_val12 = 9.25;
+float float_val13 = 10.25;
+float float_val14 = 11.25;
+float float_val15 = 12.25;
 
 double double_val1 = 45.654;
 double double_val2 = -67.66;
+double double_val3 = 0.25;
+double double_val4 = 1.25;
+double double_val5 = 2.25;
+double double_val6 = 3.25;
+double double_val7 = 4.25;
+double double_val8 = 5.25;
+double double_val9 = 6.25;
+double double_val10 = 7.25;
+double double_val11 = 8.25;
+double double_val12 = 9.25;
+double double_val13 = 10.25;
+double double_val14 = 11.25;
+double double_val15 = 12.25;
 
 #define DELTA (0.001)
 
@@ -298,6 +324,39 @@
 	  && (float_arg2 - float_val2) > -DELTA);
 }
 
+/* This function has many arguments to force some of them to be passed via
+   the stack instead of registers, to test that GDB can construct correctly
+   the parameter save area. Note that Linux/ppc32 has 8 float registers to use
+   for float parameter passing and Linux/ppc64 has 13, so the number of
+   arguments has to be at least 14 to contemplate these platforms.  */
+
+float
+#ifdef NO_PROTOTYPES
+t_float_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13,
+		   f14, f15)
+     float f1, float f2, float f3, float f4, float f5, float f6, float f7,
+     float f8, float f9, float f10, float f11, float f12, float f13, float f14,
+     float f15;
+#else
+t_float_many_args (float f1, float f2, float f3, float f4, float f5, float f6,
+		   float f7, float f8, float f9, float f10, float f11,
+		   float f12, float f13, float f14, float f15)
+#endif
+{
+  float sum_args;
+  float sum_values;
+
+  sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12
+	     + f13 + f14 + f15;
+  sum_values = float_val1 + float_val2 + float_val3 + float_val4 + float_val5
+	       + float_val6 + float_val7 + float_val8 + float_val9
+	       + float_val10 + float_val11 + float_val12 + float_val13
+	       + float_val14 + float_val15;
+
+  return ((sum_args - sum_values) < DELTA
+	  && (sum_args - sum_values) > -DELTA);
+}
+
 #ifdef PROTOTYPES
 int t_double_values (double double_arg1, double double_arg2)
 #else
@@ -311,6 +370,39 @@
 	  && (double_arg2 - double_val2) > -DELTA);
 }
 
+/* This function has many arguments to force some of them to be passed via
+   the stack instead of registers, to test that GDB can construct correctly
+   the parameter save area. Note that Linux/ppc32 has 8 float registers to use
+   for float parameter passing and Linux/ppc64 has 13, so the number of
+   arguments has to be at least 14 to contemplate these platforms.  */
+
+double
+#ifdef NO_PROTOTYPES
+t_double_many_args (f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13,
+		   f14, f15)
+     double f1, double f2, double f3, double f4, double f5, double f6,
+     double f7, double f8, double f9, double f10, double f11, double f12,
+     double f13, double f14, double f15;
+#else
+t_double_many_args (double f1, double f2, double f3, double f4, double f5,
+		    double f6, double f7, double f8, double f9, double f10,
+		    double f11, double f12, double f13, double f14, double f15)
+#endif
+{
+  double sum_args;
+  double sum_values;
+
+  sum_args = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12
+	     + f13 + f14 + f15;
+  sum_values = double_val1 + double_val2 + double_val3 + double_val4
+	       + double_val5 + double_val6 + double_val7 + double_val8
+	       + double_val9 + double_val10 + double_val11 + double_val12
+	       + double_val13 + double_val14 + double_val15;
+
+  return ((sum_args - sum_values) < DELTA
+	  && (sum_args - sum_values) > -DELTA);
+}
+
 #ifdef PROTOTYPES
 int t_string_values (char *string_arg1, char *string_arg2)
 #else
Index: gdb/testsuite/gdb.base/callfuncs.exp
===================================================================
--- gdb.orig/testsuite/gdb.base/callfuncs.exp	2008-01-11 09:59:22.000000000 -0800
+++ gdb/testsuite/gdb.base/callfuncs.exp	2008-01-11 09:59:33.000000000 -0800
@@ -1,5 +1,5 @@
 # Copyright 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-# 2004, 2007, 2008 Free Software Foundation, Inc.
+# 2004, 2007 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -155,6 +155,8 @@
         
 	gdb_test "p t_float_values2(3.14159,float_val2)" " = 1"
 
+	gdb_test "p t_float_many_args (float_val1, float_val2, float_val3, float_val4, float_val5, float_val6, float_val7, float_val8, float_val9, float_val10, float_val11, float_val12, float_val13, float_val14, float_val15)" " = 1" "Call function with many float arguments."
+
 	gdb_test "p t_small_values(1,2,3,4,5,6,7,8,9,10)" " = 55"
 
 	gdb_test "p t_double_values(0.0,0.0)" " = 0"
@@ -163,6 +165,8 @@
 	gdb_test "p t_double_values(45.654,double_val2)" " = 1"
 	gdb_test "p t_double_values(double_val1,-67.66)" " = 1"
 
+	gdb_test "p t_double_many_args (double_val1, double_val2, double_val3, double_val4, double_val5, double_val6, double_val7, double_val8, double_val9, double_val10, double_val11, double_val12, double_val13, double_val14, double_val15)" " = 1" "Call function with many double arguments."
+
 	gdb_test "p t_double_int(99.0, 1)" " = 0"
 	gdb_test "p t_double_int(99.0, 99)" " = 1"
 	gdb_test "p t_int_double(99, 1.0)" " = 0"
Index: gdb/ppc-sysv-tdep.c
===================================================================
--- gdb.orig/ppc-sysv-tdep.c	2008-01-11 09:59:22.000000000 -0800
+++ gdb/ppc-sysv-tdep.c	2008-01-11 13:22:52.000000000 -0800
@@ -129,17 +129,35 @@
 		}
 	      else
 		{
-		  /* SysV ABI converts floats to doubles before
-		     writing them to an 8 byte aligned stack location.  */
-		  argoffset = align_up (argoffset, 8);
+		  /* The ppc32 SysV ABI tells us to convert floats to doubles
+		     before writing them to an 8 byte aligned stack location.
+
+		     NOTE: 2008/01/11: This is not exactly right.  GCC does not
+		     convert floats to doubles neither store floats into
+		     8 bytes aligned stack locations when we have a prototyped
+		     float parameter.  In this case GCC simply stores floats
+		     into 4 bytes aligned locations.  The promotion of floats
+		     to doubles happens, for example, if we have functions with
+		     float varargs (in which case the floats are converted to
+		     doubles and we will see them as so).  The ABI text needs
+		     to be updated.  */
+
+		  /* Align to 4 bytes or 8 bytes depending on the type of
+		     the argument (float or double).  */
+		  argoffset = align_up (argoffset, len);
+
 		  if (write_pass)
 		    {
-		      char memval[8];
+		      char memval[len];
 		      convert_typed_floating (val, type, memval,
-					      builtin_type_ieee_double);
+					      (len == 4)?
+					      builtin_type_ieee_single
+					      : builtin_type_ieee_double);
 		      write_memory (sp + argoffset, val, len);
 		    }
-		  argoffset += 8;
+		  /* Set offset according to the length of the argument's
+		     type (float or double).  */
+		  argoffset += len;
 		}
 	    }
 	  else if (TYPE_CODE (type) == TYPE_CODE_FLT

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