Using multiple BITS statements in one assembly file

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
shahsunny712
Posts: 20
Joined: Wed Jan 29, 2014 11:57 am

Using multiple BITS statements in one assembly file

Post by shahsunny712 »

I am writing a second stage bootloader, a part of whose responsibility will be to enter 32 bit protected mode from 16 bit real mode.

My code has some initializing real mode code, a few real mode functions, protected mode code and a few protected mode functions. Here's what I had done (the actual code is in the same order):

- Added BITS 16 before the starting of first real mode function.

- Added BITS 32 before the first protected mode function

- Added BITS 16 before the initializing real mode code

- Added BITS 32 before the initializing protected mode code :

Code: Select all

BITS 32

mov eax, cr0
or eax, 0x1
mov cr0, eax
(I load the GDT before this, but CS is still the same as before).

This didn't work, so I read NASM's manual which said its not necessary to use this directive. I removed all of them and the code worked!

What was the mistake in my approach ? And, am I somehow mixing up bitness and the processor mode ?
h0bby1
Member
Member
Posts: 240
Joined: Wed Aug 21, 2013 7:08 am

Re: Using multiple BITS statements in one assembly file

Post by h0bby1 »

if you want the 'bits' directive to be effective in protected mode, you also have to create code segment with the 32 bit flag set accordingly, and making a far jmp to the codesegment of which 32 bit attribute correspond to the {bits} directive of the section the code is in

when you use bits directive with nasm, it changes the way nasm assemble the code, in real mode, the cpu is in 16 bit mode , and it add a size prefix db 66h to have the 32 bit instruction (like mov eax), and it also changes how call and interupt are made, in protected mode, it's the 32 bit attribute of the code segment that determine if the cpu is in 16 bit or 32 bit mode, and a code assmembled as 16 bit should be executed with cs on a 16 bit segment, and a code assembled as 32bit should be executed on a 32 bit code segment
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Using multiple BITS statements in one assembly file

Post by Bender »

Hi,
The BITS 32 or FASM's USE32 is is usually after the far jump to protected mode for bringing CS back to sanity.
Remember that under 16 bit Real Mode (80386+) you can use 32 bit Registers and data. However these require an operand size prefix (0x66) and an address size prefix (0x67). This makes it possible a Real Mode OS/Program to use 32 bit General Purpose Registers.
As the NASM manual says:
When NASM is in BITS 16 mode, instructions which use 32-bit data are prefixed with an 0x66 byte, and those referring to 32-bit addresses have an 0x67 prefix. In BITS 32 mode, the reverse is true: 32-bit instructions require no prefixes, whereas instructions using 16-bit data need an 0x66 and those working on 16-bit addresses need an 0x67
This didn't work, so I read NASM's manual which said its not necessary to use this directive. I removed all of them and the code worked!
Can you tell us what you mean by it didn't work? Triple Fault? Halt? Crash? There are a million definitions of code not working.
If you are referring to this:
You do not need to specify BITS 32 merely in order to use 32-bit instructions in a 16-bit DOS program; if you do, the assembler will generate incorrect code because it will be writing code targeted at a 32-bit platform, to be run on a 16-bit one.
I guess you've understood it wrong.(Only if you referred to this)
-Bender
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
shahsunny712
Posts: 20
Joined: Wed Jan 29, 2014 11:57 am

Re: Using multiple BITS statements in one assembly file

Post by shahsunny712 »

By code not working, I meant the screen keeps repainting itself in an infinite loop. Not sure why that would happen.
I guess you've understood it wrong.(Only if you referred to this)
No, I didn't refer to that sentence and remove the BITS. I actually referred to this:
In most cases, you should not need to use BITS explicitly.
Seems like I made a very quick judgement and should have thought up on it once.

Also, I haven't yet changed CS (as I mentioned in my question). So the processor is still in a 16-bit code segment. Is that why it failed ? I guess I am having difficulty in correlating what the processor expects and what I am instructing it. Can someone please explain it in some detail ?
freecrac
Member
Member
Posts: 69
Joined: Thu Sep 20, 2012 5:11 am
Location: germany hamburg

Re: Using multiple BITS statements in one assembly file

Post by freecrac »

Hello.
Like "h0bby1" said for to switch between the 16 bit realmode and the 32 bit protected mode we need at last a "far jmp" to the codesegment and the changing will first have an effect after this far jmp of which 32 bit attribute correspond to the {bits} directive of the section the code is in.

[bits32]
For to get the 32 bit addressmode we need additional to set the Default-Size-Bit in the codesegmet descriptor before. And if this D-bit is set, then the default size of all operands and addresses of the instructions in this 32 bit-codesegment is 32 bit without to use operand-size and/or address-size prefixes. But if we want to use 16 bit operands and/or 16 bit addresses within the 32 bit mode, then we need one or both of these size-prefixes for each one of this 16 bit instruction for to reverse the default operand- and address-size in the 32 bit codesegment.

[bits16]
If the D-bit is not set, then we get the 16 bit addressmode and all operands and addresses of the instructions in this 16 bit-codesegment is 16 bit without to use operand-size and/or address-size prefixes. If we want to use 32 bit operands and/or 32 bit addresses(80386+) within the 16 bit mode, then we need one or both of these size-prefixes for each of this 32 bit instruction for to reverse the default operand- and address-size in the 16 bit codesegment.

Dirk
User avatar
Bender
Member
Member
Posts: 449
Joined: Wed Aug 21, 2013 3:53 am
Libera.chat IRC: bender|
Location: Asia, Singapore

Re: Using multiple BITS statements in one assembly file

Post by Bender »

Hi,
Seems like I made a very quick judgement and should have thought up on it once.
You should have read the very next line.
In most cases, you should not need to use BITS explicitly. The aout, coff, elf, macho, win32 and win64 object formats, which are designed for use in 32-bit or 64-bit operating systems, all cause NASM to select 32-bit or 64-bit mode, respectively, by default
Which means that normally when you're using these formats for example win32, there is no
need of specifying [BITS 32]. NASM will do it for you by default.
However remember you're in pure binary. The assembler is unaware of what you want,
when you use win32 format the assembler knows about the output which is a Windows x86 32-bit Executable, but When it comes to binary, the assembler is unware of what you want, and hence assumes that you're writing 16-bit code as most of the times pure binaries turn into DOS COMs/Drivers or bootsectors.
But OSDev is an exceptional case, that's the reason you use BITS directive because you're writing both 16 and 32 bit code at the same time, before doing a far jump you should use use16/BITS 16, however you said you didn't set CS, you should keep it use16/BITS 16. The far jump sets CS to the Kernel Code Selector, IIRC you cannot set the value of CS directly unlike the other segment registers.
Something Like:

Code: Select all

Real_Mode:
; Since we are in RM use BITS 16
BITS 16
............
............
mov eax, cr0
or al, 1
mov cr0, eax
; This the far jump that fixes CS
jmp CODE_SELECTOR:PROTECTED
PROTECTED:
; NOW set BITS 32
BITS 32
...........
-Bender
"In a time of universal deceit - telling the truth is a revolutionary act." -- George Orwell
(R3X Runtime VM)(CHIP8 Interpreter OS)
h0bby1
Member
Member
Posts: 240
Joined: Wed Aug 21, 2013 7:08 am

Re: Using multiple BITS statements in one assembly file

Post by h0bby1 »

freecrac wrote:Hello.
Like "h0bby1" said for to switch between the 16 bit realmode and the 32 bit protected mode we need at last a "far jmp" to the codesegment and the changing will first have an effect after this far jmp of which 32 bit attribute correspond to the {bits} directive of the section the code is in.

[bits32]
For to get the 32 bit addressmode we need additional to set the Default-Size-Bit in the codesegmet descriptor before. And if this D-bit is set, then the default size of all operands and addresses of the instructions in this 32 bit-codesegment is 32 bit without to use operand-size and/or address-size prefixes. But if we want to use 16 bit operands and/or 16 bit addresses within the 32 bit mode, then we need one or both of these size-prefixes for each one of this 16 bit instruction for to reverse the default operand- and address-size in the 32 bit codesegment.

[bits16]
If the D-bit is not set, then we get the 16 bit addressmode and all operands and addresses of the instructions in this 16 bit-codesegment is 16 bit without to use operand-size and/or address-size prefixes. If we want to use 32 bit operands and/or 32 bit addresses(80386+) within the 16 bit mode, then we need one or both of these size-prefixes for each of this 32 bit instruction for to reverse the default operand- and address-size in the 16 bit codesegment.

Dirk
it's not only this, but also call and interupt instruction are not the same, as the return address is 16 bit, the stack and iret/ret instruction is different

you can do most of the 32 bit instruction in 16 bit mode, but the opcode will be different, and some opcode have different effect in 16 bit and 32 bit mode like call/int/ret/iret, if you want to make a far call to a 16 bit routine from a 32 bit code segment, need to be careful about how the calls are made, because the call in the 32 bit codesegment will push the return address as 32 bit, but the ret instruction in the 16 bit codesegment will only pop 16 bit return address, same for interupt handling

if you just want to switch from real mode to 32 bit protected, there is two different things that need to be done, first switch the cpu to protected mode which will most change how address and segment register are handled, and then switching to a 32 bit code segment to activate the 32 bit mode of the cpu, when you are in real mode, and just enable protected mode, the cpu is still in 16 bit mode with protected mode memory

so you need to first create a 32 bit code segment in the gdt, then load the 32 bit code in it, or make the segment base at the begining of physical memory, and then switch the cpu to protected mode, and make a far jump to the start address inside of the code segment, with something like jmp 0x08:start_addr, 0x08 is the selector id for the 32 bit code segment, and start_addr the address of the entry point of the 32 bit code relative to the start of the segment
shahsunny712
Posts: 20
Joined: Wed Jan 29, 2014 11:57 am

Re: Using multiple BITS statements in one assembly file

Post by shahsunny712 »

Its clear now.

Thanks a lot for your time on this guys ! :)
Post Reply