Question

Good day. I faced a problem that I couldn't solve for several days. The error appears when I try to compile this function in C language.

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");
}

Message I get from gas is following:

Error: junk '(point)' after expression

As I can understand the pointer in second line is faulty, but unfortunately I can't solve it by my own.


Thank you for help.

Was it helpful?

Solution

If you can use C++, then this one:

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

will do. If I use that template like:

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

that creates the following object code:

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

which is pretty much optimal (even for the int3 case, which is the breakpoint op). It'll also create a compile-time warning if the operand is out of the 0..255 range, due to the N constraint allowing only that.

Edit: plain old C-style macros work as well, of course:

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

creates the same code as the C++ templated function. Due to the way int behaves, it's a good idea to tell the compiler (via the "cc", "memory" constraints) about the barrier semantics, to make sure it doesn't try to re-order instructions when embedding the inline assembly.

The limitation of both is, obviously, the fact that the interrupt number must be a compile-time constant. If you absolutely don't want that, then creating a switch() statement created e.g. with the help of BOOST_PP_REPEAT() covering all 255 cases is a better option than self-modifying code, i.e. like:

#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);
    }
}

This can be done in plain C (if you change the templated function invocation for a plain __asm__ of course) - because the boost preprocessor library does not depend on a C++ compiler ... and gcc 4.7.2 creates the following code for this:


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 ... ]

Beware though if you do the above ... the compiler (gcc up to and including 4.8) is not intelligent enough to optimize the switch() away, i.e. even if you say static __inline__ ... it'll create the full jump table version of GetInInterrupt(3) instead of just an inlined int3 as would the simpler implementations.

OTHER TIPS

Below show how you could write to a location in the code. It does assume that the code is writeable in the first place, which is typically not the case in mainstream OS's - since that would hide some nasty bugs.

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");
}

I also simplified the code to avoid using two registers, and instead just using the register that Interrupt already is in. If the compiler moans about it, you may find that "a" instead or "r" solves the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top