我有两个宏,一个是用汇编编写的,另一个是用C编写的。第二个宏使用第一个宏。但是,我还想在volatile中使用程序集编写第二个宏,因此我可以在代码中控制它的位置。请注意, tid 是运行时值,而非 n 之类的常量。
在汇编中写这个的好方法是什么?此外,是否可以控制C代码的放置,例如使用volatile?
组装#define SAVE_SP(n) __asm__ __volatile__ ("movq %rsp, msp"#n";" \
"movq ts"#n", %rsp;" \
)
#define SAVE_STACK_POINTER( tid ) \
switch( tid ) \
{ \
case 0: \
SAVE_SP( 0 ); \
break; \
case 1: \
SAVE_SP( 1 ); \
break; \
case 2: \
SAVE_SP( 2 ); \
break; \
case 3: \
SAVE_SP( 3 ); \
break; \
}
答案 0 :(得分:6)
您可以向gcc询问如何在汇编中编写代码:gcc -S foo.c
或gcc -Wa,-alh=foo.s -c foo.c
。当然,您可能希望改进结果。您需要做一些额外的工作:使用%0
作为为程序集块传递的参数,并声明已被破坏的寄存器。如果您不熟悉,请查看Assembler Instructions with C Expression Operands in the GCC manual。以下是这可能是什么样的(警告,直接在浏览器中输入,并且真的不知道x86汇编语法)。
#define SAVE_STACK_POINTER(tid) __asm__ __volatile__ (" \
cmpl $0, %0 \n\
je .SAVE_STACK_POINTER_0 \n\
cmpl $1, %0 \n\
je .SAVE_STACK_POINTER_1 \n\
cmpl $2, %0 \n\
je .SAVE_STACK_POINTER_2 \n\
cmpl $3, %0 \n\
je .SAVE_STACK_POINTER_3 \n\
jmp .SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_0: \n\
movq %%rsp, msp0 \n\
movq ts0, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_1: \n\
movq %%rsp, msp1 \n\
movq ts1, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_2: \n\
movq %%rsp, msp2 \n\
movq ts2, %%rsp \n\
jmp SAVE_STACK_POINTER_done \n\
.SAVE_STACK_POINTER_3: \n\
movq %%rsp, msp3 \n\
movq ts3, %%rsp \n\
.SAVE_STACK_POINTER_done: \n\
" : : "r" (tid))
更高级的方法将涉及计算每个movq
- movq
- jmp
块占用的字节数(注意:我没有检查,我使用8)并进行计算跳进去;
__asm__(" \n\
movl %0, %eax \n\
mul 8, %eax \n\
add 4, %eax \n\
jmp . + %eax \n\
movq %%rsp, msp0 \n\
movq ts0, %%rsp \n\
jmp .SAVE_STACK_POINTER_done \n\
…
.SAVE_STACK_POINTER_done: \n\
" : : "r" (tid) : "%eax")
答案 1 :(得分:1)
假设您正在使用GCC,您可以尝试使用GNU扩展将堆栈指针寄存器映射到C变量:
static register int stack_pointer0 asm("msp0");
void myfn () {
......
saved_stack_pointer = stack_pointer0;
......
}
好吧,这可能不会影响您的原始代码(我不清楚目标是什么),但您应该能够从中找出其余部分。
我认为我的语法正确,但如果不是,请道歉。我知道这适用于通用寄存器,我非常有信心GCC知道如何处理特殊寄存器,但你永远不知道。
希望有所帮助。