Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This. The AT&T syntax for x86 thing is a huge mistake. All the official docs are Intel syntax. Intel syntax is easier to read and write. Half the gotchas in this article are problems that don't exist in Intel syntax, like the instruction suffixes. The instruction suffixes get even weirder when you get to the sign extending instructions. I wrote an article about this here: http://blog.reverberate.org/2009/07/giving-up-on-at-style-as...


The AT&T syntax for x86 thing is a huge mistake.

For someone who grew up on normal processors (MC68000 and UltraSPARC) AT&T syntax is the best thing since sliced bread: it's perfectly logical to move something to somewhere, instead of "move to somewhere something".


I haven't done any 68K Asm and barely glanced at SPARC, but how does src, dst interact with noncommutative operations like subtraction and comparison? E.g. with x86 Intel syntax,

    cmp eax, 5     ; eax - 5
    jg morethan5   ; eax > 5 ? then jump.
    sub eax, ecx     ; eax = eax - ecx
This is one of the most confusing things about AT&T x86 --- the comparisons and subtractions have their operands reversed, and you have to identify and manually reverse them to understand the code correctly. With Intel syntax, the operands to a subtraction appear in the usual arithmetic order. Or do those processors' syntax keep the order but instead replace the subtrahend with the result??

    sub A, B    ; B = A - B ??


Exactly this. The instruction set is designed around Intel syntax. When you flip operands around because you prefer a different ordering, it messes up things like jg/ja/jl/jb/etc.

And it's all arbitrary anyway. Some people might prefer a [src, dest] ordering, but it's not inherently any more natural than [dest, src]. Look at variable assignments: "x = y" in almost any programming language will assign y to x.


Yeah but in most assemblers you're not setting, but either loading or moving values into something, or from somewhere. Because of that, one never has to think in terms of x = y.


What is the difference between "setting" and "loading or moving"? I can't see any semantic difference between "eax = edi" and "mov eax, edi".


None, but in assembler one simply doesn't think in terms of x = y, it's not necessary.


This is one of the most confusing things about AT&T x86 --- the comparisons and subtractions have their operands reversed,

That is confusing as all hell to me: if I compare x to 5, and 5 to x, it's still the same comparison, so what difference does it make?

Anyway, on Motorola 68000 it would look like so, assuming data was in data register 0 (there are eight general purpose data registers, and eight general purpose address registers):

  cmp.l #5, d0    ; d0 is unchanged by the comparison
  bgt MoreThanFive
  ;
  ; substract the value of d1 from d0, and store the result
  ; in d0.
  ;
  sub.l d1, d0
however, we don't usually branch if greater or lower; we simply compare whether a register is equal to some value:

  cmp.l #5, d0
  bne NotFive


in x86 assembly it matters because what is comparison exactly? cmp is (very cleverly) defined as equivalent to sub (subtraction) without storing the result, only setting the flags.

the jump if greater/lesser/equal/greater-or-equal/etc instructions are all defined in terms of checking the sign, zero, carry and overflow flags. for instance, jz and je are the same instruction. you just use one or the other if it makes more sense in context (I used to write asm by hand for the art of 4096 byte demos)

I used intel notation, because that's what the Asphyxia tutorials and turbo pascal used. So it's what I'm used to. I don't have much of an opinion about the order except that it was an idiotic decision to swap it, either way, the confusion that caused doesn't weigh against if/which one would be more theoretically "right". All the sigils and pre/postfixes seem messy though.


>That is confusing as all hell to me: if I compare x to 5, and 5 to x, it's still the same comparison, so what difference does it make?

I haven't done assembly code for a while, and was not an expert at it earlier, so guessing, but:

it may be because of what flags in the flags register (if there is one nowadays) get set - they could be different for the two versions of your comparison.


Yes, there is a status register, every processor must have one (or else the processor couldn't function). Doesn't matter whether you compare 5 to a register (or memory location, depending on the processor), or memory / register to 5, the same bit(s) will still be set in the status register.


>Doesn't matter whether you compare 5 to a register (or memory location, depending on the processor), or memory / register to 5, the same bit(s) will still be set in the status register.

Are you sure? That was my whole point - that it may not be that way. As I said, it's been a while, but it seems to me that the bits that get set in the flags/status register, on comparing A to B, should be, in some sense at least, the opposite (maybe not for all the bits) of what would get set on comparing B to A; because I thought it would be done by subtracting A from B or B from A, and then setting (some of) those flag bits based on which was greater or equal. If that is so, comparing A to B will not have the same result in the register as comparing B to A. And the reason why I think so, is that there are assembly instuctions like JGE (Jump if Greater or Equal), JE (Jump if Equal), JNE (Jump if Not Equal), etc. - the meaning of those instructions would get changed and so would the resulting action (jump or not jump) based on the looking at the flags set on comparing A to B vs. B to A.


You're overthinking this way more than you need to.

On any given processor, in this context, there is one and only one way to compare an immediate value with one in a register, so you don't have to worry about whether you're comparing 5 to %eax, or eax to 5: you can't subtract the value in %eax from 5, because 5 is an immediate value, not a memory location.

  	.section	__TEXT,__text,regular,pure_instructions
  	.globl	_main
  	.align	4, 0x90
  _main:
  	movl	$17, %eax
  	cmpl	$5, %eax
  	jle	Exit
  	movl	$5, %eax
  Exit:	ret
now let's assemble and link that using the C compiler's front end, so we won't have to worry about _init and _fini:

  > cc cmp.s -o cmp
  > ./cmp; echo $?
  5
note the cmpl $5, %eax instruction. Now watch what happens when I attempt to compare %eax with 5:

  	.section	__TEXT,__text,regular,pure_instructions
  	.globl	_main
  	.align	4, 0x90
  _main:
  	movl	$17, %eax
  	cmpl	%eax, $5
  	jle	Exit
  	movl	$5, %eax
  Exit:	ret

  > cc cmp.s -o cmp
   cmp.s:6:13: error: invalid operand for instruction
   cmpl %eax, $5
              ^~
it can't be done, because there is one and only one way to compare an immediate value with one in a register. intel or AT&T syntax -- dst, src or src, dst -- the comparison is the same. Therefore, AT&T syntax is the best thing since sliced bread, because it's left to right instead of right to left, which is how we think in terms of taking something and moving it somewhere -- in the physical world, step 1. will be to take an object and step 2. will be to move that object somewhere.


I think we might be talking about different things, or past each other. Let it go.


Thats only part of the syntax differences between AT&T and Intel.

Also, "move destination, source(s)" is consistent regardless how many sources there are (although I agree with you that "source -> destination" is more intuitive for us left-to-right people).


I prefer Intel syntax and admit that you have a good argument in your article why the AT&T syntax might be problematic, but for newer extensions (SSE etc.) the instruction naming in Intel syntax actually converged towards AT&T syntax: Just to give an example from SSE2 (from http://softpixel.com/~cwright/programming/simd/sse2.php):

  paddb - Adds 16 8bit integers.
  paddw - Adds 8 16bit integers.
  paddd - Adds 4 32bit integers.
  paddq - Adds 2 64bit integers.


That's not really "AT&T syntax", since the suffixes here are denoting how the MMX/XMM register is being split up and not the whole operand size. Those instructions can still be used with either the 64-bit MMX or 128-bit XMM registers:

    paddb mm0, mm1
    paddb xmm0, xmm1
If it was really more like "AT&T" style (I don't know how GNU really does this, so I'm guessing), it would be more like paddqb for MMX and paddob for SSE.


I accept the argument that the suffixes mean something a little different in these SSE2 instructions than in the "classical" x86 instructions. But I think it should be clear where these suffixes come from (thus there is some convergence of the Intel syntax for new instruction towards the AT&T syntax). And indeed the instructions paddb, paddw, paddd, paddq are the same on Intel and AT&T syntax. Look at

> https://docs.oracle.com/cd/E19253-01/817-5477/817-5477.pdf

First convince yourself (for example by looking at page 26-39) that in the individual tables the column "Solaris Mnemonic" stands for the AT&T syntax and the column "Intel/AMD Mnemonic" stands for the Intel syntax.

Now look at page 48. Surprise: It is paddb, paddw, paddd, paddq both in Intel and AT&T syntax.


Additionally Intel syntax Macro Assemblers offer higher level constructs providing almost C like experience while using machine opcodes.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: