1

再会。我遇到了一个几天都无法解决的问题。当我尝试用 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");
}

我从gas中得到的信息如下:

Error: junk '(point)' after expression

据我所知,第二行的指针有问题,但不幸的是我自己无法解决。


谢谢你的帮助。

4

2 回答 2

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()例如在涵盖所有 255 个案例的帮助下创建的语句BOOST_PP_REPEAT()是比自我修改代码更好的选择,例如:

#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__当然,如果您将模板函数调用更改为纯 C) - 因为 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()离开,即即使您说它static __inline__ ...会创建完整的跳转表版本,GetInInterrupt(3)而不是内联int3的 as会更简单的实现。

于 2013-02-25T17:48:32.327 回答
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"解决问题。

于 2013-02-23T21:26:49.753 回答