Author Topic: Why can i use 32-bit registers in 16-bit mode?  (Read 23058 times)

Offline unimous

  • Jr. Member
  • *
  • Posts: 4
Why can i use 32-bit registers in 16-bit mode?
« on: January 25, 2011, 05:40:27 PM »
i my opinion, if i specify [BITS 16] in my program, then the program will be compiled into 16-bits codes, and surely we can not use 32-bits registers in this mode.
but i can write my program like this:

Code: [Select]
[section .code]
[BITS 16]
...
mov   eax, ebx
...

who can tell me why can where can i find more information on this topic, thank you.
« Last Edit: January 25, 2011, 05:42:34 PM by unimous »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Why can i use 32-bit registers in 16-bit mode?
« Reply #1 on: January 25, 2011, 06:09:11 PM »
Quote
"i my opinion, if i specify [BITS 16] in my program, then the program will be compiled into 16-bits codes, and surely we can not use 32-bits registers in this mode."

Your opinion differs from that of the CPU... and the CPU wins. :)

As Keith suggests, RTFM:

http://www.nasm.us/doc/nasmdoc6.html#section-6.1

In particular, note the paragraph on the 0x66 and 0x67 prefixes. The reason this works is because Intel employed a "clever trick" or an "ugly kludge" (depending on how you look at it) when they introduced 32-bit code - they used the same opcodes! If the CPU is in 32-bit mode, as determined by a bit in the cs descriptor, it defaults to 32-bit registers and opcodes. If this bit is clear (in protected mode), or if we're in real mode (determined by a bit in cr0), the default is 16-bit registers, opcodes, and addresses. These defaults can be toggled (on a per instruction basis) by the operand size override prefix and/or the address size override prefix. In your proposed code (using 32-bit registers in 16-bit mode), Nasm will automatically insert the 0x66 prefix - specifying "bits 16" and using 32-bit registers tells it to do so. 32-bit addressing modes in 16-bit code will also work:

Code: [Select]
bits 16
mov al, [array + ecx + edx * 4]

There's a "gotcha" with this: the total offset must be within the "limit" prescribed for this  segment, normally 0xFFFF for 16-bit code (although this can be changed, in some circumstances... so called "Flat Real Mode" or "Unreal mode).

Does that help clear it up?

Best,
Frank


Offline unimous

  • Jr. Member
  • *
  • Posts: 4
Re: Why can i use 32-bit registers in 16-bit mode?
« Reply #2 on: January 26, 2011, 02:28:05 PM »
I  am clear now, thank you very very very much.

Offline unimous

  • Jr. Member
  • *
  • Posts: 4
Re: Why can i use 32-bit registers in 16-bit mode?
« Reply #3 on: January 27, 2011, 03:04:40 AM »
I have another problem.

If i can understand like this:

if( cr0 's bit0 is clear )then cpu is in real mode and in 16-bit mode and default to 16-bit registers, opcodes and address. But we can also use 32-bit registers by inserting a 0x66 byte before the opcode, and can use 32-bit address by inserting a 0x67 byte before the opcode.

if( cr0 's bit0 is set )then cpu is in protected mode
  if( some bit in cs is clear )then cpu is default to 16-bit mode and just like the 16-bit mode above;
  else if( that bit in cs is set )then cpu is default to 32-bit mode and default to 32-bit registers, opcodes and address. But we can also use 16-bit registers by inserting a 0x66 byte before the opcode, and can use 16-bit address by inserting a 0x67 byte before the opcode.;

But what that bit in cs?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Why can i use 32-bit registers in 16-bit mode?
« Reply #4 on: January 27, 2011, 07:33:20 AM »
That's on a need-to-know basis, and I don't need to know! :)

Ummm, it's bit 54, if I'm counting them right. I should have made it clear that this isn't a bit "in" cs, but a bit in the descriptor to which cs points. I'm sure that there's some good "hardware reason" why descriptors are laid out the way they are. To me, they just seem "scrambled" - a couple bytes of "base" here, the rest of 'em over there... The bit we're interested in (the "D" bit... for "default", I guess) occurs in a byte in which the low nibble is part of the "limit", and the high nibble is some bit flags. Unless you're writing your own OS, you don't need to know the details of this, but we wouldn't be here if we weren't curious... would we? :)

Good to have some idea what the OS has done for/to you before your code runs, in any case...

http://codewiki.wikispaces.com/x86+descriptors

http://wiki.osdev.org/Global_Descriptor_Table

http://wiki.osdev.org/Babystep6

You might have better luck starting at the bottom of that list and working up (do all the "Babysteps" if you're actually writing an OS, or are curious). Good luck!

Best,
Frank