Real mode is 16-bit.
What you've got there looks like a dos .com file. Lose the "bits 32", and it ought to work.
If, if fact, you want to switch from real mode to protected mode (16- or 32-bits... you want 32, of course. 16-bit pmode exists, but isn't much used), we can provide an example of that. I see no sign of trying to do so in this code.
Assuming you're running Windows, or Linux, or BSD, or MacOSX, or so - you're already *in* 32-bit protected mode. The bad news is, you can't access hardware directly. If you *could* shove a pixel/character onto the screen directly, you wouldn't want to - might not be "your turn". "Protected mode" is protected from *us*, I'm afraid!
The fact that you end with "jmp $" suggests that maybe this is intended to run from a bootsector. That *would* allow you to switch to 32-bit mode, but not as simply as saying "bits 32". You'll have to create and load a Global Descriptor Table, alter cr0, make a far jump to reload cs with a 32-bit code selector. Now we're in 32-bit mode! But... you can't *do* much (like enable interrupts - they've got to be disabled for this) without providing 32-bit code to handle interrupts and load an IVT... Unless you're writing an OS, you don't want to mess with it!
If, by some chance, you've already switched to 32-bit pmode, you'd want to load gs with a selector pointing to a descriptor with a "base" of zero, and use 0xB8000 as an offset (the common way), or with a base of 0xB8000 and start from offset zero. Unless you've got a *lot* of descriptors in your GDT, 0B800h will not be a valid selector!!!
The CPU is in 16-bit mode or 32-bit mode, depending on cr0 and (if cr0 & 1) a bit in the code descriptor. We tell Nasm whether we want to generate 16- or 32-bit code with "bits 16" or "bits 32" (default varies with output format - 16-bits for "-f bin"). They'd *better* match!!!
If you don't understand why, try disassembling your code with "ndisasm -b 16 -o 100h myfile.(com? bin?)". This is what the CPU will see if it encounters your code in 16-bit mode. Now try it with "-b 32". Try it with and without "bits 32" in your file. Notice how many bytes are used to store, for example, "0B800h". See why "mix and match" won't work?
So... what are you trying to do?
Best,
Frank
(incidentally, with "org 100h", you're already aligned to 256 bytes, so "align 32" isn't going to do anything...)