This is the mail archive of the gdb-patches@sources.redhat.com 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: SH follow up, part 2 (was Re: [RFA] sh-tdep.c: Follow up patch to implement two different ABIs)


Corinna Vinschen writes:
 > On Tue, Sep 23, 2003 at 04:44:03PM -0400, Elena Zannoni wrote:
 > > Corinna Vinschen writes:
 > 
 > And now part 2.
 > 
 > >  > - Add the commands `set calling_convention <foo>' and
 > >  >   `show calling_convention' with <foo> being one of "gcc" and "renesas".
 > >  >   Default to "gcc".
 > > 
 > > Should be using hyphen, not underscore.  What happens if you have a
 > 
 > Done.  I followed Andrew's suggestion to change this to
 > 
 >   set sh calling-convention ...
 >   show sh calling-convention
 > 
 > > file compiled with renesas ABI but you set the calling convention to
 > > the gcc (or vice versa)?  How are the abi supported by gcc? Is there a
 > > -with-abi-renesas to be given when one compiles the tests? I.e. is it
 > > possible to run the testsuite with the one specific abi?
 > 
 > Currently there's no way to differ between these two ABIs automatically
 > though that might change at some later point.  The user has to change
 > the ABI on the command line by hand.  The compiler option was -mhitachi,
 > gcc is just changing to -mrenesas to reflect the company name change.


Hmm but then the user can set the calling convention to the wrong one.
Also the finish command, I am afraid, will be confused. There should
be something detecting the calling convention from the executable. Is
the info recorded in the file anywhere? I.e. would readelf/objdump
show it?

 > 
 > So the changes introduced with this patch are:
 > 
 > - Differ between a fpu and a nofpu version of sh_use_struct_convention.
 >   The nofpu version behaves like the fpu version, except that it uses
 >   struct convention also for all types >= 8 bytes when the Renesas ABI
 >   is active.  This especially affects long longs and doubles which are
 >   then passed on the stack.
 > 
 > - The Renesas ABI passes the address in which structs have to be returned
 >   not in r2 as the gcc ABI, but instead this return address is pushed
 >   onto the stack after all arguments have been pushed.  This affects
 >   sh_extract_struct_value_address() as well as the sh_push_dummy_call*()
 >   functions.
 > 
 > - sh_next_flt_argreg() now also takes the ABI into account.  The differences
 >   are:
 > 
 >   - In Renesas ABI, the criss-crossing register usage in little endian
 >     mode for doubles doesn't happen.
 > 
 >   - In both ABIs doubles are passed in even register pairs, fr4/fr5,
 >     fr6/fr7, ...  The difference is when a register is skipped to pass
 >     the next double.  Example:
 > 
 >       void foo(float a, double b, float c);
 > 
 >     In gcc ABI, a is passed in fr4, b then skips the odd-numbered fr5
 >     register, so it's passed in fr6/fr7 and c is then passed in the next
 >     free register, fr8.
 > 
 >     In Renesas ABI, a is passed in fr4, b is passed as in gcc ABI in
 >     fr6/fr7 but c is passed in the lowest unused register, in this example
 >     in fr5.
 > 
 > - In the Renesas ABI for CPUs with FPU, long longs are not passed in
 >   registers but on stack.
 > 
 > - The struct_return code in both sh_push_dummy_call*() functions is moved
 >   to the end of the function since it must be done after the argument
 >   passing for the Rensas ABI.
 > 
 > - `pass_on_stack' takes the Renesas ABI into account:
 > 
 >   - On FPU CPUs, Renesas ABI passes long longs always on the stack.
 > 
 >   - On non-FPU CPUs, Renesas ABI passes doubles and long doubles always
 >     on the stack.
 > 

These descriptions should be comments in the file, the more verbiage
the better.

I don't have anything in particular against these patches, but I'd like
to have a better idea about how to solve this calling convention issue
before the changes go in.

elena


 > Corinna
 > 
 > 
 > ChangeLog:
 > ==========
 > 
 > 	* sh-tdep.c (sh_cc_gcc): New static string.
 > 	(sh_cc_renesas): Ditto.
 > 	(sh_cc_enum): New array pointing to calling convention strings.
 > 	(sh_active_calling_convention): New variable pointing to
 > 	current active calling convention.
 > 	(sh_use_struct_convention_fpu): New function.
 > 	(sh_use_struct_convention_nofpu): New function.
 > 	(sh_use_struct_convention): Remove.  Superseeded by the previous
 > 	two functions.
 > 	(sh_extract_struct_value_address): Care for Renesas ABI.
 > 	(sh_next_flt_argreg): Accomodate Renesas ABI.
 > 	(sh_push_dummy_call_fpu): Ditto.
 > 	(sh_push_dummy_call_nofpu): Ditto.
 > 	(sh_gdbarch_init): Accomodate new sh_use_struct_convention_fpu and
 > 	sh_use_struct_convention_nofpu functions.
 > 	(show_sh_command): New function.
 > 	(set_sh_command): New function.
 > 	(_initialize_sh_tdep): Initialize new "set sh calling-convention",
 > 	"show sh calling-convention" commands.
 > 
 > --- sh-tdep.c.MIDNEW	2003-09-24 12:01:46.000000000 +0200
 > +++ sh-tdep.c.NEW	2003-09-24 12:24:10.000000000 +0200
 > @@ -55,6 +55,21 @@
 >  /* registers numbers shared with the simulator */
 >  #include "gdb/sim-sh.h"
 >  
 > +/* List of "set sh ..." and "show sh ..." commands.  */
 > +static struct cmd_list_element *setshcmdlist = NULL;
 > +static struct cmd_list_element *showshcmdlist = NULL;
 > +
 > +static const char sh_cc_gcc[] = "gcc";
 > +static const char sh_cc_renesas[] = "renesas";
 > +static const char *sh_cc_enum[] =
 > +{
 > +  sh_cc_gcc,
 > +  sh_cc_renesas,
 > +  NULL
 > +};
 > +
 > +static const char *sh_active_calling_convention = sh_cc_gcc;
 > +
 >  static void (*sh_show_regs) (void);
 >  
 >  #define SH_NUM_REGS 59
 > @@ -569,10 +584,25 @@ sh_skip_prologue (CORE_ADDR start_pc)
 >  
 >  /* Should call_function allocate stack space for a struct return?  */
 >  static int
 > -sh_use_struct_convention (int gcc_p, struct type *type)
 > +sh_use_struct_convention_fpu (int gcc_p, struct type *type)
 >  {
 >    int len = TYPE_LENGTH (type);
 >    int nelem = TYPE_NFIELDS (type);
 > +
 > +  return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
 > +	  (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
 > +}
 > +
 > +static int
 > +sh_use_struct_convention_nofpu (int gcc_p, struct type *type)
 > +{
 > +  int len = TYPE_LENGTH (type);
 > +  int nelem = TYPE_NFIELDS (type);
 > +
 > +  /* The Renesas ABI returns long longs/doubles etc.  always on stack. */
 > +  if (sh_active_calling_convention == sh_cc_renesas && len >= 8)
 > +    return 1;
 > +
 >    return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
 >  	  (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
 >  }
 > @@ -584,8 +614,13 @@ static CORE_ADDR
 >  sh_extract_struct_value_address (struct regcache *regcache)
 >  {
 >    ULONGEST addr;
 > -
 > -  regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
 > +  if (sh_active_calling_convention != sh_cc_renesas)
 > +    regcache_cooked_read_unsigned (regcache, STRUCT_RETURN_REGNUM, &addr);
 > +  else
 > +    {
 > +      regcache_cooked_read_unsigned (regcache, SP_REGNUM, &addr);
 > +      addr = read_memory_unsigned_integer (addr, 4);
 > +    }
 >    return addr;
 >  }
 >  
 > @@ -653,7 +688,7 @@ sh_justify_value_in_reg (struct value *v
 >  {
 >    static char valbuf[4];
 >  
 > -  memset (valbuf, 0, sizeof (valbuf)); 
 > +  memset (valbuf, 0, sizeof (valbuf));
 >    if (len < 4)
 >      {
 >        /* value gets right-justified in the register or stack word */
 > @@ -664,7 +699,7 @@ sh_justify_value_in_reg (struct value *v
 >        return valbuf;
 >      }
 >    return (char *) VALUE_CONTENTS (val);
 > -} 
 > +}
 >  
 >  /* Helper function to eval number of bytes to allocate on stack. */
 >  static CORE_ADDR
 > @@ -718,18 +753,22 @@ sh_next_flt_argreg (int len)
 >        /* Doubles are always starting in a even register number. */
 >        if (argreg & 1)
 >          {
 > -	  flt_argreg_array[argreg] = 1;
 > +	  /* In gcc ABI, the skipped register is lost for further argument
 > +	     passing now.  Not so in Renesas ABI. */
 > +	  if (sh_active_calling_convention != sh_cc_renesas)
 > +	    flt_argreg_array[argreg] = 1;
 >  
 >  	  ++argreg;
 >  
 > -          /* No register left? */
 > +	  /* No register left? */
 >  	  if (argreg > FLOAT_ARGLAST_REGNUM - FLOAT_ARG0_REGNUM)
 >  	    return FLOAT_ARGLAST_REGNUM + 1;
 >  	}
 >        /* Also mark the next register as used. */
 >        flt_argreg_array[argreg + 1] = 1;
 >      }
 > -  else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
 > +  else if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
 > +	   && sh_active_calling_convention != sh_cc_renesas)
 >      {
 >        /* In little endian, gcc passes floats like this: f5, f4, f7, f6, ... */
 >        if (!flt_argreg_array[argreg + 1])
 > @@ -761,13 +800,6 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >    /* first force sp to a 4-byte alignment */
 >    sp = sh_frame_align (gdbarch, sp);
 >  
 > -  /* The "struct return pointer" pseudo-argument has its own dedicated 
 > -     register */
 > -  if (struct_return)
 > -    regcache_cooked_write_unsigned (regcache, 
 > -				    STRUCT_RETURN_REGNUM, 
 > -				    struct_addr);
 > -
 >    /* make room on stack for args */
 >    sp -= sh_stack_allocsize (nargs, args);
 >  
 > @@ -787,7 +819,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >           This also differs in different ABIs. */
 >        pass_on_stack = 0;
 >        if (len > 16)
 > -        pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
 > +	pass_on_stack = 1; /* Types bigger than 16 bytes are passed on stack. */
 > +      else if (sh_active_calling_convention == sh_cc_renesas
 > +	       && TYPE_CODE (type) == TYPE_CODE_INT && len == 8)
 > +	pass_on_stack = 1; /* So are long longs in renesas ABI */
 >  
 >        /* Find out the next register to use for a floating point value. */
 >        if (TYPE_CODE (type) == TYPE_CODE_FLT)
 > @@ -796,10 +831,10 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >        while (len > 0)
 >  	{
 >  	  if ((TYPE_CODE (type) == TYPE_CODE_FLT 
 > -	       && flt_argreg > FLOAT_ARGLAST_REGNUM)
 > +	       && flt_argreg > FLOAT_ARGLAST_REGNUM) 
 >  	      || argreg > ARGLAST_REGNUM
 >  	      || pass_on_stack)
 > -	    {                    
 > +	    {			
 >  	      write_memory (sp + stack_offset, val, 4);
 >  	      stack_offset += 4;
 >  	    }
 > @@ -812,7 +847,7 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  	      regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
 >  	    }
 >  	  else if (argreg <= ARGLAST_REGNUM)
 > -	    {
 > +	    {			
 >  	      /* there's room in a register */
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 > @@ -826,6 +861,20 @@ sh_push_dummy_call_fpu (struct gdbarch *
 >  	}
 >      }
 >  
 > +  if (struct_return)
 > +    {
 > +      if (sh_active_calling_convention != sh_cc_renesas)
 > +	/* Using the gcc ABI, the "struct return pointer" pseudo-argument has
 > +	   its own dedicated register */
 > +	regcache_cooked_write_unsigned (regcache,
 > +					STRUCT_RETURN_REGNUM,
 > +					struct_addr);
 > +      else
 > +	/* If the function uses the renesas ABI, subtract another 4 bytes from
 > +	   the stack and store the struct return address there. */
 > +	write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
 > +    }
 > +
 >    /* Store return address. */
 >    regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
 >  
 > @@ -851,17 +900,11 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >    CORE_ADDR regval;
 >    char *val;
 >    int len;
 > +  int pass_on_stack;
 >  
 >    /* first force sp to a 4-byte alignment */
 >    sp = sh_frame_align (gdbarch, sp);
 >  
 > -  /* The "struct return pointer" pseudo-argument has its own dedicated 
 > -     register */
 > -  if (struct_return)
 > -    regcache_cooked_write_unsigned (regcache,
 > -				    STRUCT_RETURN_REGNUM,
 > -				    struct_addr);
 > -
 >    /* make room on stack for args */
 >    sp -= sh_stack_allocsize (nargs, args);
 >  
 > @@ -869,20 +912,27 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >       registers, and push the rest onto the stack.  There are 16 bytes
 >       in four registers available.  Loop thru args from first to last.  */
 >    for (argnum = 0; argnum < nargs; argnum++)
 > -    { 
 > +    {
 >        type = VALUE_TYPE (args[argnum]);
 >        len = TYPE_LENGTH (type);
 >        val = sh_justify_value_in_reg (args[argnum], len);
 >  
 > +      /* Some decisions have to be made how various types are handled.
 > +         This also differs in different ABIs. */
 > +      pass_on_stack = 0;
 > +      if (TYPE_CODE (type) == TYPE_CODE_FLT && len > 4
 > +	  && sh_active_calling_convention == sh_cc_renesas)
 > +	pass_on_stack = 1; /* Renesas ABI pushes doubles entirely on stack. */
 > +
 >        while (len > 0)
 >  	{
 > -	  if (argreg > ARGLAST_REGNUM)
 > -	    {                   
 > +	  if (argreg > ARGLAST_REGNUM || pass_on_stack)
 > +	    {			
 >  	      write_memory (sp + stack_offset, val, 4);
 > -	      stack_offset += 4; 
 > +	      stack_offset += 4;
 >  	    }
 >  	  else if (argreg <= ARGLAST_REGNUM)
 > -	    {                   
 > +	    {			
 >  	      /* there's room in a register */
 >  	      regval = extract_unsigned_integer (val, register_size (gdbarch,
 >  								     argreg));
 > @@ -896,6 +946,20 @@ sh_push_dummy_call_nofpu (struct gdbarch
 >  	}
 >      }
 >  
 > +  if (struct_return)
 > +    {
 > +      if (sh_active_calling_convention != sh_cc_renesas)
 > +	/* Using the gcc ABI, the "struct return pointer" pseudo-argument has
 > +	   its own dedicated register */
 > +	regcache_cooked_write_unsigned (regcache,
 > +					STRUCT_RETURN_REGNUM,
 > +					struct_addr);
 > +      else
 > +	/* If the function uses the renesas ABI, subtract another 4 bytes from
 > +	   the stack and store the struct return address there. */
 > +	write_memory_unsigned_integer (sp -= 4, 4, struct_addr);
 > +    }
 > +
 >    /* Store return address. */
 >    regcache_cooked_write_unsigned (regcache, PR_REGNUM, bp_addr);
 >  
 > @@ -2115,7 +2179,6 @@ sh_gdbarch_init (struct gdbarch_info inf
 >    set_gdbarch_print_registers_info (gdbarch, sh_print_registers_info);
 >  
 >    set_gdbarch_breakpoint_from_pc (gdbarch, sh_breakpoint_from_pc);
 > -  set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention);
 >  
 >    set_gdbarch_print_insn (gdbarch, gdb_print_insn_sh);
 >    set_gdbarch_register_sim_regno (gdbarch, legacy_register_sim_regno);
 > @@ -2134,6 +2197,7 @@ sh_gdbarch_init (struct gdbarch_info inf
 >  
 >    set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
 >    set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
 > +  set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_nofpu);
 >  
 >    set_gdbarch_frame_args_skip (gdbarch, 0);
 >    set_gdbarch_frameless_function_invocation (gdbarch,
 > @@ -2169,6 +2233,7 @@ sh_gdbarch_init (struct gdbarch_info inf
 >        set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
 >        set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
 >        set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
 > +      set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
 >        break;
 >  
 >      case bfd_mach_sh_dsp:
 > @@ -2190,6 +2255,7 @@ sh_gdbarch_init (struct gdbarch_info inf
 >        set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
 >        set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
 >        set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
 > +      set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
 >        break;
 >  
 >      case bfd_mach_sh3_dsp:
 > @@ -2207,6 +2273,7 @@ sh_gdbarch_init (struct gdbarch_info inf
 >        set_gdbarch_store_return_value (gdbarch, sh3e_sh4_store_return_value);
 >        set_gdbarch_extract_return_value (gdbarch, sh3e_sh4_extract_return_value);
 >        set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
 > +      set_gdbarch_use_struct_convention (gdbarch, sh_use_struct_convention_fpu);
 >        break;
 >  
 >      default:
 > @@ -2223,6 +2290,19 @@ sh_gdbarch_init (struct gdbarch_info inf
 >    return gdbarch;
 >  }
 >  
 > +static void
 > +show_sh_command (char *args, int from_tty)
 > +{
 > +  help_list (showshcmdlist, "show sh ", all_commands, gdb_stdout);
 > +}
 > +
 > +static void
 > +set_sh_command (char *args, int from_tty)
 > +{
 > +  printf_unfiltered ("\"set sh\" must be followed by an appropriate subcommand.\n");
 > +  help_list (setshcmdlist, "set sh ", all_commands, gdb_stdout);
 > +}
 > +
 >  extern initialize_file_ftype _initialize_sh_tdep; /* -Wmissing-prototypes */
 >  
 >  void
 > @@ -2233,4 +2313,16 @@ _initialize_sh_tdep (void)
 >    gdbarch_register (bfd_arch_sh, sh_gdbarch_init, NULL);
 >  
 >    add_com ("regs", class_vars, sh_show_regs_command, "Print all registers");
 > +
 > +  add_prefix_cmd ("sh", no_class, set_sh_command, "SH specific commands.",
 > +		  &setshcmdlist, "set sh ", 0, &setlist);
 > +  add_prefix_cmd ("sh", no_class, show_sh_command, "SH specific commands.",
 > +		  &showshcmdlist, "show sh ", 0, &showlist);
 > +
 > +  add_show_from_set (
 > +    add_set_enum_cmd ("calling-convention", class_vars, sh_cc_enum,
 > +		      &sh_active_calling_convention,
 > +		      "Set calling convention used when calling target "
 > +		      "functions from GDB.",
 > +		      &setshcmdlist), &showshcmdlist);
 >  }
 > 
 > -- 
 > Corinna Vinschen
 > Cygwin Developer
 > Red Hat, Inc.


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