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]

m68k-elf return value registers


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
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;
 }
 
 
@@ -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;
+    }
 }
 
 

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