When writing boot sectors, loaders, and kernels, you need to tell the compiler and assembler whether to output 16-bit real mode code, 32-bit real mode code, or 32-bit protected mode code. The NBC compiler gives this functionality using #pragmas.
Let's start out with the C source code:
#pragma optimizer(off)
#pragma ptype(rmode)
#pragma proc(186)
void do_32bit_real();
void do_32bit_pmode();
int main() {
int i = 0;
if (i == 1) {
i = 0;
}
do_32bit_real();
}
#pragma proc(386)
void do_32bit_real() {
int i = 0;
if (i == 1) {
i = 0;
}
do_32bit_pmode();
}
#pragma ptype(pmode)
void do_32bit_pmode() {
int i = 0;
if (i == 1) {
i = 0;
}
}
Now for the produced assembly code.
(Please note that I instructed NBC to include the C source lines)
.model tiny
.code
; //.optoff // we don't want anything changed unknowingly
; #pragma optimizer(off)
.optoff
; //.rmode // bios starts with (un)real mode
; #pragma ptype(rmode)
.rmode
; //.186 // only allow 80x86 code at start
; #pragma proc(186)
.186
; // prototypes here
; void do_32bit_real();
; void do_32bit_pmode();
; /* As with many boot sectors and loaders, your code may start
; * out in 16-bit real mode. However, once you have done what
; * you need to do in real mode, you can then move to protected
; * mode.
; * With this example, I will show that the first part of this
; * code, the main() function, will be in 16-bit real mode.
; * Then it will call a function that is in 32-bit real mode
; * to show the 32-bit conditional jumps, yet still in real mode.
; * Then this function will call a 32-bit pmode code to show the
; * output of that function.
; * Please note that this example is to show how to make NBC emit
; * 16-bit or 32-bit code. This example in now way has the code
; * to actually switch the processor from one to the other.
; */
; int main() {
_main:
push bp
mov bp,sp
jmp L2
L1:
; int i = 0;
mov ax,0
mov [bp-2],ax
; // the 'i' above is 16-bit. You will be able to see this
; // in the .asm output shown below.
;
; // now let's do something with this 'i' and then show a
; // conditional jump to see the 16-bit jump.
; if (i == 1) {
mov ax,[bp-2]
cmp ax,1
je L6
jmp L5
L6:
; i = 0;
mov ax,0
mov [bp-2],ax
; }
L5:
; do_32bit_real();
call _do_32bit_real
mov ax,0
L3:
mov sp,bp
pop bp
ret
L2:
sub sp,2
jmp L1
; /* Allow 32-bit code.
; * Please note that we are still in real mode. However, the
; * .asm out code will now use 32-bit assembly along with 32-bit
; * conditional jumps.
; */
; #pragma proc(386)
.386
; void do_32bit_real() {
_do_32bit_real:
push ebp
mov ebp,esp
jmp L9
L8:
; int i = 0;
mov eax,0
mov [ebp-4],eax
; // the 'i' above is 32-bit. You will be able to see this
; // in the .asm output shown below.
;
; // now let's do something with this 'i' and then show a
; // conditional jump to see the 32-bit jump.
; if (i == 1) {
mov eax,[ebp-4]
cmp eax,1
jne L12
; i = 0;
mov eax,0
mov [ebp-4],eax
; }
L12:
; do_32bit_pmode();
call _do_32bit_pmode
L10:
mov esp,ebp
pop ebp
ret
L9:
sub esp,4
jmp L8
; /* Allow 32-bit protected mode code.
; * Please note that we are now in protected mode code. The
; * overrides (66h and 67h) or now the opposite of above.
; */
; #pragma ptype(pmode) //.pmode
.pmode
; void do_32bit_pmode() {
_do_32bit_pmode:
push ebp
mov ebp,esp
jmp L16
L15:
; int i = 0;
mov eax,0
mov [ebp-4],eax
; // the 'i' above is still 32-bit.
;
; // now let's do something with this 'i' and then show a
; // conditional jump is still a 32-bit jump
; if (i == 1) {
mov eax,[ebp-4]
cmp eax,1
jne L19
; i = 0;
mov eax,0
mov [ebp-4],eax
; }
L19:
L17:
mov esp,ebp
pop ebp
ret
L16:
sub esp,4
jmp L15
.end