Age | Commit message (Collapse) | Author | Files | Lines |
|
The following amd64 insn:
...
0: 67 d5 44 8d 3d 00 00 00 00 lea 0x0(%eip),%r31d
...
uses the REX2 prefix [1], which is currently not supported in
amd64_get_insn_details.
Add the missing support in amd64_get_insn_details, as well as a corresponding
unit test.
Likewise for an amd64 insn using an EVEX prefix [2]:
...
0: 62 f1 7c 48 28 05 00 fc ff ff vmovaps -0x400(%rip),%zmm0
...
Tested on x86_64-linux.
PR tdep/32725
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32725
[1] https://en.wikipedia.org/wiki/VEX_prefix
[2] https://en.wikipedia.org/wiki/EVEX_prefix
|
|
PR tdep/31952 reports that displaced stepping over an instruction pointer
relative insn "vmovdqu 0x20(%rip),%ymm1" gives the wrong results.
This is caused by misclassification of the insn in amd64_get_insn_details,
which results in details.modrm_offset == -1, while the instruction in fact
does have a modrm byte.
The instruction is encoded as follows:
...
400557: c5 fe 6f 0d 20 00 00 00 vmovdqu 0x20(%rip),%ymm1
...
where:
- "0xc5 0xfe" is the vex2 prefix,
- "0x6f" is the opcode,
- "0x0d" is the modrm byte, and
- "0x20 0x00 0x00 0x00" is a 32-bit displacement.
The problem is related to details.opcode_len, which is 1.
While it is true that the length of the opcode in the insn (0x6f) is 1 byte,
the vex2 prefix implies that we're encoding an 2-byte opcode beginnning
with 0x0f [1].
Consequently, we should be using the twobyte_has_modrm map rather than the
onebyte_has_modrm map.
Fix this in amd64_get_insn_details, and add a selftest to check this.
Tested on x86_64-linux.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31952
[1] https://en.wikipedia.org/wiki/VEX_prefix
|
|
In amd64_get_insn_details, I found this code with a comment explaining why
enc_prefix_offset is not set:
...
else if (vex2_prefix_p (*insn))
{
/* Don't record the offset in this case because this prefix has
no REX.B equivalent. */
insn += 2;
}
...
which I didn't understand until I looked at the only use of enc_prefix_offset,
in fixup_riprel:
...
/* REX.B should be unset (VEX.!B set) as we were using rip-relative
addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
is not r8-r15. */
if (insn_details->enc_prefix_offset != -1)
{
gdb_byte *pfx = &dsc->insn_buf[insn_details->enc_prefix_offset];
if (rex_prefix_p (pfx[0]))
pfx[0] &= ~REX_B;
else if (vex3_prefix_p (pfx[0]))
pfx[1] |= VEX3_NOT_B;
else
gdb_assert_not_reached ("unhandled prefix");
}
...
Fix this by:
- setting enc_prefix_offset for the vex2 case in amd64_get_insn_details,
making the function more regular and easier to understand, and
- handling the vex2 case in the "enc_prefix_offset != -1" clause in
fixup_riprel.
Tested on x86_64-linux.
|
|
After I posted a tentative patch for PR31952, Alexander Monakov pointed out
that the patch broke instruction decoding for instructions vzeroall and
vzeroupper.
Add selftests for these two instructions in amd64-insn-decode, both using
vex2 and vex3 prefixes.
Tested on x86_64-linux.
|
|
I noticed here [1] that the vex2 prefix is essentially a special case of the
vex3 prefix, meaning it's possible to rewrite any insn with a vex2 prefix into
an equivalent one with a vex3 prefix.
Add function vex2_to_vex3 that does precisely that, in the selftests
namespace.
Add a selftest that exercises this function.
Tested on x86_64-linux.
[1] https://en.wikipedia.org/wiki/VEX_prefix
|
|
Factor out the part of fixup_riprel that patches the insn, and use it in a
unit test.
Tested on x86_64-linux.
|
|
I wanted to add a unit test for an an rip-relative amd64 insn, so I did:
...
$ gcc -fPIE hello.c
...
and used an rip-relative insn from main:
...
4005db: 48 8d 3d 1e 00 00 00 lea 0x1e(%rip),%rdi
...
While writing the unit test, I found that amd64_get_used_input_int_reg returns
rbp as input register.
Fix this by using rip_relative_p in amd64_get_used_input_int_reg to handle
this case.
Tested on x86_64-linux.
|
|
Factor out rip_relative_p, and rewrite it to use MODRM_MOD_FIELD and
MODRM_RM_FIELD.
No functional changes.
Tested on x86_64-linux.
|
|
Add a selftest that checks the results of amd64_get_insn_details and related
functions for two basic instructions.
Add a parameter assumptions to amd64_get_used_input_int_regs, to make sure
that this selftest:
...
/* INSN: add %eax,(%rcx). */
...
SELF_CHECK (amd64_get_used_input_int_regs (&details, false)
== ((1 << EAX_REG_NUM) | (1 << ECX_REG_NUM)));
...
passes because it found the "%eax" in the insn, rather than passing because of
this assumption:
...
/* Assume RAX is used. If not, we'd have to detect opcodes that implicitly
use RAX. */
used_regs_mask |= 1 << EAX_REG_NUM;
...
Tested on x86_64-linux.
|
|
The function amd64_get_unused_input_int_reg consists of two parts:
- finding the used int registers in an insn, and
- picking an unused int register.
Factor out the first part as new function amd64_get_used_input_int_regs.
No functional changes.
Tested on x86_64-linux.
|
|
While reading amd64_get_unused_input_int_reg, I noticed that it avoids picking
RSP, which has to do with how the result of the only call to it is going to be
used.
Likewise for picking a register in the RAX ... RDI range.
Fix this by:
- adding an allowed_regs_mask parameter to amd64_get_unused_input_int_reg, and
- properly documenting the value of the corresponding argument in fixup_riprel.
No functional changes.
Tested on x86_64-linux.
|
|
I noticed that amd64_get_unused_input_int_reg uses a signed int for a bit
mask:
...
/* 1 bit for each reg */
int used_regs_mask = 0;
...
There's an assert:
...
gdb_assert (used_regs_mask < 256);
...
which is meant to assert on register numbers >= 8, but if for instance
sizeof (used_regs_mask) == 4 and used_regs_mask == (1 << 31), then that is not
caught because of the signedness.
We could fix this by changing the type to unsigned int, but that only
guarantees 16 bits in the reg mask. Intel CPUs with the APX extension support
32 int registers.
The implementation of amd64_get_unused_input_int_reg doesn't support analyzing
registers with register number >= 8 yet, but now that we're changing the type,
it seems like a good idea to anticipate this.
Fix this by using uint32_t.
Likewise, update the loop over the reg mask:
...
for (i = 0; i < 8; ++i)
{
if (! (used_regs_mask & (1 << i)))
return i;
...
to handle any used_regs_mask value rather than just those for
register number < 8.
Tested on x86_64-linux.
|
|
While reading amd64_get_unused_input_int_reg, I noticed that it first asserts,
then throws an internal_error if no unused register can be found.
Looking at the documentation of gdbarch_displaced_step_copy_insn, it seems
that a failure can be indicated less abruptly, by returning a nullptr.
Fix this by:
- returning -1 in case of failure to find an unused register in
amd64_get_unused_input_int_reg, and
- propagating this to amd64_displaced_step_copy_insn.
Tested on x86_64-linux.
|
|
PR gas/32721
In this bogus piece of code distilled from fuzzing and slightly edited:
A=%eax|%!
Y=A
Z=A
or $6,Z
the first of the equates with A on the rhs changes A's section (due to
the use of S_GET_VALUE()), from expression to register, thus yielding Y
in the expression section (and X_op being O_symbol), but Z in the
register section (and X_op being O_register with X_add_value being -1).
There shouldn't be random O_register expressions, though, for targets
setting md_register_arithmetic to false. Plus both Y and Z would better
be exchangeable.
In pseudo_set() wire handling of O_symbol expressions referencing a
symbol in the expression section to that of other stuff ending up in
this section.
Also avoid bogus O_register expressions to be created, for targets
setting md_register_arithmetic to false: S_GET_VALUE() would resolve
any arithmetic, which must not happen for such targets. To be on the
safe side for such targets, also amend resolve_register(). Correct
another earlier oversight there too (affecting at least Z80), by using
the new expr_copy() helper there as well.
Undo 46b9f07dfe79 ("PR 32721, internal error in
tc-i386.c:parse_register"), albeit without losing the simplification it
did.
|
|
Quite a few constructs where unconditional when they should take
$RELOCATING into account. The original observation was that output of
"ld -r" had .text start at 0x00100000.
|
|
... by way of introducing LEX_EOL and LEX_EOS. As a prereq convert the
remaining open-coded accesses.
The Alpha change is actually a functional one: The array slot for '!'
having been set to 1 is very unlikely to have been correct. 1 means "end
of line", when surely "end of statement" was always meant.
|
|
gas'es obj-bout.c was dropped about 20 years ago, while bfd's bout.c was
dropped almost 7 years ago. Time for the unused header to go away, too.
|
|
With the switch to the use of is_end_of_stmt() in 2dd0370c433d
("rl78: use is_whitespace()") the open-coded checking against
line_separator_chars[] can be dropped.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it. This also fixes two array underrun
issues, when plain char is a signed type.
|
|
... instead of open-coding it. Also convert a variable to plain char
(allowing to drop two casts), which is how it's actually used.
|
|
... instead of open-coding it. Also convert a variable to plain char
(allowing to drop two casts), which is how it's actually used.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
In tic54x_stringer() this also fixes an array overrun issue: Converting
plain char to unsigned int could have yielded huge values when plain
char is a signed type.
In subsym_substitute() also convert a local variable to plain char, as
that's what it's really holding (and how it's used everywhere else).
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it. This also fixes two array underrun
issues, when plain char is a signed type.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it. With this there's no need for op_end (and
hence op_start) to be other than pointer to plain char. Which in turn
eliminates the need for several questionable casts.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
Fix use of is_end_of_line[] directly instead of through the
is_end_of_stmt() macro.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it. This also fixes an array underrun issue:
The wrong casting to plain int could have yielded negative values when
plain char is a signed type.
|
|
... instead of open-coding it. Note that writes to the array need to be
left alone; they can only be converted when the array is folded into
lex_type[].
|
|
... instead of open-coding it.
|
|
... instead of open-coding it.
|
|
... instead of open-coding it. Convert a variable's type to plain char
then as well, as that's what it's really holding (and how it's used
everywhere else).
|