x86 is the worst ISA. If you want to play with assembler without feeling a desire to stab yourself and end it all, I recommend ARM. Or go learn Z80, x86's weird, 8-bit cousin (it had a 16-bit version, but it sold poorly), which had a greater emphasis on backwards compatability (you can run code from the original 8080 on a Z80, unchanged), and is nicer to work with (because it wasn't extended in unticipated directions…
> x86 is the worst ISA. I can only assume you've never had to program a Burroughs B90 in assembly language.
Learning to Read X86 Assembly Language
91–100 of 238 posts
Re: Learning to Read X86 Assembly Language
#92Earlier quoted context omitted.
> How do things know where to look? The compiler generates code that uses the correct register. So the compiler picks a register into which it will put the result and then generates code after the calling location that gets the result from the correct register. And yeah, there's quite a bit of surprises. E.g. I found out that gcc is smart enough to perform tail call optimizations https://godbolt.org/g/MZDmwP
OK, so it's not a magical convention - it works it out bottom-up. First decide on registers for each parameter when you generate the code for the function, then based on that generate specific code for the instances where you call that function. Cool, thank you. Also that example, heh. I tried to go back gcc versions to see if there was a case where it didn't do TCO - nope. Also, I like how returning 0 is "xor eax, e…
So the choice of registers cannot be arbitrary, unless the compiler knows the function is only used within an object file.
The registers are predetermined by a convention unless you use the 'static' keyword to signal that the function is only used internally to a module, so the compiler has complete freedom to choose registers.
Re: Learning to Read X86 Assembly Language
#93Earlier quoted context omitted.
> How do things know where to look? The compiler generates code that uses the correct register. So the compiler picks a register into which it will put the result and then generates code after the calling location that gets the result from the correct register. And yeah, there's quite a bit of surprises. E.g. I found out that gcc is smart enough to perform tail call optimizations https://godbolt.org/g/MZDmwP
OK, so it's not a magical convention - it works it out bottom-up. First decide on registers for each parameter when you generate the code for the function, then based on that generate specific code for the instances where you call that function. Cool, thank you. Also that example, heh. I tried to go back gcc versions to see if there was a case where it didn't do TCO - nope. Also, I like how returning 0 is "xor eax, e…
Re: Learning to Read X86 Assembly Language
#94Earlier quoted context omitted.
They're not as common reasons. But yes, if you want to program your TRS-80 (but only the original: later ones were 6502), or your ZX* (How many of you lot know the ZX line? Spectrum? No?), or your Game Gear, or your Master System, or any of the various CP/M machines, you have to learn Z80.
How many of you lot know the ZX line? Spectrum? No? The ZX Spectrum and its clones were very popular in the UK, Eastern Europe, and the former USSR.
Re: Learning to Read X86 Assembly Language
#95Earlier quoted context omitted.
I never felt more like stabbing myself than when trying to cipher out exactly which immediate values are possible on ARM, and which are not. X86 I happen to enjoy. It is not "the worst ISA" by any means. It has wonderful code density, which turns out the be very important. There's a reason that x86 won and continues to win.
When originally invented the x86 instruction set was efficient - the most-used instructions had shorter byte code sequences. But eventually some instructions got 'left behind' by the compilers. There are a whole host of single-byte instructions that are never, ever used by a compiler - the register exchange instructions for instance (xchg eax, ebx). Compilers just schedule destination registers carefully, never need…
Compilers just schedule destination registers carefully, never need to swap them around.
Actually, it can happen with certain instructions that need fixed register constraints (multiply, divide, string ops) --- I've encountered a few cases where, had the compiler knew about the exchanges, it could've avoided using another register or spilling to memory. As far as I know, in modern x86 cores the reg-reg exchanges are handled in the register renamer, so they aren't slower than using an extra register and definitely faster than spilling to memory (which might happen anyway for something else if it needed the extra register.)
To witness, here is something no compiler (software) I know of can generate, even when given code that could generate it:
theloop:
xchg eax, edx
add eax, edx
loop theloop
Never say never ;-)Re: Learning to Read X86 Assembly Language
#96Earlier quoted context omitted.
I agree that the x86 ISA is pretty warty (though I have a strange fondness for it), but I'd recommend 6502 rather than Z80. There are a lot of fun retro-computer platforms that are 6502-based. Thinking of the zero-page functioning as a register-bank is really fun, too.
For 8-bits I'd recommend the 6809. Two 8-bit accumulators that can be used as a 16-bit accumulator, 4 16-bit index registers (that can largely be interchanged, except for S which is also the stack register) and you can generate pure relocatable code. And the zero-page isn't restricted to address $0000.
Re: Learning to Read X86 Assembly Language
#97Earlier quoted context omitted.
I wish 68k, but it's out of production (as is the 6809, its equally awsome 8-bit cousin). MIPS and ARM are fun, though, AFAICT. As is 6502.
(author here) ...FYI I actually learned assembly language for the first time back in the 1970s and 80s using a 6809 inside a Radio Shack "Color Computer." I was super-fun at the time. I don't remember much of it now but I'm sure x86 isn't as clean or fun as 6809 assembly was.
Re: Learning to Read X86 Assembly Language
#98Earlier quoted context omitted.
I wish 68k, but it's out of production (as is the 6809, its equally awsome 8-bit cousin). MIPS and ARM are fun, though, AFAICT. As is 6502.
If you want something friendly and CISC-y and modern, check out the Renesas RX600 and friends. They have a nice instruction set and zero-wait-state RAM and ROM, so writing assembly by hand with predictable timing ought to be easy. https://www.renesas.com/en-us/doc/products/mpumcu/doc/rx_fam...
Re: Learning to Read X86 Assembly Language
#99Earlier quoted context omitted.
...But how many of those instructions are just variants of other instructions, but with a different addressing mode?
Fair enough, some instructions have many variants. But I work with ARM assembly almost daily and I still wouldn't remember that, for example, 'VQRDMULH' is a real instruction and it stands for 'Vector Saturating Rounding Doubling Multiply Returning High Half'.
I should probably count up x86 against ARM, so I have more than guesses to go on here. Maybe that part of x86 actually better.
Re: Learning to Read X86 Assembly Language
#100Break your programs into basic blocks! Reverse engineers never read assembly in a straight line. Instead, they read the control flow graphs of subroutines, which is the graph where nodes are runs of instructions ending in jumps and branches, and the edges are the jump targets. I hope this doesn't sound complicated, because it isn't: it's literally just what I wrote in this paragraph. It takes about 15 minutes for most platforms to learn enough to recover CFGs from subroutines by hand.
To get a decent understanding of what a chunk of assembly code is doing, all you really need is:
* The code broken into subroutines (this is usually your starting point) and then CFGs (good disassemblers do this for you, but it's easy to do by hand as a first pass)
* The CALLs (CALLs don't end basic blocks!)
* The platform's calling convention (how are arguments passed and return values returned from subroutines)
There are two tricks to reading large amounts of assembly:
1. Most of the code does not matter, and you won't be much better off for painstakingly grokking it.
2. Virtually all the assembly you'll see is produced by compilers, and compilers spit out assembly in patterns. Like the dude in The Matrix, after an hour or so of reading the CFGs of programs from a particular compiler, you'll stop having to read all the instructions and start seeing the "ifs" and "whiles" and variable assignments.