Search code examples
cassemblyarminline-assemblykprobe

Removing stack dependency from Assembly Code


Im trying to remove the stack dependency from the following code.

void  myfunction(struct kprobe *p, struct pt_regs *regs)
 {
         register void *rregs asm("r1") = regs;
         register void *rfn asm("lr") = p->ainsn.insn_fn;

         __asm__ __volatile__ (
                 "stmdb  sp!, {%[regs], r11}     \n\t"
                 "ldmia  %[regs], {r0-r12}       \n\t"    
                 "blx    %[fn]                   \n\t"
                 "ldr    lr, [sp], #4            \n\t" /* lr = regs */
                 "stmia  lr, {r0-r12}            \n\t"
                 "ldr    r11, [sp], #4           \n\t"

                 : [regs] "=r" (rregs), [fn] "=r" (rfn)
                 : "" (rregs), "1" (rfn)
                 : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
                   "r8", "r9", "r10", "r12", "memory", "cc"
                 );
 }

In the above function, stmdb sp!, {%[regs], r11} pushes r1 and r11 into stack and later it retrives.

In my case, I should avoid using stack here. so I rewrote

void myfunction(struct kprobe *p, struct pt_regs *regs)
{
        int r1_bk = 0, r11_bk = 0;
        register void *rregs asm("r1") = regs;
        register void *rfn asm("lr") = p->ainsn.insn_fn;
        register void *r1b_c asm("r1") = &r1_bk;
        register void *r11b_c asm("r11") = &r11_bk;    

      __asm__ __volatile__ (
                "ldr    %[r1b], r1      \n\t"
                "ldr    %[r11b], r11    \n\t"
                "ldmia  %[regs], {r0-r12}       \n\t"
                "blx    %[fn]                   \n\t"    
                "ldr    lr, %[r1b]              \n\t" /* lr = regs */
                "stmia  lr, {r0-r12}            \n\t"
                "ldr    r11, %[r11b]            \n\t"

                : [regs] "=r" (rregs), [fn] "=r" (rfn), [r1b] "=r" (r1b_c), [r11b] "=r" (r11b_c)
                : "0" (rregs), "1" (rfn)
                : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
                  "r8", "r9", "r10", "r12", "memory", "cc"
                );
}

When I compile, following error Im getting.

/tmp/ccJMefdC.s: Assembler messages:
/tmp/ccJMefdC.s:579: Error: internal_relocation (type: OFFSET_IMM) not fixed up
/tmp/ccJMefdC.s:580: Error: internal_relocation (type: OFFSET_IMM) not fixed up
/tmp/ccJMefdC.s:583: Error: internal_relocation (type: OFFSET_IMM) not fixed up
/tmp/ccJMefdC.s:585: Error: internal_relocation (type: OFFSET_IMM) not fixed up

I refered here internal relocation not fixed up. but it doesn't give clear idea. Please share your knowledge regarding this.


Solution

  • Your inline asm call clobbers almost all registers and it is explicitly told to compiler via volatile directive that it shouldn't skip or try to move the call around to optimize register usage. This means compiler while producing the equivalent instructions for myfunction needs to save registers to somewhere before emitting that inline assembly.

    Let me prove it to you:

    $ cat asm_vol.c 
    void f() {
        asm volatile("" : : : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
                      "r8", "r9", "r10", "r12", "memory", "cc");
    }
    $ arm-linux-gnueabihf-gcc -c -O2 asm_vol.c
    $ arm-linux-gnueabihf-objdump -d asm_vol.o
    
    asm_vol.o:     file format elf32-littlearm
    
    
    Disassembly of section .text:
    
    00000000 <f>:
       0:   e92d 07f0   stmdb   sp!, {r4, r5, r6, r7, r8, r9, sl}
       4:   e8bd 07f0   ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl}
       8:   4770        bx  lr
       a:   bf00        nop