如何在汇编中编写所有这些内容

时间:2011-11-25 16:33:37

标签: c linux gcc assembly x86

我有两个宏,一个是用汇编编写的,另一个是用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; \
    }

2 个答案:

答案 0 :(得分:6)

您可以向gcc询问如何在汇编中编写代码:gcc -S foo.cgcc -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知道如何处理特殊寄存器,但你永远不知道。

希望有所帮助。