Page 1 of 2

8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 12:26 pm
by Antti
I was just wondering whether it is possible to write code that is compatible with Real Mode, Protected Mode, and Long Mode. I do not mean using few instructions to test the mode and then branching to the correct mode-specific code. Here are few things I wrote down:

Code: Select all

Instructions using ModR/M byte (between registers) are very useful. This is the way to clear registers and moving values. Of course, we are restricted to use only lowest 16 bits.

        16-bit                  32-bit                  64-bit
        MOV AX, BX              MOV EAX, EBX            MOV EAX, EBX
        XOR AX, AX              XOR EAX, EAX            XOR EAX, EAX


Immediate values need to be 8-bit. This makes code a little bit longer.

        16-bit                  32-bit                  64-bit
        MOV AL, 8               MOV AL, 8               MOV AL, 8
        MOV AH, 8               MOV AH, 8               MOV AH, 8


To access a memory location, we could use "BX == EDI == RDI". It means that the memory location should have two bytes (actual value) and two zero bytes if using AX/EAX.

        16-bit                  32-bit                  64-bit
        MOV [BX], AX            MOV [EDI], EAX          MOV [RDI], EAX
        MOV AX, [BX]            MOV EAX, [EDI]          MOV EAX, [RDI]


Relative calls can not be used so we must use indirect addresses.

        16-bit                  32-bit                  64-bit
        CALL AX                 CALL EAX                CALL RAX
        RET                     RET                     RET


Short jumps and indirect jumps can be used.

        16-bit                  32-bit                  64-bit
        JMP rel8                JMP rel8                JMP rel8
        JMP AX                  JMP EAX                 JMP RAX


Short conditional jumps can be used.

        16-bit                  32-bit                  64-bit
        JC rel8                 JC rel8                 JC rel8
This is not a comprehensive list. However, did I forget something that makes this impossible?

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 1:16 pm
by mathematician
Well, in real mode you would have to make explicit use of the segment registers, unless you wanted to be limited to 64kb of memory, and since 32 bit or 64 bit code would probably assume a flat address space, that could be a problem.

In any case, what would be the point of having a computer with (say) 8192mb of memory inside it, but only using 0.01% of that?

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 1:51 pm
by wichtounet
If I'm not mistaken, you can use 32 bits register in real mode, which means you can expand a bit the code that is available.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 2:09 pm
by xenos
wichtounet wrote:If I'm not mistaken, you can use 32 bits register in real mode, which means you can expand a bit the code that is available.
Yes, but for that you need an operand size prefix, and if you run the same code with that prefix on 32 bit, it will use only 16 bit registers.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 2:54 pm
by wichtounet
XenOS wrote:
wichtounet wrote:If I'm not mistaken, you can use 32 bits register in real mode, which means you can expand a bit the code that is available.
Yes, but for that you need an operand size prefix, and if you run the same code with that prefix on 32 bit, it will use only 16 bit registers.
Right, didn't thought about the reverse situation :oops:

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 2:59 pm
by Antti
mathematician wrote:In any case, what would be the point of having a computer with (say) 8192mb of memory inside it, but only using 0.01% of that?
I was thinking some small modules that could run on all modes. The limit is 64 KiB and it is not a problem.
XenOS wrote:if you run the same code with that prefix on 32 bit, it will use only 16 bit registers.
Absolutely yes but there is more than that. If operand size prefixes are used, it would not be 8086 compatible code.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 3:08 pm
by Gigasoft
You can also access memory with LODSB and STOSB. One trick you could do is make sure that your data is at virtual address 0 for 16 bit mode, 6f700000h for 32 bit mode and 0ffffffff6f700000h for 64 bit mode. Then, you can load a 16 bit immediate value into a register by adding two nops at the end, and use the resulting value as an address, or by adding two nops at the end of the instructions A0 through A3. Near jumps and calls are possible by having two nops at the destination of such jumps and calls.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Thu Jan 23, 2014 3:34 pm
by Antti
Actually, this is more interesting than I first thought. Segmentation could be used in 16-bit mode and the module loader would set them before code is run. Flat memory model is used in 32-bit or 64-bit mode and the module loader give the base address in higher bits. For example, if EDI is 0x8A000000, the code must not wipe out it (e.g. "XOR DI, DI").

I was planning to write a toy compiler that outputs this kind of code. I am not going to write it manually.

EDIT: I was too tired! Of course, it is the paging that solves this.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Fri Jan 24, 2014 10:30 am
by Antti
I have another question that goes offtopic slightly but I do not dare to create a new thread for it. For alignment purposes, I have sometimes replaced one-byte "PUSH REG" instructions with two-byte "PUSH R/M" instructions. POP instructions are also used like this. E.g.

Code: Select all

50      PUSH AX         ; One byte
FFF0    PUSH AX         ; Two bytes
I try to be cautious so I am a little bit afraid of using longer versions. It is clear that probably no one else uses them. Could it be that there are even CPU bugs that cause troubles? The old 8086 manual says that the ModR/M version is "PUSH MEM16". I can imagine that they had thought that no one is going to use it for general purpose registers. However, there are programmers like Antti trying to use it like this. Will this lead to Halt and Catch Fire? It is quite cold here so perhaps it is not so bad. XenOS: is it cold in Tartu?

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Fri Jan 24, 2014 11:41 am
by xenos
Antti wrote:Absolutely yes but there is more than that. If operand size prefixes are used, it would not be 8086 compatible code.
Oh, right, forgot about that.
Antti wrote:It is quite cold here so perhaps it is not so bad. XenOS: is it cold in Tartu?
Well, this morning it was -24°C and my car didn't start, so some kind of heating would be nice. What's the temperature in your area?

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Fri Jan 24, 2014 12:09 pm
by Antti
XenOS wrote:Well, this morning it was -24°C and my car didn't start, so some kind of heating would be nice. What's the temperature in your area?
About the same temperature. It should not be bad but it still tried to freeze my fingers when I went to work. Perhaps I am not used to it. My fourth generation Golf cart starts up well if the battery is alive (it is the weakest link).

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Fri Jan 24, 2014 6:14 pm
by Octocontrabass
Antti wrote:Could it be that there are even CPU bugs that cause troubles? The old 8086 manual says that the ModR/M version is "PUSH MEM16".
It's more like undefined behavior than a bug, but using the "long" pop won't work on a NEC V20. I don't know if any other CPUs have issues with those instructions.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Sat Jan 25, 2014 3:40 am
by Antti
Octocontrabass wrote:It's more like undefined behavior than a bug, but using the "long" pop won't work on a NEC V20. I don't know if any other CPUs have issues with those instructions.
This is a good reason to stop using them. This is also a good example of being cautious. I felt that using uncommon instructions might be unsafe and soon after that you pointed out that there were, a surprise a surprise, CPUs that can not handle them. Of course, I should not have used murky instructions in the first place.

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Mon Feb 03, 2014 8:15 am
by Antti
Perhaps NASM uses instructions that are not available on 8086 and 80286 processors. It is the "AND r/m16, imm8". Hopefully I am wrong.

Code: Select all

[BITS 16]
[CPU 8086]

start:
	and ax, 0x01
Generated instructions:

Code: Select all

83 E0 01

Re: 8086, 80386 and x86-64 compatible instructions

Posted: Mon Feb 03, 2014 9:43 am
by qw
It is correct. AND r/m16, imm8 has been supported since the 8086.