Live data from Hacker News

Please restore our registers when you’re done with them

randomascii.wordpress.com

31–40 of 142 posts

Re: Please restore our registers when you’re done with them

#31
post #15

Sounds like there should be an option when you write assembly code to tell the compiler "please save/restore any register that I'm modifying in this asm code according to the target you are compiling for"

When you use inline assembly, in fact the compiler does preserve the semantics of the surrounding program considering the target's ABI -- if you tell it correctly what impacts the inline asm has. Lots of rules must be followed in order to get this behavior just right. One of the most subtle ones is "early clobbers" [1].

In many cases, you can get all the benefits of inline assembly from compiler intrinsics while letting the compiler handle all the details of register allocation and scheduling.

Note that in OP's case IIUC this was assembly code and not inline assembly. If you write functions in assembly you are solely responsible for calling conventions and ABI conformance.

[1] https://stackoverflow.com/a/15819941/489590

Re: Please restore our registers when you’re done with them

#33
post #3

It’s interesting that there is a zero stored in a register and used for hours - is that significantly faster than just using some actual zero each time? Perhaps CPUs need a “always zero” register or some similar menomic to help harden.

RISC-V has such a register. It returns zero when read, and ignored writes.

Re: Please restore our registers when you’re done with them

#34
post #3

It’s interesting that there is a zero stored in a register and used for hours - is that significantly faster than just using some actual zero each time? Perhaps CPUs need a “always zero” register or some similar menomic to help harden.

Intel has never really needed to have a zero register because xor register, register as a zeroing idiom is so fast and so recognized that Intel have optimized the hell out of it. In Sandy Bridge and onward it doesn't even go through an execution port, even for the vector registers. The problem is really whether to indulge bad programmers who don't respect the ABI at the cost of a minimal sliver of performance (even t…

I think it's not just the xor trick, but that Intel has lots of addressing modes, including ones with immediate operands that you can use in many situations.

In RISC-like machines, most of the operations are register-register, and you have load/store instructions for referencing memory.

To use an immediate operand (literal constant in the code itself), you may have to load it into a register, like

   move r7, #42
   add r1, r1, r7  ;; ok, now we have 42 in r7, we can increment r1 by 42.

Whereas in a CISC you would have

   add r1, #42  ;; two operand form
or maybe

   add r1, r1, #42 ;; three operand form
When you need a zero, you just use the immediate operand zero, and thus you don't need to to pick some register to clear.

In summary, zero registers in RISC-like instruction set architectures effectively provide a literal zero that can be used wherever a register is required, which helps because only register operands can be used in many instructions.

Re: Please restore our registers when you’re done with them

#36

Earlier quoted context omitted.

Those PUSH_XMM/POP_XMM macros appear to be Windows-only; I think they expand to nothing on other platforms because they contain their own guard for Windows internally. If that's the case, the call sites don't need to guard for it. I'm guessing that obeying this calling convention is the purpose of those macros. https://github.com/cisco/openh264/blob/db956674bbdfbaab5acdd... https://github.com/cisco/openh264/blob/db95…

The webrtc fix was thematically similar in that the programmer declared what registers were trashed and then the compiler knows which registers need to be saved. I'm not sure why the compiler doesn't notice when registers are used without being declared as being trashed - I'm really not an expert at _writing_ assembly language.

It's literally undecidable in principle whether some assembler correctly restores some register R. That's a non-trivial semantic property, Rice's theorem applies. So the compiler's only practical option if it worked this way would be a conservative option - any time it's unclear whether register R is clobbered, treat it as clobbered.

As a trivial example of why a register might not be clobbered even though my code touched it and it seems like I didn't restore it...

Suppose if R is divisible by 12 I branch, in the other branch I don't change R, but in that branch I do change R, XORing it with a value which is difficult to explain but has a value between 1 and 3 inclusive, sometimes more than once. At the end of the branch I also clear the bottom two bits of R.

R is actually not clobbered by this function! If the bottom two bits weren't zero before, R isn't divisible by 12, so we didn't change R, and if they were zero, we restore that, the other bits are never changed.

Having the human programmer promise they they wrote a correct clobber list means if their assembler does somehow restore/ preserve register R, the human can just say so, and needn't prove to the compiler somehow that this works. This sort of code is mostly in performance critical components, e.g. video decoding, where we are already trading reliance on fallible humans for better performance, so adding one extra promise feels OK.

Re: Please restore our registers when you’re done with them

#37
post #26
post #15

Sounds like there should be an option when you write assembly code to tell the compiler "please save/restore any register that I'm modifying in this asm code according to the target you are compiling for"

I not sure whether that satire. In case its not, most languages that allow inline assembly (like C) have an optional "clobber list" argument that tells the dataflow analysis of the compiler that your assembly snippet overwrites certain registers [1]. Inline assembly doesn't have target specific clobber lists because it's assumed that the code only works on one target and the programmer has to take care of making it w…

The System V x64 ABI is different from the Windows x64 ABI.

Re: Please restore our registers when you’re done with them

#38

Earlier quoted context omitted.

Intel has never really needed to have a zero register because xor register, register as a zeroing idiom is so fast and so recognized that Intel have optimized the hell out of it. In Sandy Bridge and onward it doesn't even go through an execution port, even for the vector registers. The problem is really whether to indulge bad programmers who don't respect the ABI at the cost of a minimal sliver of performance (even t…

I think it's not just the xor trick, but that Intel has lots of addressing modes, including ones with immediate operands that you can use in many situations. In RISC-like machines, most of the operations are register-register, and you have load/store instructions for referencing memory. To use an immediate operand (literal constant in the code itself), you may have to load it into a register, like move r7, #42 add r1…

That's a good point. But all of the x86 SIMD stuff is register/register and we don't have xmm0/ymm0/zmm0 being 0 like we'd expect on a load store style RISC architecture.

Re: Please restore our registers when you’re done with them

#39

Quoted post unavailable.

We ban accounts that post like this, because the community considers it spamming.

I'm not going to ban you because you've also posted other things to HN and seem like a legit user. But you've been posting these links much too often, so please stop doing that.

Re: Please restore our registers when you’re done with them

#40
post #13
post #12

Earlier quoted context omitted.

It seems to me something that could be found by some kind of valgrind-like tool - it'd be much slower than normal code but "ABI exception detected" or something.

Not worth checking for. The few people who write assembly code these days know what they are doing, and, bugs aside, the compiler knows what to do.

Also compilers violate the ABI when they know the violation can't be observed, so the external tool would have too many positives.
Post reply on HN