Inconsistent usage on onebyte_modrm and twobyte_modrm table in x86 disassembler and gdb?
Jiang, Haochen
haochen.jiang@intel.com
Mon Aug 25 02:42:41 GMT 2025
Hi all,
Recently I happened to have a look at the gdb code. At gdb/amd64-tdep.c
L1102 comment, it mentioned that:
/* WARNING: Keep onebyte_has_modrm, twobyte_has_modrm in sync with
../opcodes/i386-dis.c (until libopcodes exports them, or an alternative,
at which point delete these in favor of libopcodes' versions). */
This means the table content and usage should be the same as gas.
However, when we are using the table in disassembler at opcode/i386-dis.c
L9877, it is:
/* REX2.M in rex2 prefix represents map0 or map1. */
if (ins.last_rex2_prefix < 0 ? *ins.codep == 0x0f : (ins.rex2 & REX2_M))
{
if (!ins.rex2)
{
ins.codep++;
if (!fetch_code (info, ins.codep + 1))
goto fetch_error_out;
}
dp = &dis386_twobyte[*ins.codep];
ins.need_modrm = twobyte_has_modrm[*ins.codep];
}
else
{
dp = &dis386[*ins.codep];
ins.need_modrm = onebyte_has_modrm[*ins.codep];
}
It will use the very first byte of the bytecode.
On the other hand, in gdb, let's take VEX prefix as example at
gdb/amd64-tdep.c L1349, the logic is:
/* Skip REX/VEX instruction encoding prefixes. */
...
else if (vex2_prefix_p (*insn))
{
details->enc_prefix_offset = insn - start;
insn += 2;
}
else if (vex3_prefix_p (*insn))
{
details->enc_prefix_offset = insn - start;
insn += 3;
}
...
if (prefix != nullptr && rex2_prefix_p (*prefix))
{
...
}
else if (prefix != nullptr && vex2_prefix_p (*prefix))
{
need_modrm = twobyte_has_modrm[*insn];
details->opcode_len = 2;
}
else if (prefix != nullptr && vex3_prefix_p (*prefix))
{
need_modrm = twobyte_has_modrm[*insn];
...
}
...
It will skip the VEX prefix and use twobyte_has_modrm table instead of
onebyte_has_modrm[0xc4/c5] in disassembler. The table usage are totally
different although the table itself is the same. It will cause the need_modrm
value different eventually. For example, opcode for VPBLENDW under 128 bit
is "VEX.128.66.0F3A.WIG 0E /r ib". The need_modrm would be false in gdb
since twobyte_has_modrm[0x0e] is false.
Does anyone know the reason on that? It is weird to me.
BTW, the content of the two table is inconsistent currently due to the ud*
added in 2019. No matter what the answer of the previous question is, we
need to fix it. Maybe we should also add a comment at opcode/i386-dis.c
to have a reminder.
Thx,
Haochen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/binutils/attachments/20250825/3f1cc90e/attachment-0001.htm>
More information about the Binutils
mailing list