Page 1 of 1
GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 3:28 am
by leejbaxter
Hi folks,
This is probably going to sound like a really dumb question to the more experienced, but I'm wondering if it's possible to write assembly code for the ARM architecture (more specifically a Raspberry Pi) in Intel syntax? I'm aiming to write a retro gaming OS for the Pi, and I've already generated a naked GNU cross-compiler targetting the ARM using the tutorial within the Wiki. I'll be mostly writing inline assembler within C headers, as I prefer to write my OS in C (of course, I'll use assembler where necessary to boost performance).
My reason for wanting to use Intel syntax is that its what I'm used to, as I've previously used NASM to create a bootloader for the x86 platform (I got to the point where I could search a CD/DVD for a second-stage bootloader contained within a file, load it into memory, and execute it; along the way I could print strings and even integers in any base), so I'm familiar with the Intel syntax. Of course, if I absolutely have to I'll bite the bullet and learn AT&T, but I'd prefer not to.
I'm not quite sure how switching between the 2 syntaxes works; does the compiler simply translate the Intel code into AT&T code (e.g. by swapping operands around .etc.), or is there more to it than that? I've got a feeling that I'll not be able to use Intel-syntax, but I just want to be sure...
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 3:39 am
by pcmattman
Use the syntax GAS expects. The fact this is even a thing on x86 is ridiculous (if you want "Intel syntax", use an assembler like NASM).
Plenty of the online documentation about ARM assembly
uses GAS.
You'll notice it doesn't look much like x86 assembly at all, regardless of whether you prefer "AT&T" or "Intel" syntax or not.
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 3:58 am
by leejbaxter
pcmattman wrote:Use the syntax GAS expects. The fact this is even a thing on x86 is ridiculous (if you want "Intel syntax", use an assembler like NASM).
Plenty of the online documentation about ARM assembly
uses GAS.
You'll notice it doesn't look much like x86 assembly at all, regardless of whether you prefer "AT&T" or "Intel" syntax or not.
I know, I wish I'd gone for using AT&T syntax in the first place when I started learning! I think I need some kind of reference guide for writing assembly code using GNU assembler for the ARM, just until I'm a bit more comfortable with the syntax; can anybody recommend such a guide please?
Thanks in advance!!!
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 4:34 am
by dozniak
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 4:43 am
by jnc100
GAS on ARM doesn't really use either Intel or AT&T syntax - it can be better described as ARM syntax (i.e. that which is specified in the ARM manuals). The opcode syntax isn't exclusively either opcode dest, src or opcode src, dest but the ordering depends on the particular opcode (which you can look up in the manual). For example: mov dest, src; ldr dest, src; but str src, dest. Yes, you have to learn GAS-specific directives for setting code/data segments and labels and constants etc, but aside from that the syntax is exactly as described in the ARM manual.
Regards,
John.
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 6:43 am
by sortie
The GNU assembler only uses the "AT&T syntax" on ix86 and x86_64 platforms. This is for historical reasons and compatibility with old Unix systems (hence AT&T that played a key role in Unix). It uses the native and standard assembler format (with a few extensions) on all other platforms, and it supports quite a lot. On ARM, you will be using the standard ARM assembler syntax, which has the operand order you desire.
I suggest you bite the bullet and learn to like the GNU assembler. It has a bunch of useful features for low-level stuff. It's not really designed for human-written input, but it's designed such that a compiler can feed it a lot of useful information about the code it has generated.
I recommend that you don't do inline assembler in your headers if it can be helped. The modern gcc releases have a lot of builtins that allow you to do the common CPU operations in a manner that the compiler understands and looks much like a function call. This allows it to optimize such code reliably, because it understands what is going on. Better yet, your cross-compiler comes with a lot of useful headers installed somewhere like $PREFIX/lib/gcc/<platform>/<version>/include, there is useful headers for SSE, CPUID, and a lot of things you want to use. These headers are freestanding and is in the default include path, so you can just include them.
Inline assembly is bad because the compiler doesn't understand it. That's also the point. You have to do something that the compiler doesn't normally allow you to. You should use other means if possible, because it allows the compiler to know what is going on. Perhaps you need to do some low-level operation as finding the index of the first set bit. I suggest you write that in portable C and see if the compiler is clever enough to detect this and simply generate the single instruction that does it. This is also why you have to be careful with clobber lists, input and output registers, and the volatile keyword when doing inline assembly. It provides the compiler with a few vague pieces of information what this statement does, but it's not enough for it to do anything clever. It simply outputs the inline assembly verbatim to the assembler, without even looking at it. This has some important consequences. First of all, it cannot optimize the code properly, but it can guess from the clobber list and input/output registers and the volatile keyword. If you lied, then it may optimize the statement incorrectly leading to incorrect code, or even entirely deleting the assembly statement as unused. Secondly, you cannot do anything unexpected, because that also leads to errors. If you do a function call or jump to another function/symbol, things may be seriously screwed. If you change the assembler syntax to Intel syntax as opposed to the default syntax, then the compiler won't know, and it doesn't return to the original syntax, and the following code is assembled incorrectly. Third, it's very hard to do inline assembly properly without being experienced with it and knowing the compiler well, and keeping the documentation close, if you can understand it.
I hope this addresses your concerns.
Re: GNU - Intel Syntax and ARM???
Posted: Mon Jun 10, 2013 8:53 am
by leejbaxter
sortie wrote:The GNU assembler only uses the "AT&T syntax" on ix86 and x86_64 platforms. This is for historical reasons and compatibility with old Unix systems (hence AT&T that played a key role in Unix). It uses the native and standard assembler format (with a few extensions) on all other platforms, and it supports quite a lot. On ARM, you will be using the standard ARM assembler syntax, which has the operand order you desire.
I suggest you bite the bullet and learn to like the GNU assembler. It has a bunch of useful features for low-level stuff. It's not really designed for human-written input, but it's designed such that a compiler can feed it a lot of useful information about the code it has generated.
I recommend that you don't do inline assembler in your headers if it can be helped. The modern gcc releases have a lot of builtins that allow you to do the common CPU operations in a manner that the compiler understands and looks much like a function call. This allows it to optimize such code reliably, because it understands what is going on. Better yet, your cross-compiler comes with a lot of useful headers installed somewhere like $PREFIX/lib/gcc/<platform>/<version>/include, there is useful headers for SSE, CPUID, and a lot of things you want to use. These headers are freestanding and is in the default include path, so you can just include them.
Inline assembly is bad because the compiler doesn't understand it. That's also the point. You have to do something that the compiler doesn't normally allow you to. You should use other means if possible, because it allows the compiler to know what is going on. Perhaps you need to do some low-level operation as finding the index of the first set bit. I suggest you write that in portable C and see if the compiler is clever enough to detect this and simply generate the single instruction that does it. This is also why you have to be careful with clobber lists, input and output registers, and the volatile keyword when doing inline assembly. It provides the compiler with a few vague pieces of information what this statement does, but it's not enough for it to do anything clever. It simply outputs the inline assembly verbatim to the assembler, without even looking at it. This has some important consequences. First of all, it cannot optimize the code properly, but it can guess from the clobber list and input/output registers and the volatile keyword. If you lied, then it may optimize the statement incorrectly leading to incorrect code, or even entirely deleting the assembly statement as unused. Secondly, you cannot do anything unexpected, because that also leads to errors. If you do a function call or jump to another function/symbol, things may be seriously screwed. If you change the assembler syntax to Intel syntax as opposed to the default syntax, then the compiler won't know, and it doesn't return to the original syntax, and the following code is assembled incorrectly. Third, it's very hard to do inline assembly properly without being experienced with it and knowing the compiler well, and keeping the documentation close, if you can understand it.
I hope this addresses your concerns.
Thanks sortie, I've found that's actually the answer I wanted to hear! After poking around on the net to answer my other post (SD card I/O on the Pi), I found an example of MMIO that used pure C instead of inline assembly (as is shown in the tutorial on the wiki), using pointers to access physical addresses (and thus the hardware). I may play with assembler for certain operations later on if I need them, but I think pure C code will suffice (after all, I'm developing a retro gaming system, so it might not need the extra performance power that hand-written assembler provides)...
Thanks to everyone else for clearing things up with the fact that ARM actually carries its own syntax!