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

时间:2021-02-11 22:50:37

I have two macros, one is written in assembly and the other in C. The second macro uses the first macro. However, I also want to write the second macro in assembly with volatile, so I can control its placement in the code. And please note that tid is a runtime value, not a constant like n.

我有两个宏,一个是用汇编编写的,另一个是用C编写的。第二个宏使用第一个宏。但是,我也想用volatile编写第二个宏,所以我可以在代码中控制它的位置。请注意,tid是运行时值,而不是像n那样的常量。

What is a good way to write that in assembly? Also, is it possible to control placement of a C code like assembly with volatile?

在汇编中写这个的好方法是什么?另外,是否可以通过volatile来控制C代码的放置?

#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 个解决方案

#1


6  

You can ask gcc its idea of how to write your code in assembly: gcc -S foo.c or gcc -Wa,-alh=foo.s -c foo.c. You may want to improve on the results, of course. You will need to do a little extra: use %0 for the parameter that you pass for the assembly chunk, and declare the registers that you've clobbered. Look up Assembler Instructions with C Expression Operands in the GCC manual if you aren't familiar. Here's how this might look like (warning, typed directly into the browser, and don't really know x86 assembly syntax).

您可以向gcc询问如何在汇编中编写代码:gcc -S foo.c或gcc -Wa,-alh = foo.s -c foo.c.当然,您可能希望改进结果。您需要做一些额外的工作:将%0用于为程序集块传递的参数,并声明已经破坏的寄存器。如果您不熟悉,请在GCC手册中查找带有C表达式操作数的汇编程序指令。这可能是这样的(警告,直接输入浏览器,并不真正了解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))

A fancier method would involve figuring out how many bytes each movq-movq-jmp block takes (note: I haven't checked, I use 8) and making a computed jump into it; something like

一个更高级的方法将涉及计算每个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")

#2


1  

Assuming you're using GCC, you could try to use a GNU extension to map the stack pointer register to a C variable:

假设您正在使用GCC,您可以尝试使用GNU扩展将堆栈指针寄存器映射到C变量:

static register int stack_pointer0 asm("msp0");

void myfn () {
  ......
  saved_stack_pointer = stack_pointer0;
  ......
}

OK, that probably doesn't do what your original code did (it wasn't clear to me what the goal was), but you should be able to figure out the rest from that.

好吧,这可能不会做你的原始代码所做的事情(我不清楚目标是什么),但你应该能够从中找出其余部分。

I think I got the syntax right, but apologies if not. I know this works for general registers, and I'm pretty confident GCC knows what to do for special registers, but you never know.

我认为我的语法正确,但如果没有道歉。我知道这适用于通用寄存器,我非常有信心GCC知道如何处理特殊寄存器,但你永远不知道。

Hope that helps.

希望有所帮助。

#1


6  

You can ask gcc its idea of how to write your code in assembly: gcc -S foo.c or gcc -Wa,-alh=foo.s -c foo.c. You may want to improve on the results, of course. You will need to do a little extra: use %0 for the parameter that you pass for the assembly chunk, and declare the registers that you've clobbered. Look up Assembler Instructions with C Expression Operands in the GCC manual if you aren't familiar. Here's how this might look like (warning, typed directly into the browser, and don't really know x86 assembly syntax).

您可以向gcc询问如何在汇编中编写代码:gcc -S foo.c或gcc -Wa,-alh = foo.s -c foo.c.当然,您可能希望改进结果。您需要做一些额外的工作:将%0用于为程序集块传递的参数,并声明已经破坏的寄存器。如果您不熟悉,请在GCC手册中查找带有C表达式操作数的汇编程序指令。这可能是这样的(警告,直接输入浏览器,并不真正了解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))

A fancier method would involve figuring out how many bytes each movq-movq-jmp block takes (note: I haven't checked, I use 8) and making a computed jump into it; something like

一个更高级的方法将涉及计算每个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")

#2


1  

Assuming you're using GCC, you could try to use a GNU extension to map the stack pointer register to a C variable:

假设您正在使用GCC,您可以尝试使用GNU扩展将堆栈指针寄存器映射到C变量:

static register int stack_pointer0 asm("msp0");

void myfn () {
  ......
  saved_stack_pointer = stack_pointer0;
  ......
}

OK, that probably doesn't do what your original code did (it wasn't clear to me what the goal was), but you should be able to figure out the rest from that.

好吧,这可能不会做你的原始代码所做的事情(我不清楚目标是什么),但你应该能够从中找出其余部分。

I think I got the syntax right, but apologies if not. I know this works for general registers, and I'm pretty confident GCC knows what to do for special registers, but you never know.

我认为我的语法正确,但如果没有道歉。我知道这适用于通用寄存器,我非常有信心GCC知道如何处理特殊寄存器,但你永远不知道。

Hope that helps.

希望有所帮助。