Удаление зависимости стека из кода сборки

Я пытаюсь удалить зависимость стека из следующего кода.

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"
                 );
 }

В приведенной выше функции, stmdb sp!, {%[regs], r11} выталкивает r1 а также r11 в стек, а затем он восстанавливается.

В моем случае, я должен избегать использования стека здесь. поэтому я переписал

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"
                );
}

Когда я компилирую, я получаю следующую ошибку.

/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

Я упоминал здесь, что внутреннее перемещение не исправлено. но это не дает четкого представления. Пожалуйста, поделитесь своими знаниями по этому поводу.

2 ответа

Решение

Ваш встроенный asm вызовите clobbers почти всех регистров, и это явно сказано компилятору через volatile директива, что он не должен пропускать или пытаться переместить вызов, чтобы оптимизировать использование регистра. Это означает, что компилятор при создании эквивалентных инструкций для myfunction необходимо сохранить регистры куда-нибудь перед отправкой этой встроенной сборки.

Позвольте мне доказать это вам:

$ 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

Причиной сообщения об ошибке является то, что ldr взять регистр и ссылку на память, вы предоставляете один и тот же регистр дважды. Затем ассемблер интерпретирует имя регистра как область памяти и поэтому жалуется, что оно не определено в том же файле.

Поскольку у вас закончились регистры, вы можете избежать использования стека только с помощью глобальной переменной.

Другие вопросы по тегам