Удаление зависимости стека из кода сборки
Я пытаюсь удалить зависимость стека из следующего кода.
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
взять регистр и ссылку на память, вы предоставляете один и тот же регистр дважды. Затем ассемблер интерпретирует имя регистра как область памяти и поэтому жалуется, что оно не определено в том же файле.
Поскольку у вас закончились регистры, вы можете избежать использования стека только с помощью глобальной переменной.