OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Mar 03, 2021 8:32 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Intel syntax with GAS?
PostPosted: Tue Dec 15, 2020 7:38 pm 
Offline
Member
Member

Joined: Wed Apr 01, 2020 4:59 pm
Posts: 65
The wiki article on GAS recommends not using GAS's intel syntax. It gives two reasons:

  1. Even in intel mode, operands are reversed in some cases
  2. Assembly produced may be suboptimal

1 is certainly true, but only applicable to a small number of x87 instructions which should be avoided anyway. 2 seems to have been fixed; at least, I was unable to reproduce it:

Code:
$ cat testatt.s
.code16     ; NB. I get the same results in 64-bit mode
f1:
mov $5, %si
mov %di, %si
mov %ax, %si
movsx %al, %si
movsb (%si), (%di)
$ cat testintel.s
.intel_syntax noprefix
.code16
f1:
mov si, 5
mov si, di
mov si, ax
movsx si, al
movsb [di], [si]
$ as testatt.s -o testatt.o && as testintel.s -o testintel.o
$ diff test{att,intel}.o && echo same
same


Should the wiki page be updated? Are there any other reasons people know of for avoiding GAS's intel syntax? It's worked great for me, personally.


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Mon Dec 21, 2020 5:42 am 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9289
Location: On the balcony, where I can actually keep 1½m distance
Your average bootloader example contains something like
Code:
jmp far 0x0008:0x00010000
On my system's binutils 2.33.1, that still gives
Code:
astest.s:4: Error: junk `0x0008:0x00010000' after expression

Have fun figuring out the correct syntax if you don't know it already. Hint: it's not in the intel or amd manuals :wink:

_________________
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Mon Dec 21, 2020 7:01 am 
Offline
Member
Member
User avatar

Joined: Tue Feb 18, 2020 3:29 pm
Posts: 639
It may be hard enough to figure out GAS syntax to begin with! Luckily, I found a document on the net (forget where) that saved me a few weeks ago when I switched to GAS.

_________________
Currently working on the Nexware project, an attempt to make a less bloated version of GNU. All repos for it can be found at https://github.com/Nexware-Project.


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Tue Jan 12, 2021 2:12 am 
Offline
Member
Member
User avatar

Joined: Fri Mar 01, 2019 3:50 pm
Posts: 39
Location: France
Combuster wrote:
Your average bootloader example contains something like
Code:
jmp far 0x0008:0x00010000
On my system's binutils 2.33.1, that still gives
Code:
astest.s:4: Error: junk `0x0008:0x00010000' after expression

Have fun figuring out the correct syntax if you don't know it already. Hint: it's not in the intel or amd manuals :wink:

It is indeed tricky to find equivalents of the Intel syntax while using GAS, that's why I'm going to take the opportunity to give the equivalent of your given instruction here so that people don't have to figure out the hard way (as I did!) :P
Code:
ljmp $0x8, $0x10000


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Mon Feb 15, 2021 2:07 pm 
Offline
Member
Member

Joined: Fri May 11, 2018 6:51 am
Posts: 75
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:
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):
Code:
   push 0x08
   push esi
   retf
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:
   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

_________________
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Mon Feb 15, 2021 4:35 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 2815
vvaltchev wrote:
I'm not sure if nasm could have helped skipping the rex.W prefix or the retf.

NASM will accept "retfq" in place of "rex.w retf".

vvaltchev wrote:
If anyone has a better alternative for the "retf" instructions above, I'd be happy to update my code.

Store the destination far pointer in memory and use a far JMP with a memory operand. Using RET without a corresponding CALL can mess up the branch prediction.

Whether or not that's actually better depends on what metric you're using.

vvaltchev wrote:
Intel syntax is *so clean*

NASM syntax is clean. Intel syntax is ambiguous.

In NASM syntax, a symbolic operand without brackets around it is an immediate operand. In Intel syntax, a symbolic operand without brackets around it may be either an immediate operand or a memory operand, and you have to look at how that symbol is defined to know which one it will be.


Top
 Profile  
 
 Post subject: Re: Intel syntax with GAS?
PostPosted: Mon Feb 15, 2021 5:14 pm 
Offline
Member
Member

Joined: Fri May 11, 2018 6:51 am
Posts: 75
Octocontrabass wrote:
NASM will accept "retfq" in place of "rex.w retf".
Ah, thanks! Also, I just noticed that the comment near the "rex.w retf" is just wrong :-)
Octocontrabass wrote:
Store the destination far pointer in memory and use a far JMP with a memory operand. Using RET without a corresponding CALL can mess up the branch prediction.
Yeah, I thought about that.. I just preferred avoiding it. Maybe is better, but I have mixed feelings. Performance it's not important as it happens just once when switching to PM32 before jumping to the kernel. But I totally agree with your argument.
Octocontrabass wrote:
vvaltchev wrote:
Intel syntax is *so clean*

NASM syntax is clean. Intel syntax is ambiguous.

In NASM syntax, a symbolic operand without brackets around it is an immediate operand. In Intel syntax, a symbolic operand without brackets around it may be either an immediate operand or a memory operand, and you have to look at how that symbol is defined to know which one it will be.
You're totally right. With "intel" I meant the nasm/intel syntax compared to AT&T. But yeah, when compared to Intel, the NASM dialect is much better. I remember that I hit myself the ambiguities you're talking about.

_________________
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group