This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
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.