
Show HN: Generate x86 Assembly with Go - mmcloughlin
https://github.com/mmcloughlin/avo
======
kazinator
In the MIPS port of the Linux kernel, there is a module which assembles a
handler for TLB faults, right into memory, each time the kernel boots up:

[https://elixir.bootlin.com/linux/v4.20/source/arch/mips/mm/t...](https://elixir.bootlin.com/linux/v4.20/source/arch/mips/mm/tlbex.c)

the code is spread among various C functions. All the uasm_ _() and UASM__ ()
calls assemble an instruction, e.g.:

    
    
      if (bcm1250_m3_war()) {
    		unsigned int segbits = 44;
    
    		uasm_i_dmfc0(&p, K0, C0_BADVADDR);
    		uasm_i_dmfc0(&p, K1, C0_ENTRYHI);
    		uasm_i_xor(&p, K0, K0, K1);
    		uasm_i_dsrl_safe(&p, K1, K0, 62);
    		uasm_i_dsrl_safe(&p, K0, K0, 12 + 1);
    		uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits);
    		uasm_i_or(&p, K0, K0, K1);
    		uasm_il_bnez(&p, &r, K0, label_leave);
    		/* No need for uasm_i_nop */
    

The K0 and K1 refer to a pair of registers that, according to the MIPS
architecture, TLB handlers can use without saving or restoring. These
registers thus appear to have unstable values from the POV of the interrupted
user or kernel space program.

I know about this module because I once patched it to make it preserve the
value of the K0 register. The K0 register then appeared to have a stable value
in user space, and I was able to patch glibc to use refer to that register for
the thread_self() context value. This saved a trip to the kernel, making
pthread_<everthing> faster: mutexes, conditions, you name it. I patched GCC's
thread local storage mechanism to also use this.

When looking for the trap handler assembly code, I could not find it in any .S
file; then I discovered it's being synthesized at run-time by C code.

~~~
sigjuice
k0, k1 are intended for use by any exception handler, not just TLB handlers.

