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]

[RFA/commit 3/3] amd64: 32 bytes allocated on stack by caller for integer parameter registers.


From: brobecke <brobecke@f8352e7e-cb20-0410-8ce7-b5d9e71c585c>

Yet another difference between Linux and Windows in the calling convention.
When calling a function, the caller is responsible for allocating
a 32byte memory region in the caller's frame; the callee can use
this region to spill the 4 registers used for INTEGER parameter passing.

It showed up when trying to call a function that takes a string as a
parameter, but could probably show up anywhere the INTEGER registers
are being used.  This depends on the actual implementation of the
function being called. In all likeliness, the larger the function,
the more chances the registers used for parameter passing are going
to be needed, and thus need to be spilled on stack.

This patch enhances amd64_push_dummy_call allowing it to also allocated
this spaces on the stack if the ABI mandates it.  Whether it is required
or not is determined by the value of a new tdep field:
integer_param_regs_saved_in_caller_frame.  The default value is zero,
and amd64-windows-tdep.c sets it to 1.

gdb/ChangeLog:

    * i386-tdep.h (struct gdbarch_tdep): Add new field
    integer_param_regs_saved_in_caller_frame.
    * amd64-windows-tdep.c (amd64_windows_init_abi): Set
    tdep->integer_param_regs_saved_in_caller_frame to 1.
    * amd64-tdep.c (amd64_push_dummy_call): Allocate some memory on
    stack if tdep->integer_param_regs_saved_in_caller_frame is set.

I can submit the exact testcase that allowed us to spot this problem.
But I think that gdb.ada/arrayparam.exp already covers this issue.

-- 
Joel

---
 gdb/amd64-tdep.c         |    6 ++++++
 gdb/amd64-windows-tdep.c |    1 +
 gdb/i386-tdep.h          |   18 ++++++++++++++----
 3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index e9e0809..2b15141 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -731,6 +731,7 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 		       int struct_return, CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   gdb_byte buf[8];
 
   /* Pass arguments.  */
@@ -748,6 +749,11 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       regcache_cooked_write (regcache, arg_regnum, buf);
     }
 
+  /* Reserve some memory on the stack for the integer-parameter registers,
+     if required by the ABI.  */
+  if (tdep->integer_param_regs_saved_in_caller_frame)
+    sp -= tdep->call_dummy_num_integer_regs * 8;
+
   /* Store return address.  */
   sp -= 8;
   store_unsigned_integer (buf, 8, byte_order, bp_addr);
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 0ed9368..05c4c1e 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -84,6 +84,7 @@ amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->call_dummy_integer_regs = amd64_windows_dummy_call_integer_regs;
   tdep->classify = amd64_windows_classify;
   tdep->memory_args_by_pointer = 1;
+  tdep->integer_param_regs_saved_in_caller_frame = 1;
 
   set_solib_ops (gdbarch, &solib_target_so_ops);
 }
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index f79a15d..5915eb9 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -82,12 +82,12 @@ struct gdbarch_tdep
   int call_dummy_num_integer_regs;
   int *call_dummy_integer_regs;
 
-  /* Classify TYPE according to calling conventions, and store
-     the result in CLASS.  Used on amd64 only.  */
+  /* Used on amd64 only.  Classify TYPE according to calling conventions,
+     and store the result in CLASS.  */
   void (*classify) (struct type *type, enum amd64_reg_class class[2]);
 
-  /* Non-zero if the first few MEMORY arguments should be passed by
-     pointer.
+  /* Used on amd64 only.  Non-zero if the first few MEMORY arguments
+     should be passed by pointer.
 
      More precisely, MEMORY arguments are passed through the stack.
      But certain architectures require that their address be passed
@@ -95,6 +95,16 @@ struct gdbarch_tdep
      available for argument passing.  */
   int memory_args_by_pointer;
 
+  /* Used on amd64 only.
+
+     If non-zero, then the callers of a function are expected to reserve
+     some space in the stack just before the area where the PC is saved
+     so that the callee may save the integer-parameter registers there.
+     The amount of space is dependent on the list of registers used for
+     integer parameter passing (see component call_dummy_num_integer_regs
+     above).  */
+  int integer_param_regs_saved_in_caller_frame;
+
   /* Floating-point registers.  */
   struct regset *fpregset;
   size_t sizeof_fpregset;
-- 
1.6.3.3


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