public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* m68k-elf return value registers
@ 2011-01-13 23:04 Vladimir Prus
  2011-01-14 11:00 ` Mark Kettenis
  0 siblings, 1 reply; 7+ messages in thread
From: Vladimir Prus @ 2011-01-13 23:04 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: Text/Plain, Size: 1331 bytes --]


This patch, originally written by Nathan Sidwel, makes m68k-tdep.c use right 
registrers for returning values from functions on bare metal. There are 
actually 3 parts:

1. Right now, it's assumed that pointer values are returned in %a0. However,
for m68k-elf, they are returned in %d0. So, this patch makes %a0 the default,
and then makes OSABI sniffers set %a0 again.

2. Structures can be returned in either %a0 or %a1. This was discussed 
previously at:

	http://thread.gmane.org/gmane.comp.gdb.devel/20117

I have now put together a table listing what register gcc uses, and how
gdb does the same with this patch. See:

	http://tinyurl.com/5r2j5x6

As you see, in the end we have only uclinuxoldeabi using wrong register
(just as now). I am not sure whether (i) this can be fixed, and (ii) anybody
care, given that this target was proposed for deprecation in gcc 4.6. Anyway,
if somebody cares, it can be done with a separate patch.

3. This patch also updates the logic that decides whether structure is 
returned in memory or registers. This is a black magic written by Nathan
that I don't pretend to understand.

Is this OK? I have tests still running, but they will only cover elf and 
linux, so it would be great to have somebody check behaviour for other
targets.


-- 
Vladimir Prus
Mentor Graphics
+7 (812) 677-68-40

[-- Attachment #2: m68k-return.diff --]
[-- Type: text/x-patch, Size: 8507 bytes --]

commit 45c4637b3cf602268bb69b9e7fc045d5cbb70d71
Author: Vladimir Prus <vladimir@codesourcery.com>
Date:   Fri Jan 14 00:10:12 2011 +0300

    Use the right structure and pointer return registers on m68k-elf.
    
    	* m68k-tdep.h (struct gdbarch_tdep): Add ptr_value_regnum
    	field.
    	* m68k-tdep.c (m68k_gdbarch_init): Use A0 for structure
    	returns on ELF targets, A1 otherwise.  Use %d0 for ptr_value_regnum.
    	(m68k_svr4_extract_return_value): Use
    	tdep->ptr_value_regnum for pointer returns.
    	(m68k_svr4_store_return_value): Likewise.
    	(m68k_reg_struct_return_r): New, broken out of ...
    	(m68k_reg_struct_return_p): ... here.  Implement gcc's structure
    	mode algorithm.
    	(m68k_svr4_init_abi): No need to specify %a0 for structure
    	returns here.  Set ptr_value_regnum, though.
    
    	* m68kbsd-tdep.c (m68kbsd_aout_init_abi): Set ptr_value_regnum to
    	A0.
    	(m68kbsd_elf_init_abi): Use A1 for struct return on OpenBSD.

diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index 082cb84..194ecf3 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -320,7 +320,7 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache,
       convert_typed_floating (buf, fpreg_type, valbuf, type);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
-    regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
+    regcache_raw_read (regcache, tdep->ptr_value_regnum, valbuf);
   else
     m68k_extract_return_value (type, regcache, valbuf);
 }
@@ -362,16 +362,77 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache,
       regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
-    {
-      regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
-      regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf);
-    }
+    regcache_raw_write (regcache, tdep->ptr_value_regnum, valbuf);
   else
     m68k_store_return_value (type, regcache, valbuf);
 }
 
 /* Return non-zero if TYPE, which is assumed to be a structure or
    union type, should be returned in registers for architecture
+   GDBARCH.
+
+   Unfortunately GCC incorrectly implements this optimization.  Rather
+   than simply return all small structs, or even just those of size
+   2^N, it uses the mode of the structure to determine this.  BLKmode
+   structs will be returned by memory and QI,HI,SI,DI,SF&DF mode
+   structs will be returned by register.  For m68k a struct is BLKmode
+   unless it's size is 2^N and the mode for that size does not need a
+   greater alignment than the structure itself.  This is horrible.  */
+
+
+static int
+m68k_reg_struct_return_r (struct type *type, int *align_p)
+{
+  enum type_code code = TYPE_CODE (type);
+  int len = TYPE_LENGTH (type);
+  int field_align = 1;
+  int my_align = len > 2 ? 2 : len;
+  int ix;
+
+  if (code != TYPE_CODE_STRUCT && code != TYPE_CODE_UNION)
+    {
+      if (align_p && my_align > *align_p)
+	*align_p = my_align;
+      return 1;
+    }
+
+  if ((len & -len) != len)
+    /* Length is not 2^n. */
+    return 0;
+
+  for (ix = 0; ix != TYPE_NFIELDS (type); ix++)
+    {
+      struct type *field_type;
+      int field_len;
+
+      if (field_is_static (&TYPE_FIELD (type, ix)))
+	/* Skip static fields.  */
+	continue;
+
+      field_type = TYPE_FIELD_TYPE (type, ix);
+      field_type = check_typedef (field_type);
+      field_len = TYPE_LENGTH (field_type);
+
+      /* Look through arrays.  */
+      while (TYPE_CODE (field_type) == TYPE_CODE_ARRAY)
+	{
+	  field_type = TYPE_TARGET_TYPE (field_type);
+	  field_type = check_typedef (field_type);
+	  field_len = TYPE_LENGTH (field_type);
+	}
+
+      if (!m68k_reg_struct_return_r (field_type, &field_align))
+	return 0;
+    }
+
+  if (align_p && field_align > *align_p)
+    *align_p = field_align;
+
+  return align_p || my_align <= field_align;
+}
+
+/* Return non-zero if TYPE, which is assumed to be a structure or
+   union type, should be returned in registers for architecture
    GDBARCH.  */
 
 static int
@@ -386,7 +447,11 @@ m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
   if (tdep->struct_return == pcc_struct_return)
     return 0;
 
-  return (len == 1 || len == 2 || len == 4 || len == 8);
+  if (len > 8)
+    /* Length is too big. */
+    return 0;
+
+  return m68k_reg_struct_return_r (type, NULL);
 }
 
 /* Determine, for architecture GDBARCH, how a return value of TYPE
@@ -440,25 +505,11 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type,
   if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
       && !m68k_reg_struct_return_p (gdbarch, type))
     {
-      /* The System V ABI says that:
-
-	 "A function returning a structure or union also sets %a0 to
-	 the value it finds in %a0.  Thus when the caller receives
-	 control again, the address of the returned object resides in
-	 register %a0."
-
-	 So the ABI guarantees that we can always find the return
-	 value just after the function has returned.  */
-
-      if (readbuf)
-	{
-	  ULONGEST addr;
-
-	  regcache_raw_read_unsigned (regcache, M68K_A0_REGNUM, &addr);
-	  read_memory (addr, readbuf, TYPE_LENGTH (type));
-	}
-
-      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+      /* Although they SYSV ABI specifies that a function returning a
+	 structure this way should preserve %a0, GCC doesn't do that.
+	 Furthermore there's no point changeing GCC to make it do it,
+	 as that would just be bloat. */
+      return RETURN_VALUE_STRUCT_CONVENTION;
     }
 
   /* This special case is for structures consisting of a single
@@ -1053,8 +1104,7 @@ m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* SVR4 uses a different calling convention.  */
   set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
 
-  /* SVR4 uses %a0 instead of %a1.  */
-  tdep->struct_value_regnum = M68K_A0_REGNUM;
+  tdep->ptr_value_regnum = M68K_A0_REGNUM;
 }
 \f
 
@@ -1228,7 +1278,17 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   /* Function call & return.  */
   set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
   set_gdbarch_return_value (gdbarch, m68k_return_value);
+  tdep->struct_return = reg_struct_return;
 
+  /* These register numbers may be overridden by an OSABI
+     sniffer.  */
+  if (info.abfd == NULL)
+    tdep->struct_value_regnum = M68K_A0_REGNUM;
+  else if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    tdep->struct_value_regnum = M68K_A0_REGNUM;
+  else
+    tdep->struct_value_regnum = M68K_A1_REGNUM;
+  tdep->ptr_value_regnum = M68K_D0_REGNUM;
 
   /* Disassembler.  */
   set_gdbarch_print_insn (gdbarch, print_insn_m68k);
@@ -1239,8 +1299,6 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 #else
   tdep->jb_pc = -1;
 #endif
-  tdep->struct_value_regnum = M68K_A1_REGNUM;
-  tdep->struct_return = reg_struct_return;
 
   /* Frame unwinder.  */
   set_gdbarch_dummy_id (gdbarch, m68k_dummy_id);
diff --git a/gdb/m68k-tdep.h b/gdb/m68k-tdep.h
index 596a8cb..3ea7f24 100644
--- a/gdb/m68k-tdep.h
+++ b/gdb/m68k-tdep.h
@@ -83,6 +83,9 @@ struct gdbarch_tdep
   /* Convention for returning structures.  */
   enum struct_return struct_return;
 
+  /* Register in which pointers are returned.  */
+  int ptr_value_regnum;
+
   /* Convention for returning floats.  zero in int regs, non-zero in float.  */
   int float_return;
 
diff --git a/gdb/m68kbsd-tdep.c b/gdb/m68kbsd-tdep.c
index 81e34e9..f5bfa1a 100644
--- a/gdb/m68kbsd-tdep.c
+++ b/gdb/m68kbsd-tdep.c
@@ -213,11 +213,12 @@ m68kbsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   m68kbsd_init_abi (info, gdbarch);
 
   tdep->struct_return = reg_struct_return;
+  tdep->ptr_value_regnum = M68K_A0_REGNUM;
 
   tramp_frame_prepend_unwinder (gdbarch, &m68kobsd_sigtramp);
 }
 
-/* NetBSD ELF.  */
+/* OpenBSD and NetBSD ELF.  */
 
 static void
 m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -233,6 +234,15 @@ m68kbsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* NetBSD ELF uses SVR4-style shared libraries.  */
   set_solib_svr4_fetch_link_map_offsets
     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
+  /* OpenBSD uses %a1to return structures.  */
+  if (info.abfd)
+    {
+      enum gdb_osabi osabi = gdbarch_lookup_osabi (info.abfd);
+
+      if (osabi == GDB_OSABI_OPENBSD_ELF)
+	tdep->struct_value_regnum = M68K_A1_REGNUM;
+    }
 }
 \f
 

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-06-11 18:50 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-13 23:04 m68k-elf return value registers Vladimir Prus
2011-01-14 11:00 ` Mark Kettenis
2011-01-25 17:01   ` Vladimir Prus
2011-04-26 11:37     ` Vladimir Prus
2011-06-11 18:50       ` Vladimir Prus
2011-04-26 11:50     ` Vladimir Prus
2011-04-26 11:58     ` Vladimir Prus

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 read-only IMAP folder(s) and NNTP newsgroup(s).