内联汇编,进入中断

时间:2013-02-23 16:51:42

标签: c inline-assembly gas

美好的一天。 我遇到了一个我几天都无法解决的问题。当我尝试用C语言编译这个函数时出现错误。

void GetInInterrupt(UChar Interrupt)
{
    //asm volatile(".intel_syntax noprefix");
    asm volatile
    (
        "movb %0, %%al\n"
        "movb %%al, 1(point)\n"
        "point:\n"
        "int $0\n"
        : /*output*/ : "r" (Interrupt) /*input*/ : /*clobbered*/
    );
    //asm volatile(".att_syntax noprefix");
}

我从天然气那里得到的消息如下:

Error: junk '(point)' after expression

我可以理解第二行中的指针有问题,但不幸的是我无法自己解决。


感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

下面显示了如何写入代码中的某个位置。它确实假设代码首先是可写的,这在主流操作系统中通常不是这种情况 - 因为这会隐藏一些令人讨厌的错误。

void GetInInterrupt(UChar Interrupt)
{
    //asm volatile(".intel_syntax noprefix");
    asm volatile
    (
        "movb %0, point+1\n"
        "point:\n"
        "int $0\n"
        : /*output*/ : "r" (Interrupt) /*input*/ : /*clobbered */
    );
    //asm volatile(".att_syntax noprefix");
}

我还简化了代码以避免使用两个寄存器,而只是使用Interrupt已经存在的寄存器。如果编译器对此有所了解,您可能会发现"a"代替"r" 1}}解决问题。

答案 1 :(得分:2)

如果你可以使用C ++,那么这个:

template <int N> static inline void GetInInterrupt (void)
{
    __asm__ ("int %0\n" : "N"(N));
}

会做的。如果我使用该模板,如:

GetInInterrupt<123>();
GetInInterrupt<3>();
GetInInterrupt<23>();
GetInInterrupt<0>();

创建以下对象代码:

   0:   cd 7b                   int    $0x7b
   2:   cc                      int3
   3:   cd 17                   int    $0x17
   5:   cd 00                   int    $0x0

这是非常优化的(即使对于int3情况,这是断点操作)。如果操作数超出0..255范围,它还会创建编译时警告,因为N约束仅允许操作数。

编辑:普通的旧式C风格的宏当然也有效:

#define GetInInterrupt(arg) __asm__("int %0\n" : : "N"((arg)) : "cc", "memory")

创建与C ++模板化函数相同的代码。由于int的行为方式,最好告诉编译器(通过"cc", "memory"约束)有关屏障语义,以确保它在嵌入时不会尝试重新排序指令。内联汇编。

显然,两者的局限性在于中断号必须是编译时常量。如果您绝对不希望这样,那么创建一个switch()语句,例如在BOOST_PP_REPEAT()的帮助下覆盖所有255个案例比自修改代码更好,例如:

#include <boost/preprocessor/repetition/repeat.html>

#define GET_INTO_INT(a, INT, d) case INT: GetInInterrupt<INT>(); break;

void GetInInterrupt(int interruptNumber)
{
    switch(interruptNumber) {
    BOOST_PP_REPEAT(256, GET_INTO_INT, 0)
    default:
        runtime_error("interrupt Number %d out of range", interruptNumber);
    }
}

这个可以在普通的C中完成(如果你改变了普通__asm__的模板化函数调用) - 因为boost预处理器库依赖于C ++编译器...而gcc 4.7.2为此创建了以下代码:


GetInInterrupt:
.LFB0:
        cmpl    $255, %edi
        jbe     .L262
        movl    %edi, %esi
        xorl    %eax, %eax
        movl    $.LC0, %edi
        jmp     runtime_error
        .p2align 4,,10
        .p2align 3
.L262:
        movl    %edi, %edi
        jmp     *.L259(,%rdi,8)
        .section        .rodata
        .align 8
        .align 4
.L259:
        .quad   .L3
        .quad   .L4
[ ... ]
        .quad   .L258
        .text
.L257:
#APP
# 17 "tccc.c" 1
        int $254

# 0 "" 2
#NO_APP
        ret
[ ... accordingly for the other vectors ... ]

请注意,如果您执行上述操作...编译器(gcc直到并包括4.8) 智能足以优化switch(),即使您说{ {1}}它将创建static __inline__ ...的完整跳转表版本,而不是简单实现的内联GetInInterrupt(3)