Live data from Hacker News

Learning to Read X86 Assembly Language

patshaughnessy.net

191–200 of 238 posts

Re: Learning to Read X86 Assembly Language

#191

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…

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.

Re: Learning to Read X86 Assembly Language

#192
post #179

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…

>>because compiler algorithms can't reliably make such contextual decisions They can actually. Compiler optimizations have come long way, even Java's JIT should be able to optimize that. (ok, not using the AL register) My personal story - I used to use exclusively assembler for 6502 and 8086 as it actually ran fast enough. In the mid 90s I saw Delphi's code (and Delphi was not known for its optimizations) but it was…

My personal story - I used to use exclusively assembler for 6502 and 8086 as it actually ran fast enough. In the mid 90s I saw Delphi's code (and Delphi was not known for its optimizations) but it was able to use the Pentium instruction pairing which takes quite an effort to accomplish by hand.

But a human would almost never use some of those more complex instructions, for a very simple reason: they eat too many clock cycles. When one is coding in assembler, one usually targets two constraints:

1. the least amount of clock cycles needed to pull off an operation;

2. the least amount of bytes to encode the operation.

Where those two meet is where the best coders get unbelievable performance out of the hardware. At least that's the case in the demo scene, although many nowadays cheat by banging the GPU's in CUDA or OpenGL.

Re: Learning to Read X86 Assembly Language

#193
post #177

If you're experimenting with asm in crystal, you might want to use --prelude=empty to remove the standard library to make the asm output cleaner. You can then then require lib_c and use that directly.

I tried that while researching the article, but found the call to "puts" doesn't link without the standard library code. And without a "puts" or similar call to produce output LLVM optimized the entire program away :) I suppose this could work if, as you suggest, I manually called out to a lib_c function like printf instead.

Yeah, puts is part of the part of the standard library, and uses crystal's evented io framework, fiber scheduler and libevent. This is what most of the extra code in the asm output will be doing.

Re: Learning to Read X86 Assembly Language

#194

Earlier quoted context omitted.

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…

It is a convention, it's called a procedure call standard. Compilers which conform to the PCS can call functions compiled by other compilers (that's how you can use libraries for example). If there's a bug in the compiler that results in non-PCS compliance, well that's a "fun" bug to track down.

>It is a convention, it's called a procedure call standard.

Is this the same thing as, or related to, the calling conventions that used to be used in Microsoft DOS and Windows native language / C apps some years ago - things like "long far pascal" as function declaration /definition qualifiers, and things like the fact that C pushes function arguments onto the stack (before the call) from left to right, and Pascal does it from right to left (or the other way around)? (Did some of that stuff, but it's been a while).

I did read the surrounding comments to this one, and saw that some of the topic was about registers, not the stack.

Re: Learning to Read X86 Assembly Language

#195

Earlier quoted context omitted.

Suppose you're right and the registers are arbitrary. Then how would foreign function calls work? If you're compiling Rust code that calls into a C library, how does it know what registers to use? 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 t…

Then how would foreign function calls work? If you're compiling Rust code that calls into a C library, how does it know what registers to use? By using information kept with the function, or perhaps even encoded into the function name itself (as already happens when distinguishing between different calling conventions, or in the case of C++ name mangling)? Coming from an Asm background, where there basically is no on…

Win32 has various different calling conventions, and each function is annotated accordingly in the header files. It's all a bit of a mess, which is presumably why they drastically simplified it in the x64 transition.

(And realistically, for all but the most trivial functions, having one convention is probably a highly reasonable default. Trivial functions should probably be made available to the compiler for inlining anyway. Note also that GCC allows you to override the number of arguments passed on the stack via an annotation on 32-bit x86, if you insist.)

Re: Learning to Read X86 Assembly Language

#196
post #194

Earlier quoted context omitted.

It is a convention, it's called a procedure call standard. Compilers which conform to the PCS can call functions compiled by other compilers (that's how you can use libraries for example). If there's a bug in the compiler that results in non-PCS compliance, well that's a "fun" bug to track down.

>It is a convention, it's called a procedure call standard. Is this the same thing as, or related to, the calling conventions that used to be used in Microsoft DOS and Windows native language / C apps some years ago - things like "long far pascal" as function declaration /definition qualifiers, and things like the fact that C pushes function arguments onto the stack (before the call) from left to right, and Pascal do…

Yes, "calling convention" is, I think, a more commonly used term for the same thing.

Re: Learning to Read X86 Assembly Language

#197

Earlier quoted context omitted.

It's not just shorter, it's also faster. But see my answer also: there are condition flag implications of using XOR and sometimes MOV will be preferable. The optimiser will always know best :)

> there are condition flag implications of using XOR and sometimes MOV will be preferable If the condition flags have to be preserved, you are right. But otherwise, read the linked article ( https://randomascii.wordpress.com/2012/12/29/the-surprising-... ): "On Sandybridge this gets even better. The register renamer detects certain instructions (xor reg, reg and sub reg, reg and various others) that always zero a reg…

It's fascinating how far down the rabbit hole goes these days. One might think machine code as emitted by compilers would be pretty close to where the buck stops, but no. Named registers are just an abstraction on top of a larger register pool, opcodes get JIT compiled and optimized to microcode instructions, execution order is mostly just a hint for the processor to ignore if it can get things done faster by reordering or parallelizing... And memory access is probably the greatest illusion of all.

Re: Learning to Read X86 Assembly Language

#198

Earlier quoted context omitted.

... and for a brief period of time in the late '80s, "popular" in India as well. (I quoted popular because they were bloody expensive. In 7th grade, a kid in my class had one. He was the only one in all of the school to have a computer.).

Huh. The Spectrum was popular elswhere because it was so comically cheap.

Relatively speaking. It was definitely much cheaper than a PC Clone with an 80286 processor, but expensive enough to be a luxury, I think.

Re: Learning to Read X86 Assembly Language

#199
post #84

Earlier quoted context omitted.

The GP didn't have much content either, merely listing off other obsessively backwards compatible things. Your reply might be suitable in a formal debate setting (as would "fallacy!" claims be suitable when challenging faulty deductive logic) but this isn't a debate, it's a conversation. The source of one's claims doesn't matter, you only know they're probably not from experience because the Parent was kind enough to…

The source of one's claims doesn't matter, you only know they're probably not from experience because the Parent was kind enough to share their age. I coded my first assembler program (a link relocation routine) when I was 13, so age is pretty meaningless in the context of assembler coding.

Given, I'm fairly weak in assembler (I've been learning), so I may not be the most reliable resource: GP has a point about my lack of experience, just not for the reason they think they do.

Re: Learning to Read X86 Assembly Language

#200
post #124

Earlier quoted context omitted.

the lower levels of optimizations are supposed to be more straightforward translations of the high-level language code. you can imagine this might be useful if you are debugging assembly.

On the other hand, I find O0 is significantly worse than what even a novice human Asm programmer would do if asked to manually compile code, and O1 would be around the same as a novice human.

Yes, I used to find that too. It's because, pre-optimization, on older architectures, the compiler outputs chunks of asm as if from a recipe book. Loads of unnecessary memory access, pointless moving data between registers, etc.

A proficient human coder, on the other hand, writes assembler that is partly optimized by default.

But few humans could write code like a seriously optimizing compiler, esp. on modern pipelined architectures - that stuff is unintelligible. Which is as it should be, because modern processors are not designed to be programmed directly by humans.

Post reply on HN