That's an interesting topic. When I started Tilck, I used nasm, because I like the Intel syntax and because nasm it's a great assembler. The problem came when I wanted to include header files in both C files and assembly files: I wanted #ifdefs and #defines to work in both places. To do that, I had to manually run the pre-processor on nasm files and have an additional step. Too much complexity. So I decided to switch to GAS: when .S files are passed to gcc, it runs the preprocessor and then GAS. In addition to that, using GAS meant dropping an extra dependency (nasm) from my project, which is
always good.
Now, returning to the topic, I wanted GAS, but I wanted the Intel syntax too. I cannot say that wasn't completely painless going from nasm to gas + intel syntax, but with minor fixes here and there, it worked. And yeah, about the far jump, in my "legacy" bootloader I have code like:
Code: Select all
enter_32bit_protected_mode:
cli
lidt [idtr]
lgdt [gdtr_base_X]
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x08:complete_flush
.code32
complete_flush:
lgdt [gdtr_flat]
jmp 0x08:(BL_ST2_DATA_SEG * 16 + complete_flush2)
complete_flush2:
It works great and it even evaluates literal expressions, that's another feature that I use a lot.
In some cases, I couldn't do a far jump with a register, so I had to use retf (see my comments below):
The fancier thing I had to write was jumping to a 32-bit segment while being in long mode, in order to enter in the "32-bit compatibility mode" (a needed step in order to enter in PM-32 from long mode):
Code: Select all
lea rdx, [rip + compat32]
push 0x08
push rdx
rex.W retf # perform a 32-bit far ret (=> far jmp to 0x08:compat32)
When I wrote it at the time, I found no better way. I'm not sure if nasm could have helped skipping the rex.W prefix or the retf. By taking a quick look now at the table at:
https://c9x.me/x86/html/file_module_x86_id_147.html, I believe that
x86 simply doesn't support a FAR indirect jump with a register. If anyone has a better alternative for the "retf" instructions above, I'd be happy to update my code. But, for the moment, I don't believe it's a GAS limitation.
Still, said that, I didn't know that GAS might generate inferior machine code when the Intel syntax is used. Does it still apply to GCC 7.x ? Are there any historic bugs I can look at? I hope the problem does not exist anymore, because the Intel syntax is *so clean* and using the same GCC toolchain is extremely convenient. Nasm is better per-se but, for the reasons I've explained, remaining in the same toolchain is much more convenient, for me.
Vlad