qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module


From: Jan Bobek
Subject: Re: [Qemu-devel] [RISU RFC PATCH v1 4/7] risugen_x86: add module
Date: Fri, 28 Jun 2019 13:06:58 -0400
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1

On 6/27/19 6:29 AM, Richard Henderson wrote:
> On 6/19/19 7:04 AM, Jan Bobek wrote:
>> +sub write_mov_reg_imm($$)
>> +{
>> +    my ($reg, $imm) = @_;
>> +
>> +    my %insn = (opcode => {value => 0xB8 | ($reg & 0x7), len => 1},
>> +                imm => {value => $imm, len => $is_x86_64 ? 8 : 4});
>> +
>> +    $insn{rex}{w} = 1 if $is_x86_64;
>> +    $insn{rex}{b} = 1 if $reg >= 8;
>> +
>> +    write_insn(%insn);
>> +}
> 
> There are 3 different insns that x86_64 can use for different ranges of
> immediates; you are always using the full 10 byte version.
> 
> Using 0xb8 without REX.W may be used for any unsigned 32-bit value.
> Using 0xc7 with REX.W may be used for any signed 32-bit value.
> Using 0xb8 with REX.W of course allows any 64-bit value.
> 
> It's not terribly important, but the code size does get large.

Funnily enough, the very first version of this function did try to
save bytes by using different instructions, but when I started writing
write_mem_getoffset, I ran into trouble with signedness. In response,
I hard-coded the 10 byte version for debugging and then never switched
it back.

I'll try to do something about this in v2.

>> +sub rand_insn_modrm($$)
>> +{
>> +    my ($opts, $insn) = @_;
>> +    my $modrm;
>> +
>> +    while (1) {
>> +        $modrm = rand_fill({mod => {bitlen => 2},
>> +                            reg => {bitlen => 3},
>> +                            rm => {bitlen => 3}},
>> +                           $opts);
>> +
>> +        if ($modrm->{mod} != MOD_DIRECT) {
>> +            # Displacement only; we cannot use this since we
>> +            # don't know absolute address of the memblock.
>> +            next if $modrm->{mod} == MOD_INDIRECT && $modrm->{rm} == 
>> REG_EBP;
> ...
>> +sub rand_insn_rex($$)
>> +{
>> +    my ($opts, $insn) = @_;
>> +
>> +    $opts->{w} = 0 unless defined $opts->{w};
>> +    $opts->{x} = 0 unless defined $opts->{x} || defined $insn->{sib};
>> +
>> +    my $rex = rand_fill({w => {bitlen => 1},
>> +                         r => {bitlen => 1},
>> +                         b => {bitlen => 1},
>> +                         x => {bitlen => 1}},
>> +                        $opts);
> 
> I don't think it's a good idea to generate reg/rm/sib.index separate from
> rex.r/b/x.  In particular, all of your tests vs EBP and ESP are not quite
> right, since the final insn may be referencing R12 or R13.

That's true. (Although not in all cases; see Table 2-5 in the Intel Manual,
Volume 2, Chapter 2, Section 2.2.1 "REX Prefixes" for some cases when REX.B
is not decoded.) This is a compromise that I've accepted, at least for v1
of the patch series. Note that this problem is also present in config entries
such as

PMOVMSKB        SSE     00001111 11010111 !emit { modrm(mod => MOD_DIRECT, reg 
=> ~REG_ESP); }

Here, we force MODRM.REG != 4, but this avoids not only ESP/RSP, but
also R12.

Hmmm... I suppose I have some ideas on how to do it better. I'll try
to fix this, though I suspect getting it 100 % right might be
difficult and time-consuming.

> What is your plan for handling the unary insns for which modrm.r is opcode and
> not a register?  This doesn't seem to allow for those.  How about insns for
> which modrm.mod must be 3 (register) or must be != 3 (memory/address)?

Both of these translate to forcing or avoiding a certain value in a field,
which is handled by the $opts argument to rand_fill; I mention this in my
email about the first patch in this series.

> Is this
> simply going to fall into "testing of illegal encodings"?

Speaking of testing of illegal encodings, it occurred to me that it
might be quite hard: since x86 uses variable-length encoding, you
cannot tell how many bytes should be skipped if an invalid instruction
is encountered.

Perhaps we could use a multi-byte NOP with the length embedded in some
of the ignored fields? We could then teach RISU to look at the
preceding instruction and skip the correct number of bytes when
appropriate. Do you think it would be worth the effort? RISU currently
doesn't seem to support this use-case, but it should be
straightforward to implement: just add a record to the trace file
that the instruction generates a SIGILL.

-Jan

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]