views:

79

answers:

3

Hello. I am using NASM to assemble my assembler code. The code I assembled looks like this:

[BITS 32]
[ORG 0]
  jmp 07c0h:start

  testvar db 0, 0, 0, 0, 0, 0, 4, 8, 15, 16, 23, 42

start:
  mov byte [testvar], 47

  hang:
    jmp hang

  times 510-($-$$) db 0
  dw 0AA55h

I had problems with another piece of code, I noticed that I couldn't modify memory, so I wrote this piece of code to test if that was actually the case. It was! I copied the assembled machine code to the first sector of a floppy, the program ran (I used MS VirtualPC). I checked RAM memory assigned to Virtual PC and searched for numbers 4 8 15 16 23 42, so that I could find where the binary code was copied. The first byte of the data was not touched. Why is it so?

A: 

My understanding is that PC compatible machines all start in 16 bit mode (for compatibility reasons). So it seems to me that you need to begin with [BITS 16], even if the first instruction is a jump to to 32 bit mode and is immediately followed by [BITS 32]. See NASM: Mixing 16 and 32 Bit Code.

I'm a little fuzzy on the floppy boot process. Are you sure the code is located where it will actually be executed? Is it possible to single-step through that code?

David Cary
The bootsector is always loaded to physical address 0x7C00, but not all BIOSes agree on the CS:IP used to refer to this address (keep in mind the wacky way 16bit realmode addressing works: seg*16+ofs).
snemarch
+4  A: 

The simple answer is that the same code assembled as 32 bit is different than that assembled as 16 bit. Boot sector code (and all loaded code) is run in 16 bit real mode until the CPU mode is switched.

The happy answer is a listing shows the difference.

                                                [BITS 16]
0000000C: C6 06 00 00 2F                          mov BYTE [testvar], 47

The same code as 32 bit

                                                [BITS 32]
0000000C: C6 05 00 00 00 00 2F                    mov BYTE [testvar], 47

The equivalent code when run as 16 bit

                                                [BITS 16]
0000000C: C6 05 00                                mov BYTE [di], 0
0000000F: 00 00                                   add [bx+si], al
00000011: 00 2F                                   add [bx], ch
Mike Gonta
Then are you saying that if I was to load a 32bit code from my 16bit bootsector and jump to it, that 32bit code would work properly, while the bootsector itself being 32bit wouldn't?
Neo_b
No. First whatever you are loading must change to a 32-bit mode.
Marco van de Voort
+2  A: 

Setting "BITS 32" in your source file only affects the opcodes the assembler spits out.

To execute 32bit code, you'll need to change the processor mode to, surprise surprise, 32bit protected mode. Typically, when moving a bit beyond your very first toy bootsector, you'll do your kernel loading in multiple steps. First, the 16bit bootsector, with all it's size constraints. This loads a 16bit bootloader, which in turn can set up protected mode. Some designs keep this 16bit part minimal and further uses a 32bit bootloader for loading the kernel, other designs load the kernel directly from the 16bit bootloader.

I suggest you take a look at http://wiki.osdev.org/Main_Page , http://www.asmcommunity.net/ and http://board.flatassembler.net/ :)

snemarch
I've already been to osdev.org, thanks for the other addresses. ;-)
Neo_b