diff options
author | Joseph Myers <joseph@codesourcery.com> | 2008-06-27 16:22:56 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2008-06-27 16:22:56 +0000 |
commit | 7ccc1c74d815b3b3a8bae8afb5f4eacb438b29c5 (patch) | |
tree | bc08f5cb189441ba4548537ced48797162767705 /gdb/i386-tdep.c | |
parent | db42f210256e79f3fa409b73e217d870989ce6cd (diff) | |
download | gdb-7ccc1c74d815b3b3a8bae8afb5f4eacb438b29c5.zip gdb-7ccc1c74d815b3b3a8bae8afb5f4eacb438b29c5.tar.gz gdb-7ccc1c74d815b3b3a8bae8afb5f4eacb438b29c5.tar.bz2 |
* i386-tdep.c (i386_16_byte_align_p): New.
(i386_push_dummy_call): Determine stack space required for
arguments going forwards allowing for 16-byte alignment, then push
arguments going forwards.
Diffstat (limited to 'gdb/i386-tdep.c')
-rw-r--r-- | gdb/i386-tdep.c | 101 |
1 files changed, 84 insertions, 17 deletions
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 91bd7d0..9dced32 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -1521,6 +1521,34 @@ i386_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) } +/* Check whether TYPE must be 16-byte-aligned when passed as a + function argument. 16-byte vectors, _Decimal128 and structures or + unions containing such types must be 16-byte-aligned; other + arguments are 4-byte-aligned. */ + +static int +i386_16_byte_align_p (struct type *type) +{ + type = check_typedef (type); + if ((TYPE_CODE (type) == TYPE_CODE_DECFLOAT + || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))) + && TYPE_LENGTH (type) == 16) + return 1; + if (TYPE_CODE (type) == TYPE_CODE_ARRAY) + return i386_16_byte_align_p (TYPE_TARGET_TYPE (type)); + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION) + { + int i; + for (i = 0; i < TYPE_NFIELDS (type); i++) + { + if (i386_16_byte_align_p (TYPE_FIELD_TYPE (type, i))) + return 1; + } + } + return 0; +} + static CORE_ADDR i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, @@ -1529,29 +1557,68 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function, { gdb_byte buf[4]; int i; + int write_pass; + int args_space = 0; - /* Push arguments in reverse order. */ - for (i = nargs - 1; i >= 0; i--) + /* Determine the total space required for arguments and struct + return address in a first pass (allowing for 16-byte-aligned + arguments), then push arguments in a second pass. */ + + for (write_pass = 0; write_pass < 2; write_pass++) { - int len = TYPE_LENGTH (value_enclosing_type (args[i])); + int args_space_used = 0; + int have_16_byte_aligned_arg = 0; - /* The System V ABI says that: + if (struct_return) + { + if (write_pass) + { + /* Push value address. */ + store_unsigned_integer (buf, 4, struct_addr); + write_memory (sp, buf, 4); + args_space_used += 4; + } + else + args_space += 4; + } - "An argument's size is increased, if necessary, to make it a - multiple of [32-bit] words. This may require tail padding, - depending on the size of the argument." + for (i = 0; i < nargs; i++) + { + int len = TYPE_LENGTH (value_enclosing_type (args[i])); - This makes sure the stack stays word-aligned. */ - sp -= (len + 3) & ~3; - write_memory (sp, value_contents_all (args[i]), len); - } + if (write_pass) + { + if (i386_16_byte_align_p (value_enclosing_type (args[i]))) + args_space_used = align_up (args_space_used, 16); - /* Push value address. */ - if (struct_return) - { - sp -= 4; - store_unsigned_integer (buf, 4, struct_addr); - write_memory (sp, buf, 4); + write_memory (sp + args_space_used, + value_contents_all (args[i]), len); + /* The System V ABI says that: + + "An argument's size is increased, if necessary, to make it a + multiple of [32-bit] words. This may require tail padding, + depending on the size of the argument." + + This makes sure the stack stays word-aligned. */ + args_space_used += align_up (len, 4); + } + else + { + if (i386_16_byte_align_p (value_enclosing_type (args[i]))) + { + args_space = align_up (args_space, 16); + have_16_byte_aligned_arg = 1; + } + args_space += align_up (len, 4); + } + } + + if (!write_pass) + { + if (have_16_byte_aligned_arg) + args_space = align_up (args_space, 16); + sp -= args_space; + } } /* Store return address. */ |