views:

598

answers:

8

I feel extremely comfortable dealing with 32-bit PowerPC assembly code, but I am completely lost when trying to make sense of x86 code. Do any of the other common architectures like ARM, MIPS, Sparc etc have an easier than x86 instruction set?

+3  A: 

I guess you should define what "easy" means for you.

I'd rather judge machine languages in terms of orthogonality (meaning: any part of an instruction can be replaced by alternatives and still give a valid instruction)

  • command (add, sub, mul, div)

  • parameters (register, memory, literal)

  • parameter size (byte, word, long, float)

  • consistent order of parameters (source x source -> dest, or dest <- source x source)

and capability / complexity of instructions

  • number of registers available

  • indexed addressing

  • implicit/explicit parameters

and others.

Probably you should give examples of which parts of x86 you deem as "not easy" in comparison to other architectures, and why.

devio
+2  A: 

ARM, and that's speaking from the point of view of someone in the middle of writing the final stages of an assembler. Here's the Architecture Reference Manual to get you started.

Edit: For some reason I assumed you meant machine code format. X86 assembly is easy - assembling it to machine code...not so much.

280Z28
I personally find ARM fairly confusing and difficult to read; Thumb mode is easier than 32-bit mode. For example, these multi-register push operations, with arbitrary stack pointers, or the add operation that has also a shift in it - they are quite confusing.
Martin v. Löwis
@Martin: Like I said, ARM is easier for machine code but X86 is easy for assembly language. :)
280Z28
Just out of curiosity, why is parsing / assembling x86 assembly so hard?
DrJokepu
@DrJokepu: The instructions are not a fixed size - short form instructions save space when you can use them. Many of the addressing modes use offsets in code, and the offsets change when the instructions change size - in turn the updated offsets can allow or prevent new instructions from using the short form.
280Z28
+3  A: 

Without a definition of "easy" im pretty sure most people would agree that the x86 instruction set is easily the most horrible for a mainstream popular CPU.

If one were to write up a list of good or best practices one should follow when designing an instruction set, the x86 would be a good example of all the opposites.

  • Not orthogonal, not all registers are equal in functionality.
  • Small limited number of specialised registers - results in too many stack operations.
  • Nasty prefix operators.
  • ...
mP
I think these properties primarily describe the simplicity of the implementation (i.e. of the microprocessor chip design). I don't think they affect ease-of-learning in a significant way (but surely contribute to the pain).
Martin v. Löwis
+2  A: 

I think the phenomenon you are experiencing is that the second assembler language is (again) difficult to learn (I assume learning PPC was also difficult when you started, back then). It gets easier the more new architectures you familiarize with - at some point, you'll enjoy finding some architectural (mis)feature that you had never seen before.

The problem with the second architecture is that you are not yet clear on what is common practice, and what is specific to the first architecture. So you expect certain things to be done on x86 the same way as they were done on PPC, when in fact x86 has its own (possibly even more elegant) way of doing stuff.

Martin v. Löwis
+2  A: 

I learnt ARM assembly and find it quite easy and powerful. I don't think shofting operands and such things confusing. At least because I learnt ARM asm first and then I read something about x86 asm.

I find that most features missing on x86 are points of strenght on ARM, for example multiple register store/read and conditional execution. Pl.us, I find very helpful having so many registers.

I think this is the usual 'religion war' RISC vs CISC, ARM vs x86. IMHO is too much subjective to be a universal principle. For example Martin v. Löwis finds ARM unelegant, while I find it so much more elegant than x86.

I also gave a shot at a microcontroller asm (Texas Instruments, can't recall the exact model name) and found it quite unelegant, while many other people may find it the 'perfect' asm.

klez
+1  A: 

Go with ARM. After 20 something years as a software engineer I write assembler every day for various platforms but never need to write x86 assembler. Partly because it is horrible, partly because I would never embed an x86 so I only run desktops/laptops with x86 and C or whatever you want to run on linux/windows is low level enough.

dwelch
+2  A: 

The Devil's Advocate Defends x86 Architecture

I'm not going to defend the MS x86 assembler itself, but see here for my comments on it. (You might want to go with the gnu one, possibly via Cygwin.) And certainly the lack of registers, the special-purpose nature of most of them, and the odd, twisted, non-orthogonal organization of the whole thing did seem to represent a classic don't do it this way example. Oh wait, how about hugely elaborate features of just epic complexity, that no one ever wanted or ever really used? You know, the segmentation unit?

Regarding the difficulty of learning, I think it's fun to write x86 assembly, though I can't quite put my finger on why that is. No instruction set architecture is really all that complex, so I think you will be able to comprehend x86 with a reasonably small level of effort, although I agree it's certainly got more elements than a RISC ISA. But it's fun, a few unusually subdivided registers, some other special purpose ones, and a number of instruction formats, but mostly using the same 1.5 address format.

Back to the defense:

On Lack of Registers: This didn't matter in the end. Even the RISC architectures eventually went to register renaming, despite their boatload of architectural registers they still needed more for performance. So x86 is maybe better, because everyone gets zillions of automatic renamed ones but x86 only needs to save a small number of arch registers.

On Complex ISA: Intel always handled this, at first with brute force superior process technology (the 286 was quite fast in its day) and today by translation: the x86 opcodes in RAM are transcoded into micro-ops as they are read into cache, thus isolating the CPU core from x86! Today, x86 is kind of an "instruction compression" scheme, just an encoding that is unravelled as program code is read by the CPU. Somethings they split instructions, sometimes they combine consecutive ones, and sometimes they just translate them.

DigitalRoss
Very good post, +OVER 9000
DrJokepu
+2  A: 

Well, most RISCs are very much alike, so if you know the PPC well, then transitioning to ARM, MIPS, or SPARC will all be a snap. I actually learnt SPARC first and then was able to pick up a MIPS and the PPC in a couple of hours.

The thing that makes the x86 so confusing isn't really its assembly language, but the design of the processor. People tend to get hung up on:

  • Segmented memory addressing -- all those ds, cs, es registers: what do they mean, how are they combined with an index register to make a fully resolved memory address? There's actually three different ways that happens, so you're learning a bunch of different modes.
  • Nonorthogonal instruction set -- some instructions only work with certain registers, other instructions have meanings that overlap, some things look like they should be fast but are really slow, etc.
  • Register-memory architecture -- the x86 is designed to have few (named) registers, so that each opcode usually has one argument that is a register and another argument that is a memory address. This is different from the PPC's load-store arch, where the memory operations are explicit. Since the stack pointer tends to bounce around a lot, this can make it hard to figure out which variable is really being used!
  • Spastic stack pointer -- where most PPC calling conventions have you move the stack pointer just once on entering a function and then once when returning, typically x86 code will be pushing and popping all over the place. You end up counting the pushes and pops to figure out just where your stack pointer has gotten to, which always makes my head hurt.

So, to get comfortable with the x86, divide and conquer: pick one of those points, learn how it works, then move on to the next. It may help to start by learning the calling conventions first, because that'll make all the other instructions that reference the stack pointer make more sense.

Crashworks
Is the "spastic stack pointer" dictated by the hardware or is it an ABI thing?
sigjuice
It's somewhere between ABI and hardware. You could theoretically use stack like a RISC chip, but there are a bunch of flow control instructions (`ret`, `enter`, `leave`, etc) that implicitly assume moving the stack pointer around. And every compiler I've seen uses `push` and `pop` in that way, which makes theoretical possibilities a moot point for me since my primary use of x86 assembly is to debug or interface with code that a compiler has generated.
Crashworks