VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

The opcodes 70-7F and 0F80-0F8F are conditional jumps(Jcc), there are multiple versions of disassembly for many of the conditional Jcc opcodes. Which one should be used for disassembly of the Jcc opcodes?

For now, I've adjusted the output to match https://github.com/barotto/IBMulator/blob/mas … /cpu/disasm.cpp from the IBMulator project.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 10, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

what do you mean there are multiple jcc opcodes? (some have multiple syntactic sugar names for the same opcode. ie: 75 is jnz but can also be 'jne' but jne is just sugar for jnz.

70 - jo
71 - jno
72 - jc
73 - jnc
74 - jz
75 - jnz
76 - jb
77 - jnbe
78 - js
79 - jns
7a - jp
7b - jnp
7c - jl
7d - jge
7e - jle
7f - jg

0F 8x opcodes are the exact same but have a 16bit (or 32 in pmode) relative address.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 2 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

Those opcodes you've mentioned are the non-sugar versions, e.g. for generic disassembly without knowing the context(since context is unknown in single instruction disassembly(not depending on other instructions))? As is the case with my emulator, UniPCemu?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 10, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

Those opcodes you've mentioned are the non-sugar versions, e.g. for generic disassembly without knowing the context(since context is unknown in single instruction disassembly(not depending on other instructions))? As is the case with my emulator, UniPCemu?

You cant ever know the context because it doesnt exist.

JNE and JNZ are the exact same thing. There is no context to be gleaned from other instructions around it. Using one over the other is irrelevant. JNE is sugar for JNZ. Its a one way conversion. Having JNE in my source is meaningless as the cpu only see's JNZ and any disassembly should show JNZ because the opcode is JNZ. There is not 'equal' flag, only 'zero'.

The sugar is too distracting, JC and JNAE are the same, but the JNAE is a false sugar, JNAE is not about 'jump if not above or equal' is really 'this jumps only if carry is set'. A beginner is not going to understand how 'above and equal' means 'carry flag'.

I would only use mnemonics that relate directly, to what they operate on. ie: use JC and never JNAE. JZ and not JE because it works on the Z flag, there is no 'Equal' flag.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 4 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

I have just implemented your first post's instruction names in UniPCemu. I assume those are the non-sugar assembly names of the instructions?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 6 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

So what should I use for opcodes 76h/77h? JA/JNA or JBE/JNBE? I'd assume JA/JNA is the correct, unsugared one(following the other patterns)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 7 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

What happens when a 32-bit, 16-bit or 8-bit immediate relative or absolute jump is executed with the different values of the D-bit in the CS segment descriptor? So what's the resulting value of EIP after such a relative jump?

For example:
0000:FF80 JMP +7E. EIP=0 or 00010000?
0000:0000FF80 JMP +7E. EIP=0 or 00010000?
0000:FF80 JMP +007E. EIP=0 or 00010000?
0000:0000FF80 JMP +007E. EIP=0 or 00010000?
0000:FF80 JMP +000007E. EIP=0 or 00010000?
0000:0000FF80 JMP +0000007E. EIP=0 or 00010000?

Where 0000:FF80 is 16-bit default operand size(CS descriptor D-bit=0), 0000:0000FF80 is 32-bit default operand size(CS descriptor D-bit=1).

Anyone? Is the clearing of EIP's high 16-bits determined by the effective(affected by prefix 66h) operand size or by the CS's D-bit only?

Both might work the same in 16-bit real mode, as any overflow in EIP being executed after the jump triggers a general protection fault, which after execution of the jump only saves the lower half(16-bits) and reads the lower half on return(clearing the upper half).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 8 of 10, by peterferrie

User metadata
Rank Oldbie
Rank
Oldbie

66-override works for relative instructions (short and long branches and relative jumps) as expected: (E)IP is used in inverse of the CS size.
So 0000FF80 JMP+007E will branch to EIP=0, for example.

Reply 9 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

So it gets masked to 16-bits with 16-bit operand size and not masked with 32-bit operand size?

Why didn't they use the code segment D-bit for enabling masking to 16-bits when zeroed? If they did, all cases could have been used in both 16-bit and 32-bit code without problems:
jmp imm8 with D=0: mask to 16-bits, 8-bit relative jump
jmp imm16 with D=0: mask to 16-bits, 16-bit relative jump
jmp imm32 with D=0: mask to 16-bits, 32-bit relative jump
jmp imm8 with D=1: 8-bit relative jump on EIP
jmp imm16 with D=1: 16-bit relative jump on EIP
jmp imm32 with D=1: 32-bit relative jump on EIP

That way, none of the opcodes are wasted, wrapping is dependent on the loaded program(D-bit) being 16-bit or 32-bit, all relative operand sizes are possible(8/16/32-bit)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 10 of 10, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thinking of it: there's also the B(ig)-bit in a segment descriptor. I know that it's effect on SS is that it selects between using ESP and SP for stack operations. Does it have any effect on data segments(DS/ES/FS/GS)? In my emulation, only the G-bit currently has effect on the limit(<<10|0xFFF when set). The top-down bit of a data segment descriptor reverses logic of valid/invalid.

What effect does the B-bit have other than selecting the default opcode size and stack size? What happens when it doesn't match the Granularity bit and is loaded inside a data segment(all but SS)? Does it affect wrapping on offsets(e.g. when using a 32-bit offset)?

Edit: Just implemented the B-bit being cleared and used with a top-down descriptor past offset 0xFFFF to fault. So it limits the offset to 64K when not set(using a 32-bit offset). What happens when it's cleared using a normal(bottom-up 0-limit) descriptor? Does it still have effect(undocumented) in that case?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io