experchange > asm.x86

R.Wieser (12-04-18, 07:47 PM)
Hello all,

I'm disassembling a program using IDA Freeware (an older version, non
graphical), and am encountering multiple INT 0x35 (and friends)
instructions. Which is commented as a floating-point emulation. Full
stop.

Ralf Browns interrupt list shows it to be emulating the 0xD9 machine opcode.
Again, full stop.

Looking in the "The IA-32 Intel Architecture Software Developer's Manual,
Volume 2 - Instruction Set Reference (24547112).pdf" document I can find
multiple entries having the 0xD9 opcode, and from it I take it that the
bytes following the above INT 0x35 are also playing a role: 0x7E 0xFA 0x8A
....

But I do have a bit of a problem interpreting the document. One of the
entries says:

[quote]
D9 /6 FNSTENV* m14/28byte Store FPU environment to m14byte or m28byte
without checking for pending unmasked floating-point exceptions. Then mask
all floating-point exceptions.
[/quote]

I have abslutily *no* idea how to match it up with the 0x7E opcode folowing
the INT 0x35. The explanation for the "/6" is as follows:

[quote]
/digit-A digit between 0 and 7 indicates that the ModR/M byte of the
instruction uses
only the r/m (register or memory) operand. The reg field contains the digit
that provides an
extension to the instruction's opcode.
[/quote]

I'm not at all sure what that means, and if the "/6" actually means that it
matches up with the low three bits of the 0x7E byte. Also, there seems to
be no info on how the "reg field" should be interpreted. And why the "mod"
bits (upper two) are both not just clear or set, as they do not seem to have
any function here(?).

In other words, help ? I could do with a bit of explanation of the
explanation I'm afraid. :-(

Regards,
Rudy Wieser
Rick C. Hodgin (12-04-18, 08:11 PM)
On Tuesday, December 4, 2018 at 12:56:44 PM UTC-5, R.Wieser wrote:
> I'm not at all sure what that means, and if the "/6" actually means that it
> matches up with the low three bits of the 0x7E byte. Also, there seems to
> be no info on how the "reg field" should be interpreted. And why the "mod"
> bits (upper two) are both not just clear or set, as they do not seem to have
> any function here(?).


The Mod/Reg/RM byte is a traditional encoding byte in all of x86
assembly, and it's not specific to FPU operations or anything else
specific. It simply indicates the two registers or memory access
that will be used with the opcode.



These values were extended with 64-bit assembly, but the funda-
mental principles are the same. The bit encodings back into
either registers or memory mapping locations, based on what the
opcode is encoded as. In some instructions, the /6 indicates
that part of the Mod/Reg/RM byte includes additional bits of
opcode encoding because the operation does not require two reg
ops explicitly as one of them is assumed, or in the case of
something like INC EAX, it only needs one.
wolfgang kern (12-04-18, 08:50 PM)
On 12/4/2018 6:47 PM, R.Wieser wrote:
....
> [quote]
> D9 /6 FNSTENV* m14/28byte Store FPU environment to m14byte or m28byte
> without checking for pending unmasked floating-point exceptions. Then mask
> all floating-point exceptions.
> [/quote]


> I have abslutily *no* idea how to match it up with the 0x7E opcode folowing
> the INT 0x35. The explanation for the "/6" is as follows:


> [quote]
> /digit-A digit between 0 and 7 indicates that the ModR/M byte of the
> instruction uses
> only the r/m (register or memory) operand.


the /6 in the RM-field (bits 3,4,5) and MOD 00 (bits 6,7) tells that
this opcode is FNSTENV

use_16:
D6 30 FNSTENV short [BX+SI]
66 D6 30 FNSTENV long [BX+SI]

use_32:
66 D6 30 FNSTENV short [EAX]
D6 30 FNSTENV long [EAX]

> The reg field contains the digit
> that provides an
> extension to the instruction's opcode.
> [/quote]


the reg-field (bits 0,1,2) is used for [mem only] addressing here.

where do you see an 0x7E "JMP NG" ?
__
wolfgang
R.Wieser (12-04-18, 10:04 PM)
Rick,

> The Mod/Reg/RM byte is a traditional encoding byte in all
> of x86 assembly, and it's not specific to FPU operations or
> anything else specific.


I know how it works for the x86 comands. For the FPU commands ? No so
much.

Even if I read the explanation to that "/{digit}" wrong and it doesn't
implicitily exclude the "Mod" part from consideration, than I'm still left
with the "Reg" part (which refers to a register), which has no meaning for
most FPU commands (with the exclusion of one or two none use a register as
source *or* target).

If I use both the "Mod" as well as the "RM" parts the INT 0x35, 0x7E 0xFA
sequence decodes to :

FNSTENV [BP-0x06]

, which looks sensible to me.

But that stil leaves the "Reg" part, which for th 0x7E value refers to the
DI register. Which does not mean anything to me.

So, what *does* it mean ?

Regards,
Rudy Wieser
Robert Wessel (12-04-18, 10:19 PM)
On Tue, 4 Dec 2018 18:47:29 +0100, "R.Wieser"
<address> wrote:

[..]
>any function here(?).
>In other words, help ? I could do with a bit of explanation of the
>explanation I'm afraid. :-(


Many x86 instructions have an extension to the base opcode in the
second ("ModR/M") byte, where the register and memory operands types
are normally specified. The extension is three bits, and is in the M
field (the low three bits of the ModR/M byte). Thus the D9/6 form of
FNSTNV encodes as:

1101 1001 mmrr r110 ...

with the "/6" being encoded in the low three bits of the second byte.

Should that be instead:
1101 1001 mmrr r111 ...

then you'd have a FNSTCW (D9/7).

The mm/rrr fields continue to specify the storage operand in those
cases. With the 7E, that's 01/111, which specifies reg+displacement
(mm=01) addressing, and register BX (rrr=111). So if you had:

d9 7e 34 12

That would be:

FNSTNV [BX+1234h]

(At least in 16-bit mode, you'd have a 32 bit displacement in 32-bit
mode).

The FPU instructions are all encoding of an "escape" instruction,
encoded as "1101 1xxx". The low three bits, plus additional bits from
the ModR/M byte form the opcode. That block of eight instructions is
replaced with eight different INTs in the conventional emulation code,
allowing the first byte of the FESC to be encoded in the vector
number. In some emulation libraries, the code will be patched with a
no-op and the actual ESC opcode byte for the instruction, if there's a
real x87 in the system (thus using the x86 instead of emulation).

There are some other oddities in the x87 instructions. Some of them
use some of the other mm/rrr bits to encode opcode values. Also some
of the newer ISA extensions go off in completely different directions
with various prefixes.
Rick C. Hodgin (12-04-18, 10:37 PM)
On Tuesday, December 4, 2018 at 3:16:31 PM UTC-5, R.Wieser wrote:
[..]
> But that stil leaves the "Reg" part, which for th 0x7E value refers to the
> DI register. Which does not mean anything to me.
> So, what *does* it mean ?


0x7E = 0111 1110 in binary

Applying that to Mod/Reg/RM fields (2:3:3):

01 111 110

The value /6 you're seeing there is what you see in the RM field.
It doesn't refer to the di register, but is where the bits of the
/6 it's referring to go.
Rick C. Hodgin (12-04-18, 11:17 PM)
On Tuesday, December 4, 2018 at 12:56:44 PM UTC-5, R.Wieser wrote:
> Looking in the "The IA-32 Intel Architecture Software Developer's Manual,
> Volume 2 - Instruction Set Reference (24547112).pdf" document I can find
> multiple entries having the 0xD9 opcode, and from it I take it that the
> bytes following the above INT 0x35 are also playing a role: 0x7E 0xFA 0x8A
> ...
> I have abslutily *no* idea how to match it up with the 0x7E opcode folowing
> the INT 0x35. The explanation for the "/6" is as follows:


I apologize, Rudy. I completely misunderstood what you were posting
here. My mistake.

Is it possible 0x8afa or 0xfa8a is a memory pointer to the instruction
to emulate, or an offset in the current data segment? I would trace
into the interrupt in the debugger and see how it decodes those values.

Also, interrupts are usually signaled with values in the registers or
on the stack being setup. What does it do before that INT 35h?
Robert Wessel (12-04-18, 11:32 PM)
On Tue, 04 Dec 2018 14:19:34 -0600, Robert Wessel
<robertwessel2> wrote:

[..]
> FNSTNV [BX+1234h]
>(At least in 16-bit mode, you'd have a 32 bit displacement in 32-bit
>mode).


Should know better than to do this from memory. With a mm=01, the
offset would be only a single byte, so:

d9 7e 12

would be:

FNSTNV [BX+12h]

A mm=10 would be for a 16-bit displacement, but then the code would
be:

d9 de 34 12
Rod Pemberton (12-05-18, 12:00 AM)
On Tue, 4 Dec 2018 18:47:29 +0100
"R.Wieser" <address> wrote:

[..]
> I can find multiple entries having the 0xD9 opcode, and from it I
> take it that the bytes following the above INT 0x35 are also playing
> a role: 0x7E 0xFA 0x8A ...


Ndisasm disassembly of the bytes given, i.e., D9 7E FA shows the
following:

00000000 D97EFA fnstcw [bp-0x6]

The ModR/M byte has three fields: Mod Reg R/M, bit-format as 2-3-3.

For 0x7E (01-111-110) the Mod field is 01 (1), Reg field is 111 (7),
and R/M field is 110 (6).

Intel syntax uses "/digit" to represent a hard-coded Reg field value
and "/r" to represent a register value for the Reg field.

So, we want the middle three bits 111 (7), i.e., D9 /7 FNSTCW.

> But I do have a bit of a problem interpreting the document. One of
> the entries says:
> [quote]
> D9 /6 FNSTENV* m14/28byte Store FPU environment to m14byte or m28byte
> without checking for pending unmasked floating-point exceptions. Then
> mask all floating-point exceptions.
> [/quote]


How did you get /6 here? ...

[quote]
D9 /7 FNSTCW* m2byte Store FPU control word to m2byte without checking
for pending unmasked floating-point exceptions.
[/quote]



> I have abslutily *no* idea how to match it up with the 0x7E opcode
> folowing the INT 0x35.


....

> The explanation for the "/6" is as follows:
> [quote]
> /digit-A digit between 0 and 7 indicates that the ModR/M byte of the
> instruction uses
> only the r/m (register or memory) operand. The reg field contains the
> digit that provides an
> extension to the instruction's opcode.
> [/quote]
> I'm not at all sure what that means, and if the "/6" actually means
> that it matches up with the low three bits of the 0x7E byte.


The Intel manuals usually have a table showing value combinations of Mod
and R/M, but don't include the Reg value. The Reg value is usually a
separate table at the top of that table. Reg specifies a register. Mod
and R/M specifies the address mode. Sandpile's version is here:



However, floating point instructions have their own format. Some of
the encodings are similar to general opcodes, e.g., with ModR/M byte,
but many are different. E.g., a 2016 Intel manual shows five different
ways to encode various floating point instructions.

See "B.17 Floating-Point Instruction Formats and Encodings" table B-38
of Appendix B in "Intel 64 and IA-32 Architectures Software Developer's
Manual" Volume 2, Instruction Set Reference. It may be differently
labeled in some other version or AMD's manuals.

> Also, there seems to be no info on how the "reg field" should be
> interpreted.


See the row here labeled "D9h 40...7Fh":



The reg field is /7 (111) for 0x7E which is either FSTCW Mw or
FNSTCW Mw as listed in the 7th column. If it was /0 it'd be FLD, /2
FST, /3 FSTP, /4 FLDENV M14/M28, /5 FLDCW Mw, /6 FSTENV or FNSTENV
M14/M28 ...

> And why the "mod" bits (upper two) are both not just
> clear or set, as they do not seem to have any function here(?).


Mod as 11 seem to be for other floating point encodings. You'll need
to look at table B-38 or the floating point bit encodings that follow.

Rod Pemberton
R.Wieser (12-05-18, 10:39 AM)
Rod (and others),

> How did you get /6 here? ...


Thats part of the problem, because of the rather terse and confusing
explanation I had to make a guess to what I should look at. As it
explicitily referred to the R/M bits I thought it applied to those.

The low three bits of 0x7E are 110b = 6.

I guessed wrong.

> Intel syntax uses "/digit" to represent a hard-coded Reg field value
> and "/r" to represent a register value for the Reg field.


:-) That is what I missed in that explanation.

And than that the R/M *and* Mod fields where to be used as normally ofcourse
(it seemed to exclude the Mod part).

> See "B.17 Floating-Point Instruction Formats and Encodings" table
> B-38 of Appendix B in "Intel 64 and IA-32 Architectures Software
> Developer's Manual" Volume 2, Instruction Set Reference. It may be
> differently labeled in some other version or AMD's manuals.


It has a different ID (B-23), but the same name in mine. And yes, it would
have explained a lot. I really need to remember searching the appendixes
too ...

> Ndisasm disassembly of the bytes given, i.e., D9 7E FA shows the
> following:


Yup. Only too late I realized that I could (should?) have done that before
posting here. (than again, I thought that I could learn to read that
explanation, which could possibly have served me in the future - forgoing
having to puzzle-it-out I mean).

This morning I made a list of 0xD9 ModRegR/M 0x90 sequences where I first
incremented the R/M, after that the Mod bits, disasembled them and saw they
matched up, as rick mentioned but I did not understand (conflicting info) at
the time, with the x86 usage.

That left the "/{number}" part to correlate with the Reg bits. A quick
list creation and disassembly of that showed it to be correct.

So much for official documentation explanations I guess .... :-((

Thanks.

Regards,
Rudy Wieser
R.Wieser (12-05-18, 11:16 AM)
Rick,

> I apologize, Rudy. I completely misunderstood what you were posting
> here. My mistake.


Don't worry about it. And thank you for telling me (quite a number of
people would have either denied or ignored it, or have simply disappeared).

> Is it possible 0x8afa or 0xfa8a is a memory pointer to the
> instruction to emulate, or an offset in the current data segment?


I don't think so. Ralf Browns interrup list mentions that the INT 0x35
translates to the 0xD9 opcode. The bytes following the INT seem to be part
of that FPU command (a bit, but not much, of guesswork here).

In this case (confirmed by disassembling a 0xD9 0x7E 0xFA sequence) the
result is an FPU instruction, with the 0x7E representing the ModRegR/M byte
and the 0xFA byte a relative offset over BP.

In short, I was confused to what the "/6" (in my first quote) was referring
to in that ModRegR/M byte, and from it did not notice the ModR/M part was to
be used as normally.

In other words: Now I know that the "/6" should match the "Reg" bits the
rest simply fell into its place.

Thanks for the help.

Regards,
Rudy Wieser
Rick C. Hodgin (12-05-18, 05:34 PM)
On Wednesday, December 5, 2018 at 4:26:04 AM UTC-5, R.Wieser wrote:
> Rick,
> > I apologize, Rudy. I completely misunderstood what you were posting
> > here. My mistake.

> Don't worry about it. And thank you for telling me (quite a number of
> people would have either denied or ignored it, or have simply disappeared).


This is the third time in a row I've dipped into my assembly
language knowledge from memory, and given wrong advice. I'm
going to take steps to correct that by consulting the IA-32
manuals before I reply in the future.

It's interesting the way our thinking / memories alter over
time. So many movies I used to be able to quote from memory,
I get even the famous quotes slightly wrong now.

More study and less reliance upon faulty Rick's aging memory
before replying.
Similar Threads