Live data from Hacker News

Learning to Read X86 Assembly Language

patshaughnessy.net

201–210 of 238 posts

Re: Learning to Read X86 Assembly Language

#201

Earlier quoted context omitted.

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 m…

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

Re: Learning to Read X86 Assembly Language

#202

Earlier quoted context omitted.

> There are only two common reasons to learn Z80 assembler, though: to program the Gameboy [...] and to program a TI calculator What about the myriad of other (mostly vintage) computer systems and video game consoles out there? ;) Sega Master System and Game Gear, for example.

The Game Boy doesn't quite use a Z80 --- like the Z80 it's based on the 8080, but in a different way. So you don't get things like the IX and IY or the alternate register banks, but you do get things like (a very crude set of) stack-relative addressing modes, which makes it a better fit for modern programming languages than the Z80. http://gbdev.gg8.se/wiki/articles/CPU_Comparision_with_Z80 As an aside: most of the o…

As I understood it, the GB is based on the Z80, not the 8080: That's why its nickname is the GBZ80.

>If you look at the instruction encodings, the Z80's actually a pile of nasty hacks. The original 8080 is way more elegant; and there's lots of software and tooling for it, too. (But it still can't run C efficiently.)

I don't know about what makes an instruction encoding elegant or inelegant, so can't help you there.

Yes, the 8080 is probably more elegant, but the extra features on the Z80 are incredibly useful (especially register exchange: The Z80 had two sets of registers, which you can exchange. No, Zachtronics didn't make that up: that was a real thing, on the Z80 at least). Also, the Z80 tooling is quite nice: asxxxx and WLA-DX are fine assemblers, and SDCC is a pretty good C compiler. It sure as heck beats cc65, in any case.

Re: Learning to Read X86 Assembly Language

#203
post #162

And, of course, modern compilers will usually produce faster, more optimized code than you ever could, without making any mistakes. This assertion comes up over and over again in the last 30 years. Every time I've had it asserted to me, it always came from non-assembler programmers, who always wrote in a high level language. I have yet to see evidence of optimizing compilers generating code even remotely close in eff…

Why couldn't they though? Doesn't sound very hard to only generate the wordy prologues and epilogues when necessary (i.e. when you have to save any registers). Why they apparently don't do this is another question then.

I'm not aware of a general algorithm which is capable of deciding whether and how many processor's registers to use instead of setting up frame and stack pointers, and pushing a variable number of arguments on the stack, are you?

A human will know while coding in assembler, at any given time, how many variables are in the game; and will almost always manage to fit them all within processor's registers; There were only two times in my life where I actually had more than eight variables within a subroutine and had to use the stack, and even then, I didn't push everything, but only as many registers as I was actually coming up short, and the rest I still stuffed in the available registers. The other time, I figured out a more efficient algorithm where I could fit everything within the seven general purpose address registers (a0 - a6, since a7 is the stack pointer). A human will also know whether the expected result is within a byte, word, longword, or quadword range, and will only use those instruction and register sizes; a compiler has no chance to figure that out. It's trivial for humans, but as far as I'm aware, impossible for a general compiler algorithm.

In fact, even the best optimizing compilers are so dumb, that one is not allowed to mix and match 8-, 16-, 32- or 64-bit code; one must either compile everything 32- or 64-bit (the linker won't let one link 32- and 64-bit object code together). A human could easily write correct assembler code using all of those instruction / register sizes at once, and we often do.

I have yet to see a compiler capable of inferring that. If you know of one, please show me the generated code. I'd love to use such a compiler.

Re: Learning to Read X86 Assembly Language

#204

Also Matt Godbolt's gcc explorer is the the bee's knees for understanding assembly https://godbolt.org/ I think that playing around with it for 2 hours will teach you more than most classes on the topic. It really drives home why interactivity is such a bit deal in education. You should also try writing a script for counting instructions in binaries. It's pretty illuminating. Here are some sample statistics https://w…

One of the most useful tools that helped me learn assembly was the Ketman Assembly Language Tutorial.[1]

As I step through an assembly language program, it gives me instant visual feedback of the contents of each register, flag, and memory.

I'm really surprised that there's nothing remotely like this on the web yet, and that I have to resort to running dosbox or freedos to have access to this super useful tool.

[1] - http://www.oocities.org/siliconvalley/office/6208/

Re: Learning to Read X86 Assembly Language

#205
post #175

And, of course, modern compilers will usually produce faster, more optimized code than you ever could, without making any mistakes. This assertion comes up over and over again in the last 30 years. Every time I've had it asserted to me, it always came from non-assembler programmers, who always wrote in a high level language. I have yet to see evidence of optimizing compilers generating code even remotely close in eff…

Bear in mind that this isn't a release build, so the generated assembly will not be optimized at all.

There isn't really much more to optimise: at higher optimization levels, the compiler will figure out whether that was a one time operation or not, and if he determines that it was, it will simply hardcode:

  moveq $52, %eax
but all the extra cruft with stack and frame pointer setup will remain unchanged, and will still be there, if only to comply with the ABI calling conventions. I guesstimate that there are up to 50 clock cycles used for each setup and teardown of the stack and frame pointers; now multiply that with the number of times a function is called, and you can easily waste hundreds of thousands, or even millions of clock cycles pretty much doing no useful work, just housekeeping.

Re: Learning to Read X86 Assembly Language

#206

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. If you want to play with assembler without feeling a desire to stab yourself and end it all, I recommend ARM. Yes, intel is really bad, especially for learning, and while ARM is certainly better, it's pretty esoteric, and also backwards (right to left) like intel. If you want a nice, orthogonal ISA to learn assembler on, MC68000 family is a song. The instructions are human readable, the processo…

I would argue for the 6502 over the 68000.

The 6502's a bit less simple to learn, but I'd say it's worth it. It worked its way into many important computers, and is arguably one of the most emulated and most used processors in existence.

Re: Learning to Read X86 Assembly Language

#207

Earlier quoted context omitted.

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".

Re: Learning to Read X86 Assembly Language

#208
Reading assembly language is about having the computer in your head, just like regular programming. You read and execute the instructions just like any other language, just the operations are that much smaller and less abstract. Each instruction is a 'function call'; just like any low level language you leverage abstraction to build up these operations into greater pieces of execution knowledge using macros and functions in logical ways to get the outcome.

It's not magic. The best way to learn assembly is to program in it. I learned on the Gameboy by getting a job and programming 2 games in it. Fun as hell, especially when the machine is small enough to really fit in your head and clock cycles count at 4Mhz.

Re: Learning to Read X86 Assembly Language

#209
post #164

Earlier quoted context omitted.

All of those are misleading because the FS segment override isn't specific to an operand. It applies to the whole instruction, which commonly has one place (a memory reference) for the override to take effect. You can have more than one override, but only the last one remains active. Normally you can have an override even if it isn't used. There are a few instructions with more than one memory access; the override on…

No. This is misleading: fs movs byte [edi], [esi] This is a syntax error: movs byte [fs:edi], [esi] And this is a valid override with sensible syntax: movs byte [edi], [fs:esi]

How would you disassemble that instruction with more than one segment prefix in front of it? The hardware accepts this by ignoring all but the final segment prefix. For example, the prefixes might be: FS, REP, GS, FS, FS

Note that code can jump past some of the prefixes. The C library on Linux does this to bypass prefixes. Reasonable assembly syntax needs to be able to describe this. You need to be able to put a label right after a prefix.

Re: Learning to Read X86 Assembly Language

#210

Earlier quoted context omitted.

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 m…

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 a…

[deleted]
Post reply on HN